/*******************************************************************

Copyright (c) 2004 Open Mobile Alliance, Ltd.  All Rights Reserved.

This software is made available under the usage and distribution terms 
covered by the Common Public License 1.0 and by using this software you
are bound by the terms and conditions of the same.

EXCEPT AS EXPRESSLY SET FORTH IN THE COMMON PUBLIC LICENSE,
THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
   
Each recipient is solely responsible for determining the 
appropriateness of using and distributing this program and assumes 
all risks associated with its exercise of rights under the Common 
Public License, including but not limited to the risks and 
costs of program errors, compliance with applicable laws, 
damage to or loss of data, programs or equipment, and 
unavailability or interruption of operations.

********************************************************************/
/*************************************************************************/
/* module:          The WBXML Encoder source file                        */
/* file:            xltencwbxml.c                                        */
/* target system:   All                                                  */
/* target OS:       All                                                  */   
/*************************************************************************/


#include <define.h>
#ifdef __SML_WBXML__
/*************************************************************************/
/*  Definitions                                                          */
/*************************************************************************/

#include "xltencwbxml.h"
#include <libmem.h>
#include <libstr.h>
#include "xlttags.h"


/**
 * FUNCTION: wbxmlGetGlobToken
 *
 * Converts a element type into its wbxml token
 *
 * PRE-Condition:   valid element type
 *
 * POST-Condition:  return of wbxml token
 *
 * IN:              elType, element type
 * 
 * OUT:             wbxml token
 * 
 * RETURN:          wbxml token 
 *                  0, if no matching wbxml token
 */
MemByte_t wbxmlGetGlobToken(XltElementType_t elType)
{

  typedef struct GlobTok_s
  {
    XltElementType_t id;
    MemByte_t        wbxml;
  } GlobTok_t;

  // encoding of global tokens; related to the type XML_ElementType_t
  GlobTok_t globtoken[] =
  {
    { END,    0x01 },  //Tag End
    { STR_I,  0x03 },  //Inline string    
    { OPAQUE, 0xC3 },  //Opaque Data  
    { UNDEF,  0x00 }
  };

  int i = -1; 
  while (globtoken[++i].id != UNDEF)
    if (globtoken[i].id == elType)
      return globtoken[i].wbxml;
  return 0;

}

/**
 * FUNCTION: wbxmlOpaqueSize2Buf
 *
 * Converts a Long_t opaque size to a wbxml mb_u_int32 and adds it to the buffer
 *
 * PRE-Condition:   size of the content to be written as opaque datatype
 *
 * POST-Condition:  the size is converted to the mb_u_int32 representation and added
 *                  to the buffer
 *
 * IN:              size, length of the opaque data
 * 
 * IN/OUT:          pBufMgr, pointer to a structure containing buffer management elements
 * 
 * RETURN:          shows error codes of function, 
 *                  0, if OK
 */
Ret_t wbxmlOpaqueSize2Buf(Long_t size, BufferMgmtPtr_t pBufMgr)
{
  Long_t _thresholdcount = 1; 
  Long_t _bytesNeeded = 0;
  MemPtr_t _byteArray;
  MemPtr_t _tmpByteArray;
  int i, j;
  Ret_t _err;

  //j max = number of bytes of size
   for (j=1; j<=sizeof(size); j++)
  {
    //if the size of the content is smaller than the power of 128,j -> 
    //one more byte is needed in the mb_u_int32 representation of WBXML
     _thresholdcount = _thresholdcount * 128;   
     if(size < _thresholdcount)
     {
       _bytesNeeded = j;
       break;
     } 
  }

  if (pBufMgr->spaceEvaluation == 0)
  {
    //allocate number of bytes needed by the mb_u_int32 data type
    if ((_byteArray = smlLibMalloc(_bytesNeeded)) == NULL) return SML_ERR_NOT_ENOUGH_SPACE;

    _tmpByteArray = _byteArray;

    //process al bytes in the mb_u_int32 data type
    for (i=1; i<=_bytesNeeded; i++)
	{
      // the lowest byte needs a 0 in its highest bit -> no | 0x80
      if ((_bytesNeeded - i) == 0)
	  {
        *_tmpByteArray = ((unsigned char)(size & 0x7F));
	  }
      // all the other byte needs a 1 in its highest bit -> | 0x80
      else
	  {
        // only the seven lower bits contain the size value -> >> 7       
        *_tmpByteArray = ((unsigned char)(((size >> (7 * (_bytesNeeded - i))) & 0x7F) | 0x80));
        _tmpByteArray++;
	  }
	}

    _err = xltAddToBuffer(_byteArray, _bytesNeeded, pBufMgr);

    smlLibFree(_byteArray);
  } else {
    pBufMgr->smlXltWrittenBytes += _bytesNeeded;
  }

  return _err;
}

/**
 * FUNCTION: wbxmlGenerateTag
 *
 * Generates a tag for a given tag ID and a given tag type
 *
 * PRE-Condition:   valid parameters 
 *
 * POST-Condition:  a new wbxml tag is written to the buffer
 *
 * IN:              tagId, the ID for the tag to generate (TN_ADD, ...)
 *                  tagType, the tag type (e.g. Begin Tag -> TT_BEG, ...)
 * 
 * IN/OUT:          pBufMgr, pointer to a structure containing buffer management elements
 * 
 * RETURN:          shows error codes of function, 
 *                  0, if OK
 */
Ret_t wbxmlGenerateTag(XltTagID_t tagId, XltTagType_t tagType, BufferMgmtPtr_t pBufMgr )
{

  Ret_t _err = SML_ERR_OK;
  MemByte_t _tmp = 0x00;

  //check if content byte has to be added to the tag
  switch (tagType)
  {
    //set the end tag
    case TT_END:
    {
      _tmp = (MemByte_t)wbxmlGetGlobToken(END);
      if (!_tmp) return SML_ERR_XLT_INVAL_TAG_TYPE;
      _err = xltAddToBuffer((&_tmp), 1, pBufMgr);
      // remember the number of byte that must follow for the according  end-tag
	  if (_err == SML_ERR_OK) pBufMgr->endTagSize -= 1;
	  return _err;
    }    
    //Begin and End Tag in one
    case TT_ALL:
    {
      _err = (MemByte_t)getTagByte(tagId, pBufMgr->smlCurExt, &_tmp);
      if ((!_tmp) || (_err != SML_ERR_OK)) return _err;
      return xltAddToBuffer((MemPtr_t)(&_tmp), 1, pBufMgr);
    }
    //Only Begin Tag -> content follows -> content byte has to be added
    case TT_BEG:
    {
      _err = (MemByte_t)getTagByte(tagId, pBufMgr->smlCurExt, &_tmp);
      if ((!_tmp) || (_err != SML_ERR_OK)) return _err;

      _tmp = ((MemByte_t)(_tmp | XLT_CONTBYTE));
      _err = xltAddToBuffer(&_tmp, 1, pBufMgr);
      // remember the number of byte that must follow for the according  end-tag
	  if (_err == SML_ERR_OK) pBufMgr->endTagSize += 1;
	  return _err;
    }
	default:
    return SML_ERR_XLT_INVAL_TAG_TYPE;
  }
         
 // return SML_ERR_OK;Unreachable
}

/**
 * FUNCTION: wbxmlWriteTypeToBuffer
 *
 * Write a content of a certain WBXML element type (e.g. STR_I) to the global buffer
 *
 * PRE-Condition:   valid parameters 
 *
 * POST-Condition:  the content is written to the wbxml buffer with the leading
 *                  bytes for the opaque data type or the STR_I data type
 *
 * IN:              pContent, the character pointer referencing the content to
 *                            write to the buffer
 *                  elType, the element type to write to the buffer (e.g. STR_I)
 *                  size, the content length
 * 
 * IN/OUT:          pBufMgr, pointer to a structure containing buffer management elements
 * 
 * RETURN:          shows error codes of function, 
 *                  0, if OK
 */
Ret_t wbxmlWriteTypeToBuffer(const MemPtr_t pContent, XltElementType_t elType, Long_t size, BufferMgmtPtr_t pBufMgr)
{
  Ret_t _err;

  MemByte_t _termstr = XLT_TERMSTR;
  MemByte_t _tmp;
  
  switch((int)elType)
  {
    case TAG:
    {

      return (xltAddToBuffer(pContent, size, pBufMgr));

    }
    case STR_I:
    {
        _tmp = (MemByte_t)wbxmlGetGlobToken(STR_I);
       if (!_tmp) return SML_ERR_XLT_WBXML_UKN_TOK;

      //add the STR_I identifier
      if ((_err = xltAddToBuffer(&_tmp, 1, pBufMgr)) != SML_ERR_OK) return _err;

      //add the string to the buffer
      if ((_err = xltAddToBuffer(pContent, size, pBufMgr)) != SML_ERR_OK) return _err;

      //add the string terminator '\0'
      if ((_err = xltAddToBuffer(&_termstr, 1, pBufMgr)) != SML_ERR_OK) return _err;

      return SML_ERR_OK;
    }
    case OPAQUE:
    {
      _tmp = (MemByte_t)wbxmlGetGlobToken(OPAQUE);
       if (!_tmp) return SML_ERR_XLT_WBXML_UKN_TOK;

      

      //add the OPAQUE identifier
      if ((_err = xltAddToBuffer(&_tmp, 1, pBufMgr)) != SML_ERR_OK) return _err;

      //add the pContent length      
      if ((_err = wbxmlOpaqueSize2Buf(size, pBufMgr)) != SML_ERR_OK) return _err;

      //add the string buffer
      if ((_err = xltAddToBuffer(pContent, size, pBufMgr)) != SML_ERR_OK) return _err;

      return SML_ERR_OK;
    }
	default:
    return SML_ERR_XLT_INVAL_PCDATA_TYPE;
  }

//  return SML_ERR_OK;unreachable
}
#endif