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
11using 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 */
20void 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.
137void 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