Newer
Older
Import / applications / MakePDF / Tests / exip-0.5.4 / src / streamIO / src / streamDecode.c
/*==================================================================*\
|                EXIP - Embeddable EXI Processor in C                |
|--------------------------------------------------------------------|
|          This work is licensed under BSD 3-Clause License          |
|  The full license terms and conditions are located in LICENSE.txt  |
\===================================================================*/

/**
 * @file streamDecode.c
 * @brief Implementing the interface to a higher-level EXI stream decoder - decode basic EXI types
 *
 * @date Aug 18, 2010
 * @author Rumen Kyusakov
 * @version 0.5
 * @par[Revision] $Id: streamDecode.c 343 2014-11-14 17:28:18Z kjussakov $
 */

#include "streamDecode.h"
#include "streamRead.h"
#include "stringManipulate.h"
#include "ioUtil.h"
#include <math.h>

errorCode decodeNBitUnsignedInteger(EXIStream* strm, unsigned char n, unsigned int* int_val)
{
	DEBUG_MSG(INFO, DEBUG_STREAM_IO, (">> (%d-bits uint)", n));
	if(n == 0)
	{
		*int_val = 0;
		return EXIP_OK;
	}

	if(WITH_COMPRESSION(strm->header.opts.enumOpt) == FALSE && GET_ALIGNMENT(strm->header.opts.enumOpt) == BIT_PACKED)
	{
		return readBits(strm, n, int_val);
	}
	else
	{
		unsigned int byte_number = ((unsigned int) n) / 8 + (n % 8 != 0);
		unsigned long tmp_byte_buf = 0;
		unsigned int i = 0;

		if(strm->buffer.bufContent < strm->context.bufferIndx + byte_number)
		{
			// The buffer end is reached: there are fewer than byte_number left unparsed
			errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;

			TRY(readEXIChunkForParsing(strm, byte_number));
		}

		*int_val = 0;
		for(i = 0; i < byte_number*8; i += 8)
		{
			tmp_byte_buf = strm->buffer.buf[strm->context.bufferIndx] << i;
			*int_val = *int_val | tmp_byte_buf;
			strm->context.bufferIndx++;
		}
	}
	return EXIP_OK;
}

errorCode decodeBoolean(EXIStream* strm, boolean* bool_val)
{
	//TODO:  when pattern facets are available in the schema datatype - handle it differently
	DEBUG_MSG(INFO, DEBUG_STREAM_IO, (">> (bool)"));
	return decodeNBitUnsignedInteger(strm, 1, bool_val);
}

errorCode decodeUnsignedInteger(EXIStream* strm, UnsignedInteger* int_val)
{
	errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
	unsigned int i = 0;
	unsigned int tmp_byte_buf = 0;
	*int_val = 0;

	DEBUG_MSG(INFO, DEBUG_STREAM_IO, (">> (uint)"));
	do
	{
		TRY(readBits(strm, 8, &tmp_byte_buf));

		*int_val += ((UnsignedInteger) (tmp_byte_buf & 0x7F)) << i;
		i += 7;
	}
	while(tmp_byte_buf & 0x80);

	return EXIP_OK;
}

errorCode decodeString(EXIStream* strm, String* string_val)
{
	errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
	UnsignedInteger string_length = 0;
	DEBUG_MSG(INFO, DEBUG_STREAM_IO, (">> (string)"));
	TRY(decodeUnsignedInteger(strm, &string_length));
	TRY(allocateStringMemoryManaged(&(string_val->str),(Index) string_length, &strm->memList));

	return decodeStringOnly(strm,(Index)  string_length, string_val);
}

errorCode decodeStringOnly(EXIStream* strm, Index str_length, String* string_val)
{
	// Assume no Restricted Character Set is defined
	//TODO: Handle the case when Restricted Character Set is defined

	// The exact size of the string is known at this point. This means that
	// this is the place to allocate the memory for the  { CharType* str; }!!!
	errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
	Index i = 0;
	Index writerPosition = 0;
	UnsignedInteger tmp_code_point = 0;

	string_val->length = str_length;

	for(i = 0; i < str_length; i++)
	{
		TRY(decodeUnsignedInteger(strm, &tmp_code_point));
		TRY(writeCharToString(string_val, (uint32_t) tmp_code_point, &writerPosition));
	}
	return EXIP_OK;
}

errorCode decodeBinary(EXIStream* strm, char** binary_val, Index* nbytes)
{
	errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
	UnsignedInteger length = 0;
	unsigned int int_val = 0;
	UnsignedInteger i = 0;

	DEBUG_MSG(INFO, DEBUG_STREAM_IO, (">> (binary)"));
	TRY(decodeUnsignedInteger(strm, &length));
	*nbytes = (Index) length;
	(*binary_val) = (char*) EXIP_MALLOC(length); // This memory should be manually freed after the content handler is invoked
	if((*binary_val) == NULL)
		return EXIP_MEMORY_ALLOCATION_ERROR;

	for(i = 0; i < length; i++)
	{
		TRY_CATCH(readBits(strm, 8, &int_val), EXIP_MFREE(*binary_val));
		(*binary_val)[i]=(char) int_val;
	}
	return EXIP_OK;
}

errorCode decodeIntegerValue(EXIStream* strm, Integer* sint_val)
{
	// TODO: If there is associated schema datatype handle differently!
	// TODO: check if the result fit into int type
	errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
	boolean bool_val = 0;
	UnsignedInteger val;

	DEBUG_MSG(INFO, DEBUG_STREAM_IO, (">> (int)"));

	TRY(decodeBoolean(strm, &bool_val));
	TRY(decodeUnsignedInteger(strm, &val));

	if(bool_val == 0) // A sign value of zero (0) is used to represent positive integers
		*sint_val = (Integer) val;
	else if(bool_val == 1) // A sign value of one (1) is used to represent negative integers
	{
		val += 1;
		*sint_val = -((Integer) val);
	}
	else
		return EXIP_UNEXPECTED_ERROR;
	return EXIP_OK;
}

errorCode decodeDecimalValue(EXIStream* strm, Decimal* dec_val)
{
	errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
	boolean sign;
	UnsignedInteger integr_part = 0;
	UnsignedInteger fract_part = 0;
	UnsignedInteger fract_part_rev = 0;
	unsigned int e;

	DEBUG_MSG(INFO, DEBUG_STREAM_IO, (">> (decimal)"));

	// TODO: implement checks on type overflow

	TRY(decodeBoolean(strm, &sign));
	TRY(decodeUnsignedInteger(strm, &integr_part));
	TRY(decodeUnsignedInteger(strm, &fract_part));

	dec_val->exponent = 0;
	fract_part_rev = 0;
	while(fract_part > 0)
	{
		fract_part_rev = fract_part_rev*10 + fract_part%10;
		fract_part = fract_part/10;
		dec_val->exponent -= 1;
	}

	dec_val->mantissa = integr_part;

	e = dec_val->exponent;
	if(e != 0)
	{
		while(e)
		{
			dec_val->mantissa *= 10;
			e++;
		}

		dec_val->mantissa += fract_part_rev;
	}

	if(sign == TRUE) // negative number
		dec_val->mantissa = -dec_val->mantissa;

	return EXIP_OK;
}

errorCode decodeFloatValue(EXIStream* strm, Float* fl_val)
{
	errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
	Integer mantissa;
	Integer exponent;

	DEBUG_MSG(INFO, DEBUG_STREAM_IO, (">> (float)"));

	TRY(decodeIntegerValue(strm, &mantissa));	//decode mantissa
	TRY(decodeIntegerValue(strm, &exponent));	//decode exponent

	DEBUG_MSG(ERROR, DEBUG_STREAM_IO, (">Float value: %ldE%ld\n", (long int)mantissa, (long int)exponent));

//  TODO: Improve the below validation: it should be independent of how the Float is defined
//
//	if(exponent >= (1 << 14) || exponent < -(1 << 14)
//			|| mantissa >= ((uint64_t) 1 << 63) ||
//			(mantissa < 0 && -mantissa > ((uint64_t) 1 << 63))
//			)
//	{
//		DEBUG_MSG(ERROR, DEBUG_STREAM_IO, (">Invalid float value: %lldE%lld\n", mantissa, exponent));
//		return EXIP_INVALID_EXI_INPUT;
//	}

	fl_val->mantissa = mantissa;
	fl_val->exponent = (int16_t)exponent; /* TODO not using exip_config.h */

	return EXIP_OK;
}

errorCode decodeDateTimeValue(EXIStream* strm, EXIType dtType, EXIPDateTime* dt_val)
{
	errorCode tmp_err_code = EXIP_UNEXPECTED_ERROR;
	Integer year;
	unsigned int monDay = 0;
	unsigned int timeVal = 0;
	boolean presence = FALSE;

	dt_val->presenceMask = 0;

	DEBUG_MSG(INFO, DEBUG_STREAM_IO, (">> (dateTime)"));

	if(dtType == VALUE_TYPE_DATE_TIME || dtType == VALUE_TYPE_DATE || dtType == VALUE_TYPE_YEAR)
	{
		/* Year component */
		TRY(decodeIntegerValue(strm, &year));
		dt_val->dateTime.tm_year = (int) year + 100;
	}
	else
	{
		dt_val->dateTime.tm_year = INT_MIN;
	}

	if(dtType == VALUE_TYPE_DATE_TIME || dtType == VALUE_TYPE_DATE || dtType == VALUE_TYPE_MONTH)
	{
		/* MonthDay component */
		TRY(decodeNBitUnsignedInteger(strm, 9, &monDay));
		dt_val->dateTime.tm_mon = monDay / 32 - 1;
		dt_val->dateTime.tm_mday = monDay % 32;
	}
	else
	{
		dt_val->dateTime.tm_mon = INT_MIN;
		dt_val->dateTime.tm_mday = INT_MIN;
	}

	if(dtType == VALUE_TYPE_DATE_TIME || dtType == VALUE_TYPE_TIME)
	{
		/* Time component */
		TRY(decodeNBitUnsignedInteger(strm, 17, &timeVal));
		dt_val->dateTime.tm_hour = (timeVal / 64) / 64;
		dt_val->dateTime.tm_min = (timeVal / 64) % 64;
		dt_val->dateTime.tm_sec = timeVal % 64;

		/* FractionalSecs presence component */
		TRY(decodeBoolean(strm, &presence));
		if(presence)
		{
			UnsignedInteger fSecs = 0;
			unsigned int tmp = 0;

			dt_val->presenceMask = dt_val->presenceMask | FRACT_PRESENCE;
			dt_val->fSecs.offset = 0;
			dt_val->fSecs.value = 0;

			/* FractionalSecs component */
			TRY(decodeUnsignedInteger(strm, &fSecs));

			while(fSecs != 0)
			{
				tmp = fSecs % 10;
				dt_val->fSecs.offset++;

				if(tmp != 0)
				{
					dt_val->fSecs.value = dt_val->fSecs.value*10 + tmp;
				}

				fSecs = fSecs / 10;
			}
			dt_val->fSecs.offset -= 1;
		}
	}
	else
	{
		dt_val->dateTime.tm_hour = INT_MIN;
		dt_val->dateTime.tm_min = INT_MIN;
		dt_val->dateTime.tm_sec = INT_MIN;
	}

	/* TimeZone presence component */
	TRY(decodeBoolean(strm, &presence));

	if(presence)
	{
		unsigned int tzone = 0;
		dt_val->presenceMask = dt_val->presenceMask | TZONE_PRESENCE;
		TRY(decodeNBitUnsignedInteger(strm, 11, &tzone));

		if(tzone > 1851)
		{
			tzone = 1851;
			DEBUG_MSG(WARNING, DEBUG_STREAM_IO, (">Invalid TimeZone value: %d\n", tzone));
		}

		dt_val->TimeZone = tzone - 896;
	}

	return EXIP_OK;
}