/**************************************************************************
*** COPYRIGHT (c) 2002 by TransNexus, Inc. ***
*** ***
*** This software is property of TransNexus, Inc. ***
*** This software is freely available under license from TransNexus. ***
*** The license terms and conditions for free use of this software by ***
*** third parties are defined in the OSP Toolkit Software License ***
*** Agreement (LICENSE.txt). Any use of this software by third ***
*** parties, which does not comply with the terms and conditions of the ***
*** OSP Toolkit Software License Agreement is prohibited without ***
*** the prior, express, written consent of TransNexus, Inc. ***
*** ***
*** Thank you for using the OSP ToolKit(TM). Please report any bugs, ***
*** suggestions or feedback to support@transnexus.com ***
*** ***
**************************************************************************/
/*
* ospxmlutil.c - Utility functions for parsing and encoding XML documents.
*/
#include "osp.h"
#include "ospbfr.h"
#include "ospxmltype.h"
#include "ospxmldoc.h"
/* pre-defined entity names */
const OSPTXMLDOCENTITY OSPVXMLDocEntities[] =
{
{ '<' , (unsigned char *)"lt" },
{ '>' , (unsigned char *)"gt" },
{ '&' , (unsigned char *)"amp" },
{ '\'' , (unsigned char *)"apos" },
{ '"' , (unsigned char *)"quot" }
};
const unsigned OSPVXMLDocEntitiesSize =
sizeof(OSPVXMLDocEntities)/sizeof(OSPTXMLDOCENTITY);
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLDocIsMatch() - does the document match a given string
*-----------------------------------------------------------------------*/
unsigned /* returns error code */
OSPPXMLDocIsMatch(
OSPTBFR **ospvBfrAddr, /* buffer containing document */
OSPTXMLENC ospvEncoding, /* character encoding */
const unsigned char *ospvString, /* string to check for match */
unsigned ospvStringLen, /* length of match string */
unsigned char ospvScratch[], /* place to store characters */
unsigned *ospvIsMatch /* place to put answer */
)
{
unsigned ospvErrCode = OSPC_ERR_NO_ERROR;
int tmpErrCode = OSPC_ERR_NO_ERROR;
unsigned cnt = 0;
if (ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (*ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (ospvEncoding == ospeXMLEncUnknown)
{
ospvErrCode = OSPC_ERR_XML_BAD_ENC;
}
if (ospvString == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvScratch == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvIsMatch == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
/* assume it's not a match for safety (in case of error break) */
*ospvIsMatch = OSPC_FALSE;
/*
* In the following loop we "peek" at enough characters to
* compare against the string. Note that we're storing the
* "peeked" characters in the scratch array, which is passed
* to us. That way the calling function has to worry about
* sizing the scratch array. But that's okay, since the caller
* presumably knows how big it needs to be. (Hint: It should
* be the same size as the match string.)
*/
for ( cnt=0; cnt<ospvStringLen; cnt++)
{
OSPPXMLDocPeekCharN(ospvBfrAddr, ospvEncoding, cnt,
&ospvScratch[cnt], &tmpErrCode);
if (tmpErrCode != OSPC_ERR_NO_ERROR)
{
break;
}
}
/*
* If we didn't get enough characters to compare, that's not
* an error; but it's certainly not a match either. If we
* didn't get a full scratch buffer, there's no need to
* continue. We've already set the default return to false.
*/
if (cnt == ospvStringLen)
{
/* be sure to null terminate the scratch string */
ospvScratch[cnt] = 0;
/* now that we've extracted the tag characters, see what we've got */
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
if (OSPM_MEMCMP((const char *)ospvScratch,
(const char *)ospvString, ospvStringLen) == 0)
{
*ospvIsMatch = OSPC_TRUE;
}
}
}
}
return(ospvErrCode);
}
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLDocSkipPast() - skip past a string in the document
*-----------------------------------------------------------------------*/
unsigned /* returns error code */
OSPPXMLDocSkipPast(
OSPTBFR **ospvBfrAddr, /* buffer containing document */
OSPTXMLENC ospvEncoding, /* character encoding */
const unsigned char *ospvString, /* string to skip past */
unsigned char ospvScratch[] /* place to store characters */
)
{
unsigned ospvErrCode = OSPC_ERR_NO_ERROR;
unsigned cnt;
unsigned len = 0;
if (ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (*ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (ospvEncoding == ospeXMLEncUnknown)
{
ospvErrCode = OSPC_ERR_XML_BAD_ENC;
}
if (ospvString == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvScratch == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
/*
* In the following loop we pre-load the scratch buffer with enough
* to compare against the string. Note that we're storing the
* characters in the scratch array, which is passed to us. That way
* the calling function has to worry about sizing the scratch array.
* But that's okay, since the caller presumably knows how big it
* needs to be. (Hint: It should be the same size as the match string.)
*/
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
for ( cnt=0, len=OSPM_STRLEN((const char *)ospvString);
((cnt<len) && (ospvErrCode==OSPC_ERR_NO_ERROR));
cnt++)
{
ospvErrCode = OSPPXMLDocReadChar(ospvBfrAddr, ospvEncoding,
&ospvScratch[cnt]);
}
/* be sure to null terminate the scratch string */
ospvScratch[cnt] = 0;
}
/*
* Now we start the main loop of the function. Here we're checking
* for a match and we continue reading characters until we find one.
*/
while (ospvErrCode == OSPC_ERR_NO_ERROR)
{
if (OSPM_MEMCMP((const char *)ospvScratch, (const char *)ospvString, len) == 0)
{
/* we've found the match, so we're done */
break;
}
/*
* No match yet, so we keep looking. First we need to shift
* the scratch buffer to make room for the new character.
* If a non-destructive memcpy is available, it might be
* a good candidate for optimizing this part.
*/
for (cnt=0; cnt<(len-1); cnt++)
{
ospvScratch[cnt] = ospvScratch[cnt+1];
}
ospvErrCode = OSPPXMLDocReadChar(ospvBfrAddr, ospvEncoding,
&ospvScratch[len-1]);
}
return(ospvErrCode);
}
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLDocSkipPastChar() - skip XML until just past a single character
*-----------------------------------------------------------------------*/
unsigned /* returns error code */
OSPPXMLDocSkipPastChar(
OSPTBFR **ospvBfrAddr, /* buffer containing document */
OSPTXMLENC ospvEncoding, /* character encoding for the document */
unsigned char ospvChar /* character to skip past */
)
{
unsigned ospvErrCode = OSPC_ERR_NO_ERROR;
unsigned char readChar;
if (ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (*ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (ospvEncoding == ospeXMLEncUnknown)
{
ospvErrCode = OSPC_ERR_XML_BAD_ENC;
}
/* loop looking for the character */
while (ospvErrCode == OSPC_ERR_NO_ERROR)
{
ospvErrCode = OSPPXMLDocReadChar(ospvBfrAddr, ospvEncoding,
&readChar);
if (readChar==ospvChar)
{
break;
}
}
return(ospvErrCode);
}
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLDocGetEncoding()
*-----------------------------------------------------------------------*/
unsigned /* returns error code */
OSPPXMLDocGetEncoding(
OSPTBFR **ospvBfrAddr, /* buffer containing document */
OSPTXMLENC *ospvEncoding /* place to store encoding type */
)
{
unsigned ospvErrCode = OSPC_ERR_NO_ERROR;
int readChar;
unsigned char char1 = '\0';
unsigned char char2 = '\0';
if (ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (*ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
*ospvEncoding = ospeXMLEncUnknown;
/*
* First have a look at the first two bytes in the buffer. From
* these, we can deduce the character encoding.
*/
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
readChar = OSPPBfrPeekByte(*ospvBfrAddr);
if (readChar != -1)
{
char1 = (char) readChar;
}
else
{
ospvErrCode = OSPC_ERR_BUF_INCOMPLETE;
}
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
readChar = OSPPBfrPeekByteN(*ospvBfrAddr,1);
if (readChar != -1)
{
char2 = (char) readChar;
}
else
{
ospvErrCode = OSPC_ERR_XML_INCOMPLETE;
}
}
/*
* Now we check the characters, this stuff is pretty much
* straight from the XML specification.
*/
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
if ((char1 == OSPC_XMLDOC_UTF16MSB) &&
(char2 == OSPC_XMLDOC_UTF16LSB))
{
/* we found the UTF-16 byte order mark, it's big-endian */
*ospvEncoding = ospeXMLEncUTF16b;
}
else if ((char1 == OSPC_XMLDOC_UTF16LSB) &&
(char2 == OSPC_XMLDOC_UTF16LSB))
{
/* we found the UTF-16 byte order mark, it's little-endian */
*ospvEncoding = ospeXMLEncUTF16l;
}
else if ((char1 == OSPC_XMLDOC_UTF16NULL) &&
(char2 == OSPC_XMLDOC_OPEN))
{
/* UTF-16 without the byte order mark, big-endian */
*ospvEncoding = ospeXMLEncUTF16b;
}
else if ((char1 == OSPC_XMLDOC_OPEN) &&
(char2 == OSPC_XMLDOC_UTF16NULL))
{
/* UTF-16 without the byte order mark, little-endian */
*ospvEncoding = ospeXMLEncUTF16l;
}
else if ((char1 == OSPC_XMLDOC_OPEN) &&
(char2 == OSPC_XMLDOC_QUEST))
{
/* this is UTF-8 */
*ospvEncoding = ospeXMLEncUTF8;
}
else
{
/*
* According to the XML standard, anything other
* than UTF8 or UTF16 must have a character
* encoding declaration. Since we've already
* checked for UTF16 and we've already looked
* for the start of a character encoding, that
* only leaves UTF8.
*/
*ospvEncoding = ospeXMLEncUTF8;
}
}
return(ospvErrCode);
}
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLDocTranslateEntity() - translate an entity name into its value
*-----------------------------------------------------------------------*/
unsigned /* returns error code */
OSPPXMLDocTranslateEntity(
unsigned char *ospvName,
unsigned char *ospvChar /* place to store character */
)
{
unsigned ospvErrCode = OSPC_ERR_NO_ERROR;
unsigned cnt;
if (ospvName == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvChar == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
/* is this a character reference */
if (*ospvName == OSPC_XMLDOC_CHARREF)
{
ospvName++;
/* is it hex? */
if (*ospvName == OSPC_XMLDOC_HEXREF)
{
/* this one's hex */
ospvName++;
for (*ospvChar = 0; *ospvName; ospvName++)
{
*ospvChar *= 0x10;
if ((*ospvName >= '0') && (*ospvName <= '9'))
{
unsigned char x = *ospvChar;
*ospvChar = (unsigned char)(x + ((unsigned char)*ospvName - (unsigned char)'0'));
}
else if ((*ospvName >= 'a') && (*ospvName <= 'f'))
{
unsigned char x = *ospvChar;
*ospvChar = (unsigned char)(x + ((unsigned char)*ospvName - (unsigned char)'a') + 10);
}
else if ((*ospvName >= 'A') && (*ospvName <= 'F'))
{
unsigned char x = *ospvChar;
*ospvChar = (unsigned char)(x + ((unsigned char)*ospvName - (unsigned char)'A') + 10);
}
else
{
ospvErrCode = OSPC_ERR_XML_BAD_ENTITY;
}
}
}
else
{
/* just a decimal character reference */
for (*ospvChar = 0; *ospvName; ospvName++)
{
*ospvChar *= 10;
if ((*ospvName >= '0') && (*ospvName <= '9'))
{
unsigned char x = *ospvChar;
*ospvChar = (unsigned char)(x + ((unsigned char)*ospvName - (unsigned char)'0'));
}
else
{
ospvErrCode = OSPC_ERR_XML_BAD_ENTITY;
}
}
}
}
else
{
/* not a character reference - check for predefined name */
for (cnt=0; cnt<OSPVXMLDocEntitiesSize; cnt++)
{
if (OSPM_MEMCMP((const char *)ospvName,
(const char *)OSPVXMLDocEntities[cnt].ospmEntName,
OSPM_STRLEN((const char *)(const char *)OSPVXMLDocEntities[cnt].ospmEntName)) == 0)
{
break;
}
}
if (cnt < OSPVXMLDocEntitiesSize)
{
*ospvChar = OSPVXMLDocEntities[cnt].ospmEntValue;
}
else
{
ospvErrCode = OSPC_ERR_XML_BAD_ENTITY;
}
}
}
return(ospvErrCode);
}
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLDocReadChar() - read a single character from an XML document
*-----------------------------------------------------------------------*/
unsigned /* returns error code */
OSPPXMLDocReadChar(
OSPTBFR **ospvBfrAddr, /* buffer containing document */
OSPTXMLENC ospvEncoding, /* character encoding for document */
unsigned char *ospvChar /* place to store read character */
)
{
unsigned ospvErrCode = OSPC_ERR_NO_ERROR;
int readChar = '\0';
if (ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (*ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (ospvEncoding == ospeXMLEncUnknown)
{
ospvErrCode = OSPC_ERR_XML_BAD_ENC;
}
if (ospvChar == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
/* read the first byte */
readChar = OSPPBfrReadByte(*ospvBfrAddr);
if (readChar == -1)
{
ospvErrCode = OSPC_ERR_BUF_INCOMPLETE;
}
}
/* what we do next depends on the encoding */
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
/* UTF-8 is pretty easy -- we're done */
if (ospvEncoding == ospeXMLEncUTF8)
{
*ospvChar = (unsigned char)readChar;
}
else
{
if (ospvEncoding == ospeXMLEncUTF16l)
{
*ospvChar = (unsigned char)readChar;
readChar = OSPPBfrReadByte(*ospvBfrAddr);
if (readChar == -1)
{
ospvErrCode = OSPC_ERR_BUF_INCOMPLETE;
}
else if (readChar != OSPC_XMLDOC_UTF16NULL)
{
ospvErrCode = OSPC_ERR_XML_BAD_ENC;
}
}
else
{
if (ospvEncoding == ospeXMLEncUTF16b)
{
readChar = OSPPBfrReadByte(*ospvBfrAddr);
if (readChar == -1)
{
ospvErrCode = OSPC_ERR_BUF_INCOMPLETE;
}
else if (readChar != OSPC_XMLDOC_UTF16NULL)
{
ospvErrCode = OSPC_ERR_XML_BAD_ENC;
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
*ospvChar = (unsigned char)readChar;
}
}
}
}
}
return(ospvErrCode);
}
#ifdef OSPC_DEBUG
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLDocPeekCharN() - look at the Nth character in an XML document
*-----------------------------------------------------------------------*/
void
OSPPXMLDocPeekCharN(
OSPTBFR **ospvBfrAddr, /* buffer containing document */
OSPTXMLENC ospvEncoding, /* character encoding for the document */
unsigned ospvCnt, /* character to look at */
unsigned char *ospvChar, /* place to store character */
int *ospvErrCode /* error code */
)
{
int readChar = '\0';
if (ospvBfrAddr == OSPC_OSNULL)
{
*ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (*ospvBfrAddr == OSPC_OSNULL)
{
*ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (ospvEncoding == ospeXMLEncUnknown)
{
*ospvErrCode = OSPC_ERR_XML_BAD_ENC;
}
if (ospvChar == OSPC_OSNULL)
{
*ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (*ospvErrCode == OSPC_ERR_NO_ERROR)
{
/* handle each encoding separately */
switch (ospvEncoding)
{
case ospeXMLEncUTF8:
readChar = OSPPBfrPeekByteN(*ospvBfrAddr, ospvCnt);
break;
case ospeXMLEncUTF16l:
readChar = OSPPBfrPeekByteN(*ospvBfrAddr, 2*ospvCnt);
break;
case ospeXMLEncUTF16b:
readChar = OSPPBfrPeekByteN(*ospvBfrAddr, (2*ospvCnt+1));
break;
default:
*ospvErrCode = (unsigned )OSPC_ERR_OS_FAILURE;
break;
}
}
if (*ospvErrCode == OSPC_ERR_NO_ERROR)
{
if(readChar == -1)
{
*ospvErrCode = OSPC_ERR_BUF_INCOMPLETE;
}
else
{
*ospvChar = (unsigned char)readChar;
}
}
return;
}
#endif /* OSPC_DEBUG */
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLDocSkipWhite() - skip whitespace in an XML document
*-----------------------------------------------------------------------*/
unsigned /* returns error code */
OSPPXMLDocSkipWhite(
OSPTBFR **ospvBfrAddr, /* buffer containing document */
OSPTXMLENC ospvEncoding /* character encoding for the document */
)
{
unsigned ospvErrCode = OSPC_ERR_NO_ERROR;
unsigned char readChar = 0;
if (ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (*ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (ospvEncoding == ospeXMLEncUnknown)
{
ospvErrCode = OSPC_ERR_XML_BAD_ENC;
}
while (ospvErrCode == OSPC_ERR_NO_ERROR)
{
OSPPXMLDocPeekCharN(ospvBfrAddr, ospvEncoding, 0,
&readChar, (int *)&ospvErrCode);
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
if (OSPPXMLIsSpace(readChar))
{
ospvErrCode = OSPPXMLDocReadChar(ospvBfrAddr, ospvEncoding,
&readChar);
}
else
{
break;
}
}
}
return(ospvErrCode);
}
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLAddReference() - add entity references to XML character data
*-----------------------------------------------------------------------*/
unsigned /* returns error code */
OSPPXMLAddReference(
const unsigned char *ospvRawData, /* data to reference */
unsigned ospvDataSize, /* number of bytes of data */
OSPTBFR **ospvBfrAddr /* buffer to stuff output */
)
{
unsigned ospvErrCode = OSPC_ERR_NO_ERROR;
unsigned dataCnt;
unsigned char ch;
if (ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (*ospvBfrAddr == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (ospvRawData == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
for ( dataCnt=0; (dataCnt<ospvDataSize) && (ospvErrCode == OSPC_ERR_NO_ERROR);
dataCnt++, ospvRawData++)
{
/*
* There are two things that will cause us to replace a raw
* data byte with an entity reference: (1) a value that
* XML does not consider a valid character (e.g. 0); and
* (2) the "greater than" character (>) that marks the
* end of element tags and CDATA sections. (Other sections
* aren't relevant because they won't be confused with
* character data anyway.)
*/
if (OSPPXMLIsChar(*ospvRawData) &&
(*ospvRawData != OSPC_XMLDOC_CLOSE))
{
/* this character's okay as is */
if (OSPPBfrWriteByte(ospvBfrAddr, *ospvRawData) != 1)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
}
else
{
/* this one needs to be referenced */
if (OSPPBfrWriteByte(ospvBfrAddr, OSPC_XMLDOC_REF) != 1)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
if (OSPPBfrWriteByte(ospvBfrAddr, OSPC_XMLDOC_CHARREF) != 1)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
if (OSPPBfrWriteByte(ospvBfrAddr, OSPC_XMLDOC_HEXREF) != 1)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
ch = (char)('0' + (*ospvRawData)/16);
if (ch > '9')
{
ch += 'a' - '0' - 10;
}
if (OSPPBfrWriteByte(ospvBfrAddr, ch) != 1)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
ch = (char)('0' + ((*ospvRawData)%16));
if (ch > '9')
{
ch += 'a' - '0' - 10;
}
if (OSPPBfrWriteByte(ospvBfrAddr, ch) != 1)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
}
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
if (OSPPBfrWriteByte(ospvBfrAddr, OSPC_XMLDOC_REFEND) != 1)
{
ospvErrCode = OSPC_ERR_BUF_EMPTY;
}
}
}
}
}
return(ospvErrCode);
}
/**/
/*-----------------------------------------------------------------------*
* OSPPXMLDereference() - resolve entity references in XML character data
*-----------------------------------------------------------------------*/
unsigned /* returns error code */
OSPPXMLDereference(
const unsigned char *ospvCharData, /* character data to deference */
unsigned *ospvDataSize, /* input: max, output: actual */
unsigned char *ospvRawData /* place to put output */
)
{
unsigned ospvErrCode = OSPC_ERR_NO_ERROR;
unsigned dataCnt;
unsigned charCnt;
unsigned char entity[OSPC_XMLDOC_ENTITYSIZE];
unsigned char *start = ospvRawData;
/* Description of the following variable:
* TRUE = Find the length of the data and write the data to ospvRawData
* FALSE = Find only the length of the data
*/
unsigned flag = OSPC_FALSE;
/* If flag == TRUE, the following is used to store the size of the entity
* after it has been translated.
*/
unsigned char translatedEntity[OSPC_XMLDOC_ENTITYSIZE];
if (ospvCharData == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvDataSize == OSPC_OSNULL)
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
if (ospvRawData == OSPC_OSNULL)
{
if (*ospvDataSize == 0)
{
flag = OSPC_FALSE;
}
else
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
}
else
{
if (*ospvDataSize > 0)
{
flag = OSPC_TRUE;
}
else
{
ospvErrCode = OSPC_ERR_XML_INVALID_ARGS;
}
}
/*
* As we start the loop through the characters, we can end
* the loop one of two ways: (1) we get to the end of the
* string, which is indicated by a NULL byte; or (2) something
* bad happens. Bad things will be flagged by ospvErrCode
* so the loop can watch that.
*/
/* The variable flag determines which mode this function is in.
* If flag is set to FALSE, then this function only determines
* the size of the data in ospvCharData; otherwise, this
* function returns the processed data in ospvRawData as well
* as its size.
*/
/* keep track of how much data we've written */
dataCnt = 0;
/* and go into our loop */
while ((ospvErrCode == OSPC_ERR_NO_ERROR) && (*ospvCharData != '\0'))
{
/* is the byte a reference instead of a raw character? */
if (*ospvCharData == OSPC_XMLDOC_REF)
{
/* this is an entity reference, get the whole entity name */
/* first skipping past the reference character */
ospvCharData++;
for (charCnt=0; charCnt<OSPC_XMLDOC_ENTITYSIZE; charCnt++)
{
/* are we at the end of the reference? */
if (*ospvCharData == '\0')
{
/* yes, but we didn't finish! */
ospvErrCode = OSPC_ERR_XML_BAD_ENTITY;
break;
}
else if (*ospvCharData == OSPC_XMLDOC_REFEND)
{
/*
* We've found the end of the entity reference;
* skip past it and break.
*/
ospvCharData++;
break;
}
else
{
/* just another part of the reference */
entity[charCnt] = *ospvCharData++;
}
}
/* we got to the end of the reference, make sure no errors */
if (ospvErrCode == OSPC_ERR_NO_ERROR)
{
entity[charCnt] = '\0';
if(flag == OSPC_TRUE)
{
ospvErrCode = OSPPXMLDocTranslateEntity(entity, ospvRawData);
ospvRawData++;
dataCnt++;
}
else
{
/* Clear the buffer that temporarily holds the entity for counting */
for(charCnt = 0; charCnt < OSPC_XMLDOC_ENTITYSIZE; charCnt++)
{
translatedEntity[charCnt] = '\0';
}
/* Get the entity */
ospvErrCode = OSPPXMLDocTranslateEntity(entity, translatedEntity);
/* Determine the size of the entity and add it to dataCnt *
dataCnt += OSPM_STRLEN((const char *)translatedEntity); */
dataCnt++;
}
}
}
else
{
if(flag == OSPC_TRUE)
{
/* just a plain old character */
*ospvRawData++ = *ospvCharData++;
}
else
{
*ospvCharData++;
}
dataCnt++;
}
/* make sure there's still room in the data area */
if ((flag == OSPC_TRUE)&&(dataCnt > *ospvDataSize))
{
ospvErrCode = (unsigned )OSPC_ERR_OS_FAILURE;
break;
}
}
/* update the size of the data */
*ospvDataSize = dataCnt;
if(flag == OSPC_TRUE)
{
ospvRawData = start;
}
return(ospvErrCode);
}