Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*
 * 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);
}