/* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2005 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
*
* wsencode.c
*
* Author: Markku Rossi
*
* Copyright (c) 1999-2000 WAPIT OY LTD.
* All rights reserved.
*
* Encoding and decoding routines.
*
*/
#include "wsint.h"
/********************* Types and definitions ****************************/
#define WS_MB_CONT_BIT 0x80
#define WS_MB_DATA_MASK 0x7f
/********************* Global functions *********************************/
unsigned char *ws_encode_mb_uint32(WsUInt32 value, unsigned char *buffer,
size_t *len_return)
{
unsigned char *p = buffer + WS_MB_UINT32_MAX_ENCODED_LEN;
size_t len = 1;
/* Set the terminator byte. */
*p = value & WS_MB_DATA_MASK;
value >>= 7;
p--;
/* And add the data. */
while (value > 0) {
*p = (value & WS_MB_DATA_MASK) | WS_MB_CONT_BIT;
value >>= 7;
p--;
len++;
}
*len_return = len;
return p + 1;
}
WsUInt32 ws_decode_mb_uint32(const unsigned char *buffer, size_t *len)
{
WsUInt32 value = 0;
size_t i;
for (i = 0; i < *len; i++) {
value <<= 7;
value |= buffer[i] & WS_MB_DATA_MASK;
if ((buffer[i] & WS_MB_CONT_BIT) == 0)
break;
}
*len = i + 1;
return value;
}
WsBool ws_encode_buffer(WsBuffer *buffer, ...)
{
va_list ap;
WsEncodingSpec spec;
int ival;
unsigned char *p;
unsigned char *cp;
size_t len;
WsUInt32 ui32;
unsigned char data[64];
va_start(ap, buffer);
while ((spec = va_arg(ap, int)) != WS_ENC_END)
{
switch (spec)
{
case WS_ENC_BYTE:
case WS_ENC_INT8:
case WS_ENC_UINT8:
ival = va_arg(ap, int);
if (!ws_buffer_append_space(buffer, &p, 1))
goto error;
WS_PUT_UINT8(p, ival);
break;
case WS_ENC_INT16:
case WS_ENC_UINT16:
ival = va_arg(ap, int);
if (!ws_buffer_append_space(buffer, &p, 2))
goto error;
WS_PUT_UINT16(p, ival);
break;
case WS_ENC_INT32:
case WS_ENC_UINT32:
ival = va_arg(ap, long);
if (!ws_buffer_append_space(buffer, &p, 4))
goto error;
WS_PUT_UINT32(p, ival);
break;
case WS_ENC_MB_UINT16:
case WS_ENC_MB_UINT32:
if (spec == WS_ENC_MB_UINT16)
ui32 = va_arg(ap, int);
else
ui32 = va_arg(ap, long);
len = sizeof(data);
cp = ws_encode_mb_uint32(ui32, data, &len);
if (!ws_buffer_append_space(buffer, &p, len))
goto error;
memcpy(p, cp, len);
break;
case WS_ENC_DATA:
cp = va_arg(ap, unsigned char *);
len = va_arg(ap, unsigned int);
if (!ws_buffer_append_space(buffer, &p, len))
goto error;
memcpy(p, cp, len);
break;
default:
ws_fatal("ws_encode_buffer(): unknown type %d: probably a missing "
"WS_ENC_END",
spec);
break;
}
}
va_end(ap);
return WS_TRUE;
/*
* Error handling.
*/
error:
va_end(ap);
return WS_FALSE;
}
size_t ws_decode_buffer(const unsigned char *buffer, size_t buffer_len, ...)
{
va_list ap;
WsEncodingSpec spec;
WsUInt8 *i8p;
WsUInt16 *i16p;
WsUInt32 *i32p;
unsigned char **cpp;
size_t len;
size_t orig_buffer_len = buffer_len;
va_start(ap, buffer_len);
while ((spec = va_arg(ap, int)) != WS_ENC_END) {
switch (spec) {
case WS_ENC_BYTE:
case WS_ENC_INT8:
case WS_ENC_UINT8:
if (buffer_len < 1)
goto too_short_buffer;
i8p = va_arg(ap, WsUInt8 *);
WS_GET_UINT8(buffer, *i8p);
buffer++;
buffer_len--;
break;
case WS_ENC_INT16:
case WS_ENC_UINT16:
if (buffer_len < 2)
goto too_short_buffer;
i16p = va_arg(ap, WsUInt16 *);
WS_GET_UINT16(buffer, *i16p);
buffer += 2;
buffer_len -= 2;
break;
case WS_ENC_INT32:
case WS_ENC_UINT32:
if (buffer_len < 4)
goto too_short_buffer;
i32p = va_arg(ap, WsUInt32 *);
WS_GET_UINT32(buffer, *i32p);
buffer += 4;
buffer_len -= 4;
break;
case WS_ENC_MB_UINT16:
case WS_ENC_MB_UINT32:
{
size_t len = buffer_len;
WsUInt32 i32;
if (buffer_len < 1)
goto too_short_buffer;
i32 = ws_decode_mb_uint32(buffer, &len);
if (spec == WS_ENC_MB_UINT16) {
i16p = va_arg(ap, WsUInt16 *);
*i16p = i32;
} else {
i32p = va_arg(ap, WsUInt32 *);
*i32p = i32;
}
buffer += len;
buffer_len -= len;
}
break;
case WS_ENC_DATA:
cpp = va_arg(ap, unsigned char **);
len = va_arg(ap, size_t);
if (buffer_len < len)
goto too_short_buffer;
*cpp = (unsigned char *) buffer;
buffer += len;
buffer_len -= len;
break;
default:
ws_fatal("ws_encode_buffer(): unknown type %d: probably a missing "
"WS_ENC_END",
spec);
break;
}
}
va_end(ap);
return orig_buffer_len - buffer_len;
too_short_buffer:
va_end(ap);
return 0;
}