/* * File: Version.cpp * * Copyright (c) Freescale Semiconductor, Inc. All rights reserved. * See included license file for license details. */ #include "Version.h" #include "EndianUtilities.h" using namespace elftosb; /*! * Parses a string in the form "xxx.xxx.xxx" (where x is a digit) into * three version fields for major, minor, and revision. The output is * right aligned BCD in host-natural byte order. * * \param versionString String containing the version. */ void version_t::set(const std::string & versionString) { size_t length = versionString.size(); unsigned version = 0; unsigned index = 0; typedef enum { kVersionStateNone, kVersionStateMajor, kVersionStateMinor, kVersionStateRevision } VersionParseState; // set initial versions to 0s m_major = 0; m_minor = 0; m_revision = 0; VersionParseState parseState = kVersionStateNone; bool done = false; for (; index < length && !done; ++index) { char c = versionString[index]; if (isdigit(c)) { switch (parseState) { case kVersionStateNone: parseState = kVersionStateMajor; version = c - '0'; break; case kVersionStateMajor: case kVersionStateMinor: case kVersionStateRevision: version = (version << 4) | (c - '0'); break; } } else if (c == '.') { switch (parseState) { case kVersionStateNone: parseState = kVersionStateNone; break; case kVersionStateMajor: m_major = version; version = 0; parseState = kVersionStateMinor; break; case kVersionStateMinor: m_minor = version; version = 0; parseState = kVersionStateRevision; break; case kVersionStateRevision: m_revision = version; version = 0; done = true; break; } } else { switch (parseState) { case kVersionStateNone: parseState = kVersionStateNone; break; case kVersionStateMajor: m_major = version; done = true; break; case kVersionStateMinor: m_minor = version; done = true; break; case kVersionStateRevision: m_revision = version; done = true; break; } } } switch (parseState) { case kVersionStateMajor: m_major = version; break; case kVersionStateMinor: m_minor = version; break; case kVersionStateRevision: m_revision = version; break; default: // do nothing break; } } //! \brief Converts host endian BCD version values to the equivalent big-endian BCD values. //! //! The output is a half-word. And BCD is inherently big-endian, or byte ordered, if //! you prefer to think of it that way. So for little endian systems, we need to convert //! the output half-word in reverse byte order. When it is written to disk or a //! buffer it will come out big endian. //! //! For example: //! - The input is BCD in host endian format, so 0x1234. Written to a file, this would //! come out as 0x34 0x12, reverse of what we want. //! - The desired BCD output is the two bytes 0x12 0x34. //! - So the function's uint16_t result must be 0x3412 on a little-endian host. //! //! On big endian hosts, we don't have to worry about byte swapping. void version_t::fixByteOrder() { m_major = ENDIAN_HOST_TO_BIG_U16(m_major); m_minor = ENDIAN_HOST_TO_BIG_U16(m_minor); m_revision = ENDIAN_HOST_TO_BIG_U16(m_revision); }