xref: /netbsd-src/external/bsd/elftosb/dist/common/Version.cpp (revision 993229b6fea628ff8b1fa09146c80b0cfb2768eb)
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