1 /*
2  * File:  Version.cpp
3  *
4  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5  * See included license file for license details.
6  */
7 
8 #include "Version.h"
9 #include "EndianUtilities.h"
10 
11 using namespace elftosb;
12 
13 /*!
14  * Parses a string in the form "xxx.xxx.xxx" (where x is a digit) into
15  * three version fields for major, minor, and revision. The output is
16  * right aligned BCD in host-natural byte order.
17  *
18  * \param versionString String containing the version.
19  */
set(const std::string & versionString)20 void version_t::set(const std::string & versionString)
21 {
22           size_t length = versionString.size();
23           unsigned version = 0;
24           unsigned index = 0;
25 
26           typedef enum {
27                     kVersionStateNone,
28                     kVersionStateMajor,
29                     kVersionStateMinor,
30                     kVersionStateRevision
31           } VersionParseState;
32 
33           // set initial versions to 0s
34           m_major = 0;
35           m_minor = 0;
36           m_revision = 0;
37 
38           VersionParseState parseState = kVersionStateNone;
39           bool done = false;
40           for (; index < length && !done; ++index)
41           {
42                     char c = versionString[index];
43 
44                     if (isdigit(c))
45                     {
46                               switch (parseState)
47                               {
48                                         case kVersionStateNone:
49                                                   parseState = kVersionStateMajor;
50                                                   version = c - '0';
51                                                   break;
52                                         case kVersionStateMajor:
53                                         case kVersionStateMinor:
54                                         case kVersionStateRevision:
55                                                   version = (version << 4) | (c - '0');
56                                                   break;
57                               }
58                     }
59                     else if (c == '.')
60                     {
61                               switch (parseState)
62                               {
63                                         case kVersionStateNone:
64                                                   parseState = kVersionStateNone;
65                                                   break;
66                                         case kVersionStateMajor:
67                                                   m_major = version;
68                                                   version = 0;
69                                                   parseState = kVersionStateMinor;
70                                                   break;
71                                         case kVersionStateMinor:
72                                                   m_minor = version;
73                                                   version = 0;
74                                                   parseState = kVersionStateRevision;
75                                                   break;
76                                         case kVersionStateRevision:
77                                                   m_revision = version;
78                                                   version = 0;
79                                                   done = true;
80                                                   break;
81                               }
82                     }
83                     else
84                     {
85                               switch (parseState)
86                               {
87                                         case kVersionStateNone:
88                                                   parseState = kVersionStateNone;
89                                                   break;
90                                         case kVersionStateMajor:
91                                                   m_major = version;
92                                                   done = true;
93                                                   break;
94                                         case kVersionStateMinor:
95                                                   m_minor = version;
96                                                   done = true;
97                                                   break;
98                                         case kVersionStateRevision:
99                                                   m_revision = version;
100                                                   done = true;
101                                                   break;
102                               }
103                     }
104           }
105 
106           switch (parseState)
107           {
108                     case kVersionStateMajor:
109                               m_major = version;
110                               break;
111                     case kVersionStateMinor:
112                               m_minor = version;
113                               break;
114                     case kVersionStateRevision:
115                               m_revision = version;
116                               break;
117                     default:
118                               // do nothing
119                               break;
120           }
121 }
122 
123 //! \brief Converts host endian BCD version values to the equivalent big-endian BCD values.
124 //!
125 //! The output is a half-word. And BCD is inherently big-endian, or byte ordered, if
126 //! you prefer to think of it that way. So for little endian systems, we need to convert
127 //! the output half-word in reverse byte order. When it is written to disk or a
128 //! buffer it will come out big endian.
129 //!
130 //! For example:
131 //!     - The input is BCD in host endian format, so 0x1234. Written to a file, this would
132 //!       come out as 0x34 0x12, reverse of what we want.
133 //!     - The desired BCD output is the two bytes 0x12 0x34.
134 //!     - So the function's uint16_t result must be 0x3412 on a little-endian host.
135 //!
136 //! On big endian hosts, we don't have to worry about byte swapping.
fixByteOrder()137 void version_t::fixByteOrder()
138 {
139           m_major = ENDIAN_HOST_TO_BIG_U16(m_major);
140           m_minor = ENDIAN_HOST_TO_BIG_U16(m_minor);
141           m_revision = ENDIAN_HOST_TO_BIG_U16(m_revision);
142 }
143 
144