/*******************************************************************************
*
* MODULE: ctype.c
*
********************************************************************************
*
* DESCRIPTION: ANSI C data type objects
*
********************************************************************************
*
* Copyright (c) 2002-2015 Marcus Holland-Moritz. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the same terms as Perl itself.
*
*******************************************************************************/
/*===== GLOBAL INCLUDES ======================================================*/
#include <ctype.h>
#include <assert.h>
/*===== LOCAL INCLUDES =======================================================*/
#include "byteorder.h"
/*===== DEFINES ==============================================================*/
#ifndef NULL
#define NULL ((void *) 0)
#endif
/*----------------------------------------------------------*/
/* reading/writing integers in big/little endian byte order */
/* depending on the native byte order of the system */
/*----------------------------------------------------------*/
#if ARCH_NATIVE_BYTEORDER == ARCH_BYTEORDER_BIG_ENDIAN
/*--------------------*/
/* big endian systems */
/*--------------------*/
#define GET_LE_WORD(ptr, value, sign) \
value = (sign ## _16) \
( ( (u_16) *( (const u_8 *) ((ptr)+0) ) << 0) \
| ( (u_16) *( (const u_8 *) ((ptr)+1) ) << 8) \
)
#define GET_LE_LONG(ptr, value, sign) \
value = (sign ## _32) \
( ( (u_32) *( (const u_8 *) ((ptr)+0) ) << 0) \
| ( (u_32) *( (const u_8 *) ((ptr)+1) ) << 8) \
| ( (u_32) *( (const u_8 *) ((ptr)+2) ) << 16) \
| ( (u_32) *( (const u_8 *) ((ptr)+3) ) << 24) \
)
#if ARCH_NATIVE_64_BIT_INTEGER
#define GET_LE_LONGLONG(ptr, value, sign) \
value = (sign ## _64) \
( ( (u_64) *( (const u_8 *) ((ptr)+0) ) << 0) \
| ( (u_64) *( (const u_8 *) ((ptr)+1) ) << 8) \
| ( (u_64) *( (const u_8 *) ((ptr)+2) ) << 16) \
| ( (u_64) *( (const u_8 *) ((ptr)+3) ) << 24) \
| ( (u_64) *( (const u_8 *) ((ptr)+4) ) << 32) \
| ( (u_64) *( (const u_8 *) ((ptr)+5) ) << 40) \
| ( (u_64) *( (const u_8 *) ((ptr)+6) ) << 48) \
| ( (u_64) *( (const u_8 *) ((ptr)+7) ) << 56) \
)
#endif
#define SET_LE_WORD(ptr, value) \
do { \
register u_16 v = value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 0) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 8) & 0xFF); \
} while (0)
#define SET_LE_LONG(ptr, value) \
do { \
register u_32 v = value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 0) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 8) & 0xFF); \
*((u_8 *) ((ptr)+2)) = (u_8) ((v >> 16) & 0xFF); \
*((u_8 *) ((ptr)+3)) = (u_8) ((v >> 24) & 0xFF); \
} while (0)
#if ARCH_NATIVE_64_BIT_INTEGER
#define SET_LE_LONGLONG(ptr, value) \
do { \
register u_64 v = value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 0) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 8) & 0xFF); \
*((u_8 *) ((ptr)+2)) = (u_8) ((v >> 16) & 0xFF); \
*((u_8 *) ((ptr)+3)) = (u_8) ((v >> 24) & 0xFF); \
*((u_8 *) ((ptr)+4)) = (u_8) ((v >> 32) & 0xFF); \
*((u_8 *) ((ptr)+5)) = (u_8) ((v >> 40) & 0xFF); \
*((u_8 *) ((ptr)+6)) = (u_8) ((v >> 48) & 0xFF); \
*((u_8 *) ((ptr)+7)) = (u_8) ((v >> 56) & 0xFF); \
} while (0)
#endif
#ifdef CAN_UNALIGNED_ACCESS
#define GET_BE_WORD(ptr, value, sign) \
value = (sign ## _16) ( *( (const u_16 *) (ptr) ) )
#define GET_BE_LONG(ptr, value, sign) \
value = (sign ## _32) ( *( (const u_32 *) (ptr) ) )
#if ARCH_NATIVE_64_BIT_INTEGER
#define GET_BE_LONGLONG(ptr, value, sign) \
value = (sign ## _64) ( *( (const u_64 *) (ptr) ) )
#endif
#define SET_BE_WORD(ptr, value) \
*( (u_16 *) (ptr) ) = (u_16) value
#define SET_BE_LONG(ptr, value) \
*( (u_32 *) (ptr) ) = (u_32) value
#if ARCH_NATIVE_64_BIT_INTEGER
#define SET_BE_LONGLONG(ptr, value) \
*( (u_64 *) (ptr) ) = (u_64) value
#endif
#else
#define GET_BE_WORD(ptr, value, sign) \
do { \
if (((unsigned long) (ptr)) % 2) \
value = (sign ## _16) \
( ( (u_16) *( (const u_8 *) ((ptr)+0) ) << 8) \
| ( (u_16) *( (const u_8 *) ((ptr)+1) ) << 0) \
); \
else \
value = (sign ## _16) ( *( (const u_16 *) (ptr) ) ); \
} while (0)
#define GET_BE_LONG(ptr, value, sign) \
do { \
switch (((unsigned long) (ptr)) % 4) \
{ \
case 0: \
value = (sign ## _32) ( *( (const u_32 *) (ptr) ) ); \
break; \
\
case 2: \
value = (sign ## _32) \
( ( (u_32) *( (const u_16 *) ((ptr)+0) ) << 16) \
| ( (u_32) *( (const u_16 *) ((ptr)+2) ) << 0) \
); \
break; \
\
default: \
value = (sign ## _32) \
( ( (u_32) *( (const u_8 *) ((ptr)+0) ) << 24) \
| ( (u_32) *( (const u_16 *) ((ptr)+1) ) << 8) \
| ( (u_32) *( (const u_8 *) ((ptr)+3) ) << 0) \
); \
break; \
} \
} while (0)
#if ARCH_NATIVE_64_BIT_INTEGER
#define GET_BE_LONGLONG(ptr, value, sign) \
do { \
value = (sign ## _64) \
( ( (u_64) *( (const u_8 *) ((ptr)+0) ) << 56) \
| ( (u_64) *( (const u_8 *) ((ptr)+1) ) << 48) \
| ( (u_64) *( (const u_8 *) ((ptr)+2) ) << 40) \
| ( (u_64) *( (const u_8 *) ((ptr)+3) ) << 32) \
| ( (u_64) *( (const u_8 *) ((ptr)+4) ) << 24) \
| ( (u_64) *( (const u_8 *) ((ptr)+5) ) << 16) \
| ( (u_64) *( (const u_8 *) ((ptr)+6) ) << 8) \
| ( (u_64) *( (const u_8 *) ((ptr)+7) ) << 0) \
); \
} while (0)
#endif
#define SET_BE_WORD(ptr, value) \
do { \
if (((unsigned long) (ptr)) % 2) \
{ \
register u_16 v = (u_16) value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 8) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 0) & 0xFF); \
} \
else \
*( (u_16 *) (ptr) ) = (u_16) value; \
} while (0)
#define SET_BE_LONG(ptr, value) \
do { \
switch (((unsigned long) (ptr)) % 4) \
{ \
case 0: \
*( (u_32 *) (ptr) ) = (u_32) value; \
break; \
\
case 2: \
{ \
register u_32 v = (u_32) value; \
*((u_16 *) ((ptr)+0)) = (u_16) ((v >> 16) & 0xFFFF); \
*((u_16 *) ((ptr)+2)) = (u_16) ((v >> 0) & 0xFFFF); \
} \
break; \
\
default: \
{ \
register u_32 v = (u_32) value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 24) & 0xFF ); \
*((u_16 *) ((ptr)+1)) = (u_16) ((v >> 8) & 0xFFFF); \
*((u_8 *) ((ptr)+3)) = (u_8) ((v >> 0) & 0xFF ); \
} \
break; \
} \
} while (0)
#if ARCH_NATIVE_64_BIT_INTEGER
#define SET_BE_LONGLONG(ptr, value) \
do { \
register u_64 v = value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 56) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 48) & 0xFF); \
*((u_8 *) ((ptr)+2)) = (u_8) ((v >> 40) & 0xFF); \
*((u_8 *) ((ptr)+3)) = (u_8) ((v >> 32) & 0xFF); \
*((u_8 *) ((ptr)+4)) = (u_8) ((v >> 24) & 0xFF); \
*((u_8 *) ((ptr)+5)) = (u_8) ((v >> 16) & 0xFF); \
*((u_8 *) ((ptr)+6)) = (u_8) ((v >> 8) & 0xFF); \
*((u_8 *) ((ptr)+7)) = (u_8) ((v >> 0) & 0xFF); \
} while (0)
#endif
#endif
#elif ARCH_NATIVE_BYTEORDER == ARCH_BYTEORDER_LITTLE_ENDIAN
/*-----------------------*/
/* little endian systems */
/*-----------------------*/
#define GET_BE_WORD(ptr, value, sign) \
value = (sign ## _16) \
( ( (u_16) *( (const u_8 *) ((ptr)+0) ) << 8) \
| ( (u_16) *( (const u_8 *) ((ptr)+1) ) << 0) \
)
#define GET_BE_LONG(ptr, value, sign) \
value = (sign ## _32) \
( ( (u_32) *( (const u_8 *) ((ptr)+0) ) << 24) \
| ( (u_32) *( (const u_8 *) ((ptr)+1) ) << 16) \
| ( (u_32) *( (const u_8 *) ((ptr)+2) ) << 8) \
| ( (u_32) *( (const u_8 *) ((ptr)+3) ) << 0) \
)
#if ARCH_NATIVE_64_BIT_INTEGER
#define GET_BE_LONGLONG(ptr, value, sign) \
value = (sign ## _64) \
( ( (u_64) *( (const u_8 *) ((ptr)+0) ) << 56) \
| ( (u_64) *( (const u_8 *) ((ptr)+1) ) << 48) \
| ( (u_64) *( (const u_8 *) ((ptr)+2) ) << 40) \
| ( (u_64) *( (const u_8 *) ((ptr)+3) ) << 32) \
| ( (u_64) *( (const u_8 *) ((ptr)+4) ) << 24) \
| ( (u_64) *( (const u_8 *) ((ptr)+5) ) << 16) \
| ( (u_64) *( (const u_8 *) ((ptr)+6) ) << 8) \
| ( (u_64) *( (const u_8 *) ((ptr)+7) ) << 0) \
)
#endif
#define SET_BE_WORD(ptr, value) \
do { \
register u_16 v = (u_16) value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 8) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 0) & 0xFF); \
} while (0)
#define SET_BE_LONG(ptr, value) \
do { \
register u_32 v = (u_32) value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 24) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 16) & 0xFF); \
*((u_8 *) ((ptr)+2)) = (u_8) ((v >> 8) & 0xFF); \
*((u_8 *) ((ptr)+3)) = (u_8) ((v >> 0) & 0xFF); \
} while (0)
#if ARCH_NATIVE_64_BIT_INTEGER
#define SET_BE_LONGLONG(ptr, value) \
do { \
register u_64 v = value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 56) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 48) & 0xFF); \
*((u_8 *) ((ptr)+2)) = (u_8) ((v >> 40) & 0xFF); \
*((u_8 *) ((ptr)+3)) = (u_8) ((v >> 32) & 0xFF); \
*((u_8 *) ((ptr)+4)) = (u_8) ((v >> 24) & 0xFF); \
*((u_8 *) ((ptr)+5)) = (u_8) ((v >> 16) & 0xFF); \
*((u_8 *) ((ptr)+6)) = (u_8) ((v >> 8) & 0xFF); \
*((u_8 *) ((ptr)+7)) = (u_8) ((v >> 0) & 0xFF); \
} while (0)
#endif
#ifdef CAN_UNALIGNED_ACCESS
#define GET_LE_WORD(ptr, value, sign) \
value = (sign ## _16) ( *( (const u_16 *) (ptr) ) )
#define GET_LE_LONG(ptr, value, sign) \
value = (sign ## _32) ( *( (const u_32 *) (ptr) ) )
#if ARCH_NATIVE_64_BIT_INTEGER
#define GET_LE_LONGLONG(ptr, value, sign) \
value = (sign ## _64) ( *( (const u_64 *) (ptr) ) )
#endif
#define SET_LE_WORD(ptr, value) \
*( (u_16 *) (ptr) ) = (u_16) value
#define SET_LE_LONG(ptr, value) \
*( (u_32 *) (ptr) ) = (u_32) value
#if ARCH_NATIVE_64_BIT_INTEGER
#define SET_LE_LONGLONG(ptr, value) \
*( (u_64 *) (ptr) ) = (u_64) value
#endif
#else
#define GET_LE_WORD(ptr, value, sign) \
do { \
if (((unsigned long) (ptr)) % 2) \
value = (sign ## _16) \
( ( (u_16) *( (const u_8 *) ((ptr)+0) ) << 0) \
| ( (u_16) *( (const u_8 *) ((ptr)+1) ) << 8) \
); \
else \
value = (sign ## _16) ( *( (const u_16 *) (ptr) ) ); \
} while (0)
#define GET_LE_LONG(ptr, value, sign) \
do { \
switch (((unsigned long) (ptr)) % 4) \
{ \
case 0: \
value = (sign ## _32) ( *( (const u_32 *) (ptr) ) ); \
break; \
\
case 2: \
value = (sign ## _32) \
( ( (u_32) *( (const u_16 *) ((ptr)+0) ) << 0) \
| ( (u_32) *( (const u_16 *) ((ptr)+2) ) << 16) \
); \
break; \
\
default: \
value = (sign ## _32) \
( ( (u_32) *( (const u_8 *) ((ptr)+0) ) << 0) \
| ( (u_32) *( (const u_16 *) ((ptr)+1) ) << 8) \
| ( (u_32) *( (const u_8 *) ((ptr)+3) ) << 24) \
); \
break; \
} \
} while (0)
#if ARCH_NATIVE_64_BIT_INTEGER
#define GET_LE_LONGLONG(ptr, value, sign) \
do { \
value = (sign ## _64) \
( ( (u_64) *( (const u_8 *) ((ptr)+0) ) << 0) \
| ( (u_64) *( (const u_8 *) ((ptr)+1) ) << 8) \
| ( (u_64) *( (const u_8 *) ((ptr)+2) ) << 16) \
| ( (u_64) *( (const u_8 *) ((ptr)+3) ) << 24) \
| ( (u_64) *( (const u_8 *) ((ptr)+4) ) << 32) \
| ( (u_64) *( (const u_8 *) ((ptr)+5) ) << 40) \
| ( (u_64) *( (const u_8 *) ((ptr)+6) ) << 48) \
| ( (u_64) *( (const u_8 *) ((ptr)+7) ) << 56) \
); \
} while (0)
#endif
#define SET_LE_WORD(ptr, value) \
do { \
if (((unsigned long) (ptr)) % 2) \
{ \
register u_16 v = (u_16) value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 0) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 8) & 0xFF); \
} \
else \
*( (u_16 *) (ptr) ) = (u_16) value; \
} while (0)
#define SET_LE_LONG(ptr, value) \
do { \
switch (((unsigned long) (ptr)) % 4) \
{ \
case 0: \
*( (u_32 *) (ptr) ) = (u_32) value; \
break; \
\
case 2: \
{ \
register u_32 v = (u_32) value; \
*((u_16 *) ((ptr)+0)) = (u_16) ((v >> 0) & 0xFFFF); \
*((u_16 *) ((ptr)+2)) = (u_16) ((v >> 16) & 0xFFFF); \
} \
break; \
\
default: \
{ \
register u_32 v = (u_32) value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 0) & 0xFF ); \
*((u_16 *) ((ptr)+1)) = (u_16) ((v >> 8) & 0xFFFF); \
*((u_8 *) ((ptr)+3)) = (u_8) ((v >> 24) & 0xFF ); \
} \
break; \
} \
} while (0)
#if ARCH_NATIVE_64_BIT_INTEGER
#define SET_LE_LONGLONG(ptr, value) \
do { \
register u_64 v = value; \
*((u_8 *) ((ptr)+0)) = (u_8) ((v >> 0) & 0xFF); \
*((u_8 *) ((ptr)+1)) = (u_8) ((v >> 8) & 0xFF); \
*((u_8 *) ((ptr)+2)) = (u_8) ((v >> 16) & 0xFF); \
*((u_8 *) ((ptr)+3)) = (u_8) ((v >> 24) & 0xFF); \
*((u_8 *) ((ptr)+4)) = (u_8) ((v >> 32) & 0xFF); \
*((u_8 *) ((ptr)+5)) = (u_8) ((v >> 40) & 0xFF); \
*((u_8 *) ((ptr)+6)) = (u_8) ((v >> 48) & 0xFF); \
*((u_8 *) ((ptr)+7)) = (u_8) ((v >> 56) & 0xFF); \
} while (0)
#endif
#endif
#else /* ARCH_NATIVE_BYTEORDER */
#error "unknown native byte order"
#endif /* ARCH_NATIVE_BYTEORDER */
#define GET_BE_BYTE(ptr, value, sign) \
value = *((const sign ## _8 *) (ptr))
#define GET_LE_BYTE(ptr, value, sign) \
value = *((const sign ## _8 *) (ptr))
#define SET_BE_BYTE(ptr, value) \
*((u_8 *) (ptr)) = (u_8) value
#define SET_LE_BYTE(ptr, value) \
*((u_8 *) (ptr)) = (u_8) value
#define ALL_64_BITS (~((u_64) 0))
#define ALL_32_BITS (~((u_32) 0))
/*===== TYPEDEFS =============================================================*/
enum shift_direction {
SHIFT_LEFT,
SHIFT_RIGHT
};
/*===== STATIC FUNCTION PROTOTYPES ===========================================*/
/*===== EXTERNAL VARIABLES ===================================================*/
/*===== GLOBAL VARIABLES =====================================================*/
/*===== STATIC VARIABLES =====================================================*/
/*===== STATIC FUNCTIONS =====================================================*/
static int integer2string(IntValue *pInt);
static void string2integer(IntValue *pInt);
/*===== FUNCTIONS ============================================================*/
/*******************************************************************************
*
* ROUTINE: integer2string
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2002
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION: Turn an integer into a string.
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
static int integer2string(IntValue *pInt)
{
#if ARCH_NATIVE_64_BIT_INTEGER
register u_64 val;
#else
register u_32 hval, lval, tval, umod, lmod;
#endif
int stack[20], len, sp;
char *pStr = pInt->string;
if (pStr == NULL)
return 0;
len = sp = 0;
#if ARCH_NATIVE_64_BIT_INTEGER
if (pInt->sign && pInt->value.s < 0)
{
val = -pInt->value.s;
*pStr++ = '-';
len++;
}
else
val = pInt->value.u;
while (val > 0)
stack[sp++] = val % 10, val /= 10;
#else
hval = pInt->value.u.h;
lval = pInt->value.u.l;
if (pInt->sign && pInt->value.s.h < 0)
{
*pStr++ = '-';
len++;
if (lval-- == 0)
hval--;
hval = ~hval;
lval = ~lval;
}
while (hval > 0)
{
static const u_32 CDIV[10] = {
0x00000000, 0x19999999, 0x33333333, 0x4CCCCCCC, 0x66666666,
0x80000000, 0x99999999, 0xB3333333, 0xCCCCCCCC, 0xE6666666
};
static const u_32 CMOD[10] =
{ 0U, 6U, 2U, 8U, 4U, 0U, 6U, 2U, 8U, 4U };
umod = hval % 10; hval /= 10;
lmod = lval % 10; lval /= 10;
lmod += CMOD[umod];
tval = CDIV[umod];
if (lmod >= 10)
lmod -= 10, tval++;
lval += tval;
if (lval < tval)
hval++;
stack[sp++] = lmod;
}
while (lval > 0)
stack[sp++] = lval % 10, lval /= 10;
#endif
len += sp;
if (sp == 0)
*pStr++ = '0';
else
while(sp-- > 0)
*pStr++ = (char) ('0' + stack[sp]);
*pStr = '\0';
return len;
}
/*******************************************************************************
*
* ROUTINE: string2integer
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2002
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION: Turn a dec/hex/oct string into an integer.
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
static void string2integer(IntValue *pInt)
{
register int val;
register const char *pStr = pInt->string;
#if ARCH_NATIVE_64_BIT_INTEGER
register u_64 iv = 0;
#else
register u_32 hval = 0, lval = 0;
#endif
pInt->sign = 0;
while (isspace(*pStr)) /* ignore leading whitespace */
pStr++;
switch (*pStr)
{
default : break;
case '-': pInt->sign = 1;
case '+': while(isspace(*++pStr));
}
if (*pStr == '0') /* seems to be hex or octal */
{
pStr++;
if (*pStr == 'x') /* must be hex */
{
while (isxdigit(val = *++pStr))
{
if (isdigit(val))
val -= (int) '0';
else if (isupper(val))
val -= (int) 'A' - 10;
else
val -= (int) 'a' - 10;
#if ARCH_NATIVE_64_BIT_INTEGER
iv = (iv << 4) | (val & 0xF);
#else
hval = (hval << 4) | (lval >> 28);
lval = (lval << 4) | (val & 0xF);
#endif
}
}
else if (*pStr == 'b') /* must be binary */
{
pStr++;
while (*pStr == '0' || *pStr == '1')
{
val = (int) (*pStr - '0');
#if ARCH_NATIVE_64_BIT_INTEGER
iv = (iv << 1) | (val & 0x1);
#else
hval = (hval << 1) | (lval >> 31);
lval = (lval << 1) | (val & 0x1);
#endif
pStr++;
}
}
else /* must be octal */
{
while (isdigit(*pStr) && *pStr != '8' && *pStr != '9')
{
val = (int) (*pStr - '0');
#if ARCH_NATIVE_64_BIT_INTEGER
iv = (iv << 3) | (val & 0x7);
#else
hval = (hval << 3) | (lval >> 29);
lval = (lval << 3) | (val & 0x7);
#endif
pStr++;
}
}
}
else /* must be decimal */
{
#if ARCH_NATIVE_64_BIT_INTEGER
while (isdigit(val = *pStr++))
iv = 10*iv + (val - (int) '0');
#else
register u_32 temp;
do
{
if (!isdigit(val = *pStr++))
goto end_of_string;
lval = 10*lval + (val - (int) '0');
}
while (lval < 429496729);
while (isdigit(val = *pStr++))
{
hval = ((hval << 3) | (lval >> 29))
+ ((hval << 1) | (lval >> 31));
lval <<= 1;
temp = lval + (lval << 2);
if (temp < lval)
hval++;
lval = temp + (int) (val - '0');
if (lval < temp)
hval++;
}
#endif
}
#if ARCH_NATIVE_64_BIT_INTEGER
if (pInt->sign)
pInt->value.s = -iv;
else
pInt->value.u = iv;
#else
end_of_string:
if (pInt->sign && (hval || lval))
{
if (lval-- == 0)
hval--;
pInt->value.u.h = ~hval;
pInt->value.u.l = ~lval;
}
else
{
pInt->value.u.h = hval;
pInt->value.u.l = lval;
}
#endif
}
/*******************************************************************************
*
* ROUTINE: shift_integer
*
* WRITTEN BY: Marcus Holland-Moritz ON: Apr 2005
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION: Bit-shift an u_64 value left or right.
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
static void shift_integer(u_64 *pval, unsigned bits, enum shift_direction dir)
{
assert(bits <= 64);
#if ARCH_NATIVE_64_BIT_INTEGER
switch (dir)
{
case SHIFT_LEFT:
*pval <<= bits;
break;
case SHIFT_RIGHT:
*pval >>= bits;
break;
}
#else
switch (dir)
{
case SHIFT_LEFT:
if (bits >= 32)
{
pval->h = pval->l << (bits - 32);
pval->l = 0;
}
else
{
pval->h = (pval->h << bits) | (pval->l >> (32 - bits));
pval->l <<= bits;
}
break;
case SHIFT_RIGHT:
if (bits >= 32)
{
pval->l = pval->h >> (bits - 32);
pval->h = 0;
}
else
{
pval->l = (pval->l >> bits) | (pval->h << (32 - bits));
pval->h >>= bits;
}
break;
}
#endif
}
/*******************************************************************************
*
* ROUTINE: mask_integer
*
* WRITTEN BY: Marcus Holland-Moritz ON: Apr 2005
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION: Bit-mask an u_64 value.
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
static void mask_integer(u_64 *pval, unsigned bits, unsigned shift, int extend_msb)
{
u_64 mask;
const unsigned msb = bits + shift - 1;
assert(bits <= 64);
assert(shift <= 64);
assert((bits + shift) <= 64);
#if ARCH_NATIVE_64_BIT_INTEGER
mask = (ALL_64_BITS >> (64 - bits)) << shift;
*pval &= mask;
if (extend_msb && bits > 0)
if (*pval & (((u_64)1) << msb))
*pval |= ALL_64_BITS << msb;
#else
if (bits > 32)
{
mask.h = (ALL_32_BITS >> (64 - bits));
mask.l = ALL_32_BITS;
}
else
{
mask.h = 0;
mask.l = (ALL_32_BITS >> (32 - bits));
}
if (shift > 0)
shift_integer(&mask, shift, SHIFT_LEFT);
pval->h &= mask.h;
pval->l &= mask.l;
if (extend_msb && bits > 0)
{
if (msb >= 32)
{
if (pval->h & (((u_32)1) << (msb - 32)))
pval->h |= ALL_32_BITS << (msb - 32);
}
else
{
if (pval->l & (((u_32)1) << msb))
{
pval->h = ALL_32_BITS;
pval->l |= ALL_32_BITS << msb;
}
}
}
#endif
}
/*******************************************************************************
*
* ROUTINE: merge_integer
*
* WRITTEN BY: Marcus Holland-Moritz ON: Apr 2005
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION: Merge an u_64 value into another one.
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
static void merge_integer(u_64 *dest, const u_64 *src, unsigned bits, unsigned shift)
{
u_64 mask;
assert(bits <= 64);
assert(shift <= 64);
assert((bits + shift) <= 64);
#if ARCH_NATIVE_64_BIT_INTEGER
mask = (ALL_64_BITS >> (64 - bits)) << shift;
*dest = (*dest & (~mask)) | (*src & mask);
#else
if (bits > 32)
{
mask.h = (ALL_32_BITS >> (64 - bits));
mask.l = ALL_32_BITS;
}
else
{
mask.h = 0;
mask.l = (ALL_32_BITS >> (32 - bits));
}
if (shift > 0)
shift_integer(&mask, shift, SHIFT_LEFT);
dest->h = (dest->h & (~mask.h)) | (src->h & mask.h);
dest->l = (dest->l & (~mask.l)) | (src->l & mask.l);
#endif
}
/*******************************************************************************
*
* ROUTINE: string_is_integer
*
* WRITTEN BY: Marcus Holland-Moritz ON: Mar 2004
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION: Decide if a string contains a dec/hex/oct integer.
*
* ARGUMENTS:
*
* RETURNS: Zero if the string doesn't hold an interpretable number.
* The base (i.e. 2, 8, 10 or 16) if the string is a number.
*
*******************************************************************************/
int string_is_integer(const char *pStr)
{
int rval;
/* ignore leading whitespace */
while (isspace(*pStr))
pStr++;
switch (*pStr)
{
default : break;
case '-':
case '+': while (isspace(*++pStr));
}
if (*pStr == '0') /* seems to be hex or octal */
{
pStr++;
if (*pStr == 'x') /* must be hex */
{
pStr++;
while (isxdigit(*pStr))
pStr++;
rval = 16;
}
else if (*pStr == 'b') /* must be binary */
{
pStr++;
while (*pStr == '0' || *pStr == '1')
pStr++;
rval = 2;
}
else /* must be octal */
{
while (isdigit(*pStr) && *pStr != '8' && *pStr != '9')
pStr++;
rval = 8;
}
}
else /* must be decimal */
{
while (isdigit(*pStr))
pStr++;
rval = 10;
}
/* ignore trailing whitespace */
while (isspace(*pStr))
pStr++;
return *pStr ? 0 : rval;
}
/*******************************************************************************
*
* ROUTINE: fetch_integer
*
* WRITTEN BY: Marcus Holland-Moritz ON: Oct 2002
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
#if ARCH_NATIVE_64_BIT_INTEGER
#define FETCH(bo, what) \
do { \
if (sign) \
GET_ ## bo ## _ ## what (ptr, iv.value.s, i); \
else \
GET_ ## bo ## _ ## what (ptr, iv.value.u, u); \
} while (0)
#else
#define FETCH(bo, what) \
do { \
if(sign) \
{ \
GET_ ## bo ## _ ## what (ptr, iv.value.s.l, i); \
iv.value.s.h = ((i_32) iv.value.s.l) < 0 ? -1 : 0; \
} \
else \
{ \
GET_ ## bo ## _ ## what (ptr, iv.value.u.l, u); \
iv.value.u.h = 0; \
} \
} while (0)
#endif
void fetch_integer(unsigned size, unsigned sign, unsigned bits, unsigned shift,
CByteOrder bo, const void *src, IntValue *pIV)
{
register const u_8 *ptr = (const u_8 *) src;
IntValue iv = *pIV;
switch (size)
{
case 1:
FETCH(BE, BYTE);
break;
case 2:
if (bo == CBO_BIG_ENDIAN)
FETCH(BE, WORD);
else
FETCH(LE, WORD);
break;
case 4:
if (bo == CBO_BIG_ENDIAN)
FETCH(BE, LONG);
else
FETCH(LE, LONG);
break;
case 8:
#if ARCH_NATIVE_64_BIT_INTEGER
if (bo == CBO_BIG_ENDIAN)
FETCH(BE, LONGLONG);
else
FETCH(LE, LONGLONG);
#else
if (bo == CBO_BIG_ENDIAN)
{
GET_BE_LONG(ptr, iv.value.u.h, u);
GET_BE_LONG(ptr+4, iv.value.u.l, u);
}
else
{
GET_LE_LONG(ptr, iv.value.u.l, u);
GET_LE_LONG(ptr+4, iv.value.u.h, u);
}
#endif
break;
default:
break;
}
iv.sign = sign;
if (bits > 0)
{
if (shift > 0)
shift_integer(&iv.value.u, shift, SHIFT_RIGHT);
mask_integer(&iv.value.u, bits, 0, sign);
}
if (iv.string)
(void) integer2string(&iv);
*pIV = iv;
}
#undef FETCH
/*******************************************************************************
*
* ROUTINE: store_integer
*
* WRITTEN BY: Marcus Holland-Moritz ON: Oct 2002
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
#if ARCH_NATIVE_64_BIT_INTEGER
#define STORE(bo, what) \
do { \
SET_ ## bo ## _ ## what (ptr, iv.value.u); \
} while (0)
#else
#define STORE(bo, what) \
do { \
SET_ ## bo ## _ ## what (ptr, iv.value.u.l); \
} while (0)
#endif
void store_integer(unsigned size, unsigned bits, unsigned shift,
CByteOrder bo, void *dest, const IntValue *pIV)
{
register u_8 *ptr = (u_8 *) dest;
IntValue iv = *pIV;
if (iv.string)
string2integer(&iv);
if (bits > 0)
{
IntValue orig;
orig.string = NULL;
fetch_integer(size, 0, 0, 0, bo, dest, &orig);
if (shift > 0)
shift_integer(&iv.value.u, shift, SHIFT_LEFT);
merge_integer(&orig.value.u, &iv.value.u, bits, shift);
iv = orig;
}
switch (size)
{
case 1:
STORE(BE, BYTE);
break;
case 2:
if (bo == CBO_BIG_ENDIAN)
STORE(BE, WORD);
else
STORE(LE, WORD);
break;
case 4:
if (bo == CBO_BIG_ENDIAN)
STORE(BE, LONG);
else
STORE(LE, LONG);
break;
case 8:
#if ARCH_NATIVE_64_BIT_INTEGER
if (bo == CBO_BIG_ENDIAN)
STORE(BE, LONGLONG);
else
STORE(LE, LONGLONG);
#else
if (bo == CBO_BIG_ENDIAN)
{
SET_BE_LONG(ptr, iv.value.u.h);
SET_BE_LONG(ptr+4, iv.value.u.l);
}
else
{
SET_LE_LONG(ptr, iv.value.u.l);
SET_LE_LONG(ptr+4, iv.value.u.h);
}
#endif
break;
default:
break;
}
}
#undef STORE