core: Add generic LE/BE load/store uint type convertors and use them in msgb

Submitted-by: Max <max.suraev@fairwaves.co>
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
Max 2014-06-04 19:07:41 +02:00 committed by Sylvain Munaut
parent 12ba778afd
commit 5377701746
7 changed files with 377 additions and 12 deletions

2
.gitignore vendored
View File

@ -89,7 +89,7 @@ doc/html.tar
src/crc*gen.c
include/osmocom/core/crc*gen.h
include/osmocom/core/bit*gen.h
# vi files
*.sw?

View File

@ -2,6 +2,9 @@ nobase_include_HEADERS = \
osmocom/codec/codec.h \
osmocom/core/application.h \
osmocom/core/backtrace.h \
osmocom/core/bit16gen.h \
osmocom/core/bit32gen.h \
osmocom/core/bit64gen.h \
osmocom/core/bits.h \
osmocom/core/bitvec.h \
osmocom/core/conv.h \
@ -107,6 +110,10 @@ endif
noinst_HEADERS = osmocom/core/timer_compat.h
osmocom/core/bit%gen.h: osmocom/core/bitXXgen.h.tpl
$(AM_V_GEN)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)sed -e's/XX/$*/g' $< > $@
osmocom/core/crc%gen.h: osmocom/core/crcXXgen.h.tpl
$(AM_V_GEN)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)sed -e's/XX/$*/g' $< > $@

View File

@ -0,0 +1,103 @@
/*
* bitXXgen.h
*
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \brief load unaligned n-byte integer (little-endian encoding) into uintXX_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns XX bit unsigned integer
*/
static inline uintXX_t osmo_loadXXle_ext(const void *p, uint8_t n)
{
uint8_t i;
uintXX_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uintXX_t)q[i] << (8 * i)), i++);
return r;
}
/*! \brief load unaligned n-byte integer (big-endian encoding) into uintXX_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns XX bit unsigned integer
*/
static inline uintXX_t osmo_loadXXbe_ext(const void *p, uint8_t n)
{
uint8_t i;
uintXX_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uintXX_t)q[i] << (XX - 8* (1 + i))), i++);
return r;
}
/*! \brief store unaligned n-byte integer (little-endian encoding) into uintXX_t
* \param[in] x unsigned XX bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_storeXXle_ext(uintXX_t x, uint8_t *p, uint8_t n)
{
uint8_t i;
for(i = 0; i < n; p[i] = (x >> i * 8) & 0xFF, i++);
}
/*! \brief store unaligned n-byte integer (big-endian encoding) into uintXX_t
* \param[in] x unsigned XX bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_storeXXbe_ext(uintXX_t x, uint8_t *p, uint8_t n)
{
uint8_t i;
for(i = 0; i < n; p[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
}
/* Convenience function for most-used cases */
/*! \brief load unaligned XX-bit integer (little-endian encoding) */
static inline uintXX_t osmo_loadXXle(const void *p)
{
return osmo_loadXXle_ext(p, XX / 8);
}
/*! \brief load unaligned XX-bit integer (big-endian encoding) */
static inline uintXX_t osmo_loadXXbe(const void *p)
{
return osmo_loadXXbe_ext(p, XX / 8);
}
/*! \brief store unaligned XX-bit integer (little-endian encoding) */
static inline void osmo_storeXXle(uintXX_t x, void *p)
{
return osmo_storeXXle_ext(x, p, XX / 8);
}
/*! \brief store unaligned XX-bit integer (big-endian encoding) */
static inline void osmo_storeXXbe(uintXX_t x, void *p)
{
return osmo_storeXXbe_ext(x, p, XX / 8);
}

View File

@ -1,6 +1,11 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <osmocom/core/bit16gen.h>
#include <osmocom/core/bit32gen.h>
#include <osmocom/core/bit64gen.h>
/*! \defgroup bits soft, unpacked and packed bits
* @{

View File

@ -22,6 +22,7 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/bits.h>
/*! \defgroup msgb Message buffers
* @{
@ -204,8 +205,7 @@ static inline void msgb_put_u8(struct msgb *msgb, uint8_t word)
static inline void msgb_put_u16(struct msgb *msgb, uint16_t word)
{
uint8_t *space = msgb_put(msgb, 2);
space[0] = word >> 8 & 0xFF;
space[1] = word & 0xFF;
osmo_store16be(word, space);
}
/*! \brief append a uint32 value to the end of the message
@ -215,10 +215,7 @@ static inline void msgb_put_u16(struct msgb *msgb, uint16_t word)
static inline void msgb_put_u32(struct msgb *msgb, uint32_t word)
{
uint8_t *space = msgb_put(msgb, 4);
space[0] = word >> 24 & 0xFF;
space[1] = word >> 16 & 0xFF;
space[2] = word >> 8 & 0xFF;
space[3] = word & 0xFF;
osmo_store32be(word, space);
}
/*! \brief remove data from end of message
@ -235,6 +232,7 @@ static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len)
msgb->len -= len;
return tmp;
}
/*! \brief remove uint8 from end of message
* \param[in] msgb message buffer
* \returns 8bit value taken from end of msgb
@ -244,6 +242,7 @@ static inline uint8_t msgb_get_u8(struct msgb *msgb)
uint8_t *space = msgb_get(msgb, 1);
return space[0];
}
/*! \brief remove uint16 from end of message
* \param[in] msgb message buffer
* \returns 16bit value taken from end of msgb
@ -251,8 +250,9 @@ static inline uint8_t msgb_get_u8(struct msgb *msgb)
static inline uint16_t msgb_get_u16(struct msgb *msgb)
{
uint8_t *space = msgb_get(msgb, 2);
return space[0] << 8 | space[1];
return osmo_load16be(space);
}
/*! \brief remove uint32 from end of message
* \param[in] msgb message buffer
* \returns 32bit value taken from end of msgb
@ -260,7 +260,7 @@ static inline uint16_t msgb_get_u16(struct msgb *msgb)
static inline uint32_t msgb_get_u32(struct msgb *msgb)
{
uint8_t *space = msgb_get(msgb, 4);
return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3];
return osmo_load32be(space);
}
/*! \brief prepend (push) some data to start of message
@ -284,6 +284,7 @@ static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
msgb->len += len;
return msgb->data;
}
/*! \brief remove (pull) a header from the front of the message buffer
* \param[in] msgb message buffer
* \param[in] len number of octets to be pulled
@ -323,6 +324,7 @@ static inline uint8_t msgb_pull_u8(struct msgb *msgb)
uint8_t *space = msgb_pull(msgb, 1) - 1;
return space[0];
}
/*! \brief remove uint16 from front of message
* \param[in] msgb message buffer
* \returns 16bit value taken from end of msgb
@ -330,8 +332,9 @@ static inline uint8_t msgb_pull_u8(struct msgb *msgb)
static inline uint16_t msgb_pull_u16(struct msgb *msgb)
{
uint8_t *space = msgb_pull(msgb, 2) - 2;
return space[0] << 8 | space[1];
return osmo_load16be(space);
}
/*! \brief remove uint32 from front of message
* \param[in] msgb message buffer
* \returns 32bit value taken from end of msgb
@ -339,7 +342,7 @@ static inline uint16_t msgb_pull_u16(struct msgb *msgb)
static inline uint32_t msgb_pull_u32(struct msgb *msgb)
{
uint8_t *space = msgb_pull(msgb, 4) - 4;
return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3];
return osmo_load32be(space);
}
/*! \brief Increase headroom of empty msgb, reducing the tailroom

View File

@ -1,20 +1,192 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/bits.h>
static const uint8_t input[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
static const uint8_t exp_out[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
static char s[18];
enum END {LE, BE};
const char * end2str(enum END e) {
if (e == LE) return "LE";
return "BE";
}
/* convenience wrappers */
inline uint64_t load64(enum END e, const uint8_t *buf, unsigned nbytes) {
return (e == BE) ? osmo_load64be_ext(buf, nbytes) : osmo_load64le_ext(buf, nbytes);
}
inline uint32_t load32(enum END e, const uint8_t *buf, unsigned nbytes) {
return (e == BE) ? osmo_load32be_ext(buf, nbytes) : osmo_load32le_ext(buf, nbytes);
}
inline uint16_t load16(enum END e, const uint8_t *buf) {
return (e == BE) ? osmo_load16be(buf) : osmo_load16le(buf);
}
inline void store64(enum END e, uint64_t t, uint8_t *buf, unsigned nbytes) {
(e == BE) ? osmo_store64be_ext(t, buf, nbytes) : osmo_store64le_ext(t, buf, nbytes);
}
inline void store32(enum END e, uint64_t t, uint8_t *buf, unsigned nbytes) {
(e == BE) ? osmo_store32be_ext(t, buf, nbytes) : osmo_store32le_ext(t, buf, nbytes);
}
inline void store16(enum END e, uint64_t t, uint8_t *buf) {
(e == BE) ? osmo_store16be(t, buf) : osmo_store16le(t, buf);
}
/* helper functions */
inline bool printcheck(bool chk, unsigned nbytes, enum END e, bool b)
{
if (!chk) {
printf("%u %s FAILED", nbytes * 8, end2str(e));
return true;
}
printf("%u %s OK", nbytes * 8, end2str(e));
return b;
}
inline bool dumpcheck(const char *dump, const char *s, unsigned nbytes, bool chk, enum END e, bool b)
{
bool x = printcheck(chk, nbytes, e, b);
if (!dump) return x;
int m = memcmp(s, dump, nbytes);
if (0 == m) {
printf(", storage OK");
return x;
}
printf(", [%d]", m);
return true;
}
/* printcheckXX(): load/store 'test' and check against 'expected' value, compare to 'dump' buffer if given and print if necessary */
inline void printcheck64(enum END e, unsigned nbytes, uint64_t test, uint64_t expected, const char *dump, bool print)
{
uint8_t buf[nbytes];
store64(e, test, buf, nbytes);
char *s = osmo_hexdump_nospc(buf, nbytes);
uint64_t result = load64(e, buf, nbytes);
print = dumpcheck(dump, s, nbytes, result == expected, e, print);
if (print)
printf(": buffer %s known buffer %s loaded %.16" PRIx64 " expected %.16" PRIx64, s, dump, result, expected);
printf("\n");
}
inline void printcheck32(enum END e, unsigned nbytes, uint32_t test, uint32_t expected, const char *dump, bool print)
{
uint8_t buf[nbytes];
store32(e, test, buf, nbytes);
char *s = osmo_hexdump_nospc(buf, nbytes);
uint32_t result = load32(e, buf, nbytes);
print = dumpcheck(dump, s, nbytes, result == expected, e, print);
if (print)
printf(": buffer %s known buffer %s loaded %.8" PRIx32 " expected %.8" PRIx32, s, dump, result, expected);
printf("\n");
}
inline void printcheck16(enum END e, uint32_t test, uint32_t expected, const char *dump, bool print)
{
uint8_t buf[2];
store16(e, test, buf);
char *s = osmo_hexdump_nospc(buf, 2);
uint16_t result = load16(e, buf);
print = dumpcheck(dump, s, 2, result == expected, e, print);
if (print)
printf(": buffer %s known buffer %s loaded %.4" PRIx16 " expected %.4" PRIx16, s, dump, result, expected);
printf("\n");
}
/* compute expected value - zero excessive bytes */
inline uint64_t exp64(enum END e, unsigned nbytes, uint64_t value) {
uint8_t adj = 64 - nbytes * 8;
uint64_t v = value << adj;
return (e == LE) ? v >> adj : v;
}
inline uint32_t exp32(enum END e, unsigned nbytes, uint32_t value) {
uint8_t adj = 32 - nbytes * 8;
uint32_t v = value << adj;
return (e == LE) ? v >> adj : v;
}
/* run actual tests - if 'test' is 0 than generate random test value internally */
inline void check64(uint64_t test, uint64_t expected, unsigned nbytes, enum END e)
{
bool print = true;
if (0 == test && 0 == expected) {
test = ((uint64_t)rand() << 32) + rand();
expected = exp64(e, nbytes, test);
print = false;
}
snprintf(s, 17, "%.16" PRIx64, expected);
printcheck64(e, nbytes, test, expected, (BE == e) ? s : NULL, print);
}
inline void check32(uint32_t test, uint32_t expected, unsigned nbytes, enum END e)
{
bool print = true;
if (0 == test && 0 == expected) {
test = rand();
expected = exp32(e, nbytes, test);
print = false;
}
snprintf(s, 17, "%.8" PRIx32, expected);
printcheck32(e, nbytes, test, expected, (BE == e) ? s : NULL, print);
}
inline void check16(uint16_t test, enum END e)
{
bool print = true;
if (0 == test) {
test = (uint16_t)rand();
print = false;
}
snprintf(s, 17, "%.4" PRIx16, test);
printcheck16(e, test, test, (BE == e) ? s : NULL, print);
}
int main(int argc, char **argv)
{
uint8_t out[ARRAY_SIZE(input)];
unsigned int offs;
srand(time(NULL));
for (offs = 0; offs < sizeof(out); offs++) {
uint8_t *start = out + offs;
uint8_t len = sizeof(out) - offs;
@ -32,5 +204,49 @@ int main(int argc, char **argv)
printf("\n");
}
printf("checking byte packing...\n");
printf("running static tests...\n");
check64(0xDEADBEEFF00DCAFE, 0xDEADBEEFF00DCAFE, 8, BE);
check64(0xDEADBEEFF00DCAFE, 0xADBEEFF00DCAFE00, 7, BE);
check64(0xDEADBEEFF00DCAFE, 0xBEEFF00DCAFE0000, 6, BE);
check64(0xDEADBEEFF00DCAFE, 0xEFF00DCAFE000000, 5, BE);
check64(0xDEADBEEFF00DCAFE, 0xDEADBEEFF00DCAFE, 8, LE);
check64(0xDEADBEEFF00DCAFE, 0x00ADBEEFF00DCAFE, 7, LE);
check64(0xDEADBEEFF00DCAFE, 0x0000BEEFF00DCAFE, 6, LE);
check64(0xDEADBEEFF00DCAFE, 0x000000EFF00DCAFE, 5, LE);
check32(0xBABEFACE, 0xBABEFACE, 4, BE);
check32(0xBABEFACE, 0xBEFACE00, 3, BE);
check32(0xBABEFACE, 0xBABEFACE, 4, LE);
check32(0xBABEFACE, 0x00BEFACE, 3, LE);
check16(0xB00B, BE);
check16(0xB00B, LE);
printf("running random tests...\n");
check64(0, 0, 8, BE);
check64(0, 0, 7, BE);
check64(0, 0, 6, BE);
check64(0, 0, 5, BE);
check64(0, 0, 8, LE);
check64(0, 0, 7, LE);
check64(0, 0, 6, LE);
check64(0, 0, 5, LE);
check32(0, 0, 4, BE);
check32(0, 0, 3, BE);
check32(0, 0, 4, LE);
check32(0, 0, 3, LE);
check16(0, BE);
check16(0, LE);
return 0;
}

View File

@ -22,3 +22,34 @@ REVERSED: 02 01
INORDER: 80
REVERSED: 01
checking byte packing...
running static tests...
64 BE OK, storage OK: buffer deadbeeff00dcafe known buffer deadbeeff00dcafe loaded deadbeeff00dcafe expected deadbeeff00dcafe
56 BE OK, storage OK: buffer adbeeff00dcafe known buffer adbeeff00dcafe00 loaded adbeeff00dcafe00 expected adbeeff00dcafe00
48 BE OK, storage OK: buffer beeff00dcafe known buffer beeff00dcafe0000 loaded beeff00dcafe0000 expected beeff00dcafe0000
40 BE OK, storage OK: buffer eff00dcafe known buffer eff00dcafe000000 loaded eff00dcafe000000 expected eff00dcafe000000
64 LE OK: buffer feca0df0efbeadde known buffer (null) loaded deadbeeff00dcafe expected deadbeeff00dcafe
56 LE OK: buffer feca0df0efbead known buffer (null) loaded 00adbeeff00dcafe expected 00adbeeff00dcafe
48 LE OK: buffer feca0df0efbe known buffer (null) loaded 0000beeff00dcafe expected 0000beeff00dcafe
40 LE OK: buffer feca0df0ef known buffer (null) loaded 000000eff00dcafe expected 000000eff00dcafe
32 BE OK, storage OK: buffer babeface known buffer babeface loaded babeface expected babeface
24 BE OK, storage OK: buffer beface known buffer beface00 loaded beface00 expected beface00
32 LE OK: buffer cefabeba known buffer (null) loaded babeface expected babeface
24 LE OK: buffer cefabe known buffer (null) loaded 00beface expected 00beface
16 BE OK, storage OK: buffer b00b known buffer b00b loaded b00b expected b00b
16 LE OK: buffer 0bb0 known buffer (null) loaded b00b expected b00b
running random tests...
64 BE OK, storage OK
56 BE OK, storage OK
48 BE OK, storage OK
40 BE OK, storage OK
64 LE OK
56 LE OK
48 LE OK
40 LE OK
32 BE OK, storage OK
24 BE OK, storage OK
32 LE OK
24 LE OK
16 BE OK, storage OK
16 LE OK