/* encdec - encode and decode integers, times, and * internationalized strings to and from popular binary formats * Copyright (c) 2002 Michael B. Allen * * The GNU Library General Public License * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA */ #include #include #include "encdec.h" #if defined(_WIN32) #define m0xFFFFFFFFLL 0xFFFFFFFFUi64 #define m32LL 32Ui64 #define m1000LL 1000Ui64 #define m10000LL 10000Ui64 #define MILLISECONDS_BETWEEN_1970_AND_1601 11644473600000Ui64 #else #define m0xFFFFFFFFLL 0xFFFFFFFFLL #define m32LL 32LL #define m1000LL 1000LL #define m10000LL 10000LL #define MILLISECONDS_BETWEEN_1970_AND_1601 11644473600000LL #endif union convert_float { float f; uint32_t i; }; union convert_double { double d; uint64_t i; }; /* Encode integers */ size_t enc_uint16be(uint16_t s, unsigned char *dst) { dst[0] = (s >> 8) & 0xFF; dst[1] = s & 0xFF; return 2; } size_t enc_uint32be(uint32_t i, unsigned char *dst) { dst[0] = (i >> 24) & 0xFF; dst[1] = (i >> 16) & 0xFF; dst[2] = (i >> 8) & 0xFF; dst[3] = i & 0xFF; return 4; } size_t enc_uint16le(uint16_t s, unsigned char *dst) { dst[0] = s & 0xFF; dst[1] = (s >> 8) & 0xFF; return 2; } size_t enc_uint32le(uint32_t i, unsigned char *dst) { dst[0] = i & 0xFF; dst[1] = (i >> 8) & 0xFF; dst[2] = (i >> 16) & 0xFF; dst[3] = (i >> 24) & 0xFF; return 4; } /* Decode integers */ uint16_t dec_uint16be(const unsigned char *src) { return ((unsigned)src[0] << 8) | src[1]; } uint32_t dec_uint32be(const unsigned char *src) { return ((unsigned)src[0] << 24) | ((unsigned)src[1] << 16) | ((unsigned)src[2] << 8) | src[3]; } uint16_t dec_uint16le(const unsigned char *src) { return src[0] | ((unsigned)src[1] << 8); } uint32_t dec_uint32le(const unsigned char *src) { return src[0] | ((unsigned)src[1] << 8) | ((unsigned)src[2] << 16) | ((unsigned)src[3] << 24); } /* Encode and decode 64 bit integers */ size_t enc_uint64be(uint64_t i, unsigned char *dst) { enc_uint32be(i & m0xFFFFFFFFLL, dst + 4); enc_uint32be((i >> m32LL) & m0xFFFFFFFFLL, dst); return 8; } size_t enc_uint64le(uint64_t i, unsigned char *dst) { enc_uint32le(i & m0xFFFFFFFFLL, dst); enc_uint32le((i >> m32LL) & m0xFFFFFFFFLL, dst + 4); return 8; } uint64_t dec_uint64be(const unsigned char *src) { uint64_t i; i = dec_uint32be(src); i <<= m32LL; i |= dec_uint32be(src + 4); return i; } uint64_t dec_uint64le(const unsigned char *src) { uint64_t i; i = dec_uint32le(src + 4); i <<= m32LL; i |= dec_uint32le(src); return i; } /* Encode floats */ size_t enc_floatle(const float f, unsigned char *dst) { union convert_float c; c.f = f; return enc_uint32le(c.i, dst); } size_t enc_floatbe(const float f, unsigned char *dst) { union convert_float c; c.f = f; return enc_uint32be(c.i, dst); } /* Decode floating point numbers */ float dec_floatle(const unsigned char *src) { union convert_float c; c.i = dec_uint32le(src); return c.f; } float dec_floatbe(const unsigned char *src) { union convert_float c; c.i = dec_uint32be(src); return c.f; } /* Encode and decode doubles */ size_t enc_doublele(const double d, unsigned char *dst) { union convert_double c; c.d = d; return enc_uint64le(c.i, dst); } size_t enc_doublebe(const double d, unsigned char *dst) { union convert_double c; c.d = d; return enc_uint64be(c.i, dst); } double dec_doublele(const unsigned char *src) { union convert_double c; c.i = dec_uint64le(src); return c.d; } double dec_doublebe(const unsigned char *src) { union convert_double c; c.i = dec_uint64be(src); return c.d; } /* Encode times */ #define SEC_BETWEEEN_1904_AND_1970 2082844800 size_t enc_time(const time_t *timep, unsigned char *dst, int enc) { uint64_t t; if (timep == NULL || dst == NULL) { errno = EINVAL; return -1; } if (enc < 1 || enc > TIME_NUM_ENC) { errno = EINVAL; return -1; } switch(enc) { case TIME_1970_SEC_32BE: return enc_uint32be(*timep, dst); case TIME_1970_SEC_32LE: return enc_uint32le(*timep, dst); case TIME_1904_SEC_32BE: return enc_uint32be(*timep + SEC_BETWEEEN_1904_AND_1970, dst); case TIME_1904_SEC_32LE: return enc_uint32le(*timep + SEC_BETWEEEN_1904_AND_1970, dst); case TIME_1601_NANOS_64BE: t = ((*timep * m1000LL) + MILLISECONDS_BETWEEN_1970_AND_1601) * m10000LL; return enc_uint64be(t, dst); case TIME_1601_NANOS_64LE: t = ((*timep * m1000LL) + MILLISECONDS_BETWEEN_1970_AND_1601) * m10000LL; return enc_uint64le(t, dst); case TIME_1970_MILLIS_64BE: return enc_uint64be(*timep * m1000LL, dst); case TIME_1970_MILLIS_64LE: return enc_uint64le(*timep * m1000LL, dst); default: return (size_t)-1; } } /* Decode times */ time_t dec_time(const unsigned char *src, int enc) { uint64_t t; if (src == NULL) { errno = EINVAL; return -1; } if (enc < 1 || enc > TIME_NUM_ENC) { errno = EINVAL; return -1; } switch(enc) { case TIME_1970_SEC_32BE: return dec_uint32be(src); case TIME_1970_SEC_32LE: return dec_uint32le(src); case TIME_1904_SEC_32BE: return dec_uint32be(src) - SEC_BETWEEEN_1904_AND_1970; case TIME_1904_SEC_32LE: return dec_uint32le(src) - SEC_BETWEEEN_1904_AND_1970; case TIME_1601_NANOS_64BE: t = dec_uint64be(src); return (t / m10000LL - MILLISECONDS_BETWEEN_1970_AND_1601) / m1000LL; case TIME_1601_NANOS_64LE: t = dec_uint64le(src); return (t / m10000LL - MILLISECONDS_BETWEEN_1970_AND_1601) / m1000LL; case TIME_1970_MILLIS_64BE: return dec_uint64be(src) / m1000LL; case TIME_1970_MILLIS_64LE: return dec_uint64le(src) / m1000LL; default: return (time_t)-1; } }