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