number parsing with optionals

This commit is contained in:
Juri Glass 2011-07-11 10:58:50 +02:00
parent cd078d5f3f
commit 268bfe423c
3 changed files with 95 additions and 54 deletions

View file

@ -30,16 +30,16 @@ extern "C" {
// Parses a number. Identified by type (SML_TYPE_INTEGER or SML_TYPE_UNSIGNED)
// and maximal number of bytes (SML_TYPE_NUMBER_8, SML_TYPE_NUMBER_16,
// SML_TYPE_NUMBER_32, SML_TYPE_NUMBER_64)
u64 sml_number_parse(sml_buffer *buf, unsigned char type, int max_size);
void *sml_number_parse(sml_buffer *buf, unsigned char type, int max_size);
#define sml_u8_parse(buf) (u8) sml_number_parse(buf, SML_TYPE_UNSIGNED, SML_TYPE_NUMBER_8)
#define sml_u16_parse(buf) (u16) sml_number_parse(buf, SML_TYPE_UNSIGNED, SML_TYPE_NUMBER_16)
#define sml_u32_parse(buf) (u32) sml_number_parse(buf, SML_TYPE_UNSIGNED, SML_TYPE_NUMBER_32)
#define sml_u64_parse(buf) (u64) sml_number_parse(buf, SML_TYPE_UNSIGNED, SML_TYPE_NUMBER_64)
#define sml_i8_parse(buf) (i8) sml_number_parse(buf, SML_TYPE_INTEGER, SML_TYPE_NUMBER_8)
#define sml_i16_parse(buf) (i16) sml_number_parse(buf, SML_TYPE_INTEGER, SML_TYPE_NUMBER_16)
#define sml_i32_parse(buf) (i32) sml_number_parse(buf, SML_TYPE_INTEGER, SML_TYPE_NUMBER_32)
#define sml_i64_parse(buf) (i64) sml_number_parse(buf, SML_TYPE_INTEGER, SML_TYPE_NUMBER_64)
#define sml_u8_parse(buf) (u8 *) sml_number_parse(buf, SML_TYPE_UNSIGNED, SML_TYPE_NUMBER_8)
#define sml_u16_parse(buf) (u16 *) sml_number_parse(buf, SML_TYPE_UNSIGNED, SML_TYPE_NUMBER_16)
#define sml_u32_parse(buf) (u32 *) sml_number_parse(buf, SML_TYPE_UNSIGNED, SML_TYPE_NUMBER_32)
#define sml_u64_parse(buf) (u64 *) sml_number_parse(buf, SML_TYPE_UNSIGNED, SML_TYPE_NUMBER_64)
#define sml_i8_parse(buf) (i8 *) sml_number_parse(buf, SML_TYPE_INTEGER, SML_TYPE_NUMBER_8)
#define sml_i16_parse(buf) (i16 *) sml_number_parse(buf, SML_TYPE_INTEGER, SML_TYPE_NUMBER_16)
#define sml_i32_parse(buf) (i32 *) sml_number_parse(buf, SML_TYPE_INTEGER, SML_TYPE_NUMBER_32)
#define sml_i64_parse(buf) (i64 *) sml_number_parse(buf, SML_TYPE_INTEGER, SML_TYPE_NUMBER_64)
void sml_number_write(unsigned char type, int size, u64 value, sml_buffer *buf);

View file

@ -21,10 +21,21 @@
#include <string.h>
#include <stdio.h>
u64 sml_number_parse(sml_buffer *buf, unsigned char type, int max_size) {
#define SML_BIG_ENDIAN 1
#define SML_LITTLE_ENDIAN 0
int sml_number_endian();
void sml_number_byte_swap(unsigned char *bytes, int bytes_len);
void *sml_number_parse(sml_buffer *buf, unsigned char type, int max_size) {
if (sml_buf_optional_is_skipped(buf)) {
return 0;
}
int l, i;
unsigned char b;
u64 n = 0;
short negative_int = 0;
if (sml_buf_get_next_type(buf) != type) {
buf->error = 1;
return 0;
@ -36,26 +47,28 @@ u64 sml_number_parse(sml_buffer *buf, unsigned char type, int max_size) {
return 0;
}
unsigned char *np = malloc(max_size);
memset(np, 0, max_size);
b = sml_buf_get_current_byte(buf);
// negative value with leading 1's
if (type == SML_TYPE_INTEGER && b & 128) {
n =~ n;
b = 0xFF;
for (i = 0; i < l; i++) {
n <<= 8;
n |= b;
n = (n & ~b) | sml_buf_get_current_byte(buf);
sml_buf_update_bytes_read(buf, 1);
if (type == SML_TYPE_INTEGER && (b & 128)) {
negative_int = 1;
}
int missing_bytes = max_size - l;
memcpy(&(np[missing_bytes]), sml_buf_get_current_buf(buf), l);
if (negative_int) {
for (i = 0; i < missing_bytes; i++) {
np[i] = 0xFF;
}
}
else {
for (i = 0; i < l; i++) {
n <<= 8;
n |= sml_buf_get_current_byte(buf);
sml_buf_update_bytes_read(buf, 1);
}
if (!(sml_number_endian() == SML_BIG_ENDIAN)) {
sml_number_byte_swap(np, max_size);
}
return n;
return np;
}
void sml_number_write(unsigned char type, int size, u64 value, sml_buffer *buf) {
@ -70,3 +83,23 @@ void sml_number_write(unsigned char type, int size, u64 value, sml_buffer *buf)
}
buf->cursor += size;
}
void sml_number_byte_swap(unsigned char *bytes, int bytes_len) {
int i;
unsigned char ob[bytes_len];
memcpy(&ob, bytes, bytes_len);
for (i = 0; i < bytes_len; i++) {
bytes[i] = ob[bytes_len - (i + 1)];
}
}
int sml_number_endian() {
int i = 1;
char *p = (char *)&i;
if (p[0] == 1)
return SML_LITTLE_ENDIAN;
else
return SML_BIG_ENDIAN;
}

View file

@ -17,6 +17,7 @@
// along with libSML. If not, see <http://www.gnu.org/licenses/>.
#include "../unity/unity_fixture.h"
#include "../unity/unity.h"
#include "test_helper.h"
#include <sml/sml_number.h>
@ -28,75 +29,80 @@ TEST_SETUP(sml_number) {
buf = sml_buffer_init(512);
}
TEST_TEAR_DOWN(sml_number) {
}
TEST_TEAR_DOWN(sml_number) {}
TEST(sml_number, parse_unsigned8) {
hex2binary("6201", sml_buf_get_current_buf(buf));
u8 n = sml_u8_parse(buf);
TEST_ASSERT_EQUAL(1, n);
u8 *n = sml_u8_parse(buf);
TEST_ASSERT_EQUAL(1, *n);
}
TEST(sml_number, parse_unsigned16) {
hex2binary("630101", sml_buf_get_current_buf(buf));
u16 n = sml_u16_parse(buf);
TEST_ASSERT_EQUAL(257, n);
u16 *n = sml_u16_parse(buf);
TEST_ASSERT_EQUAL(257, *n);
}
TEST(sml_number, parse_unsigned32) {
hex2binary("6500000001", sml_buf_get_current_buf(buf));
u32 n = sml_u32_parse(buf);
TEST_ASSERT_EQUAL(1, n);
u32 *n = sml_u32_parse(buf);
TEST_ASSERT_EQUAL(1, *n);
}
TEST(sml_number, parse_unsigned32_fewer_bytes) {
hex2binary("64010001", sml_buf_get_current_buf(buf));
u32 n = sml_u32_parse(buf);
TEST_ASSERT_EQUAL(65537, n);
u32 *n = sml_u32_parse(buf);
TEST_ASSERT_EQUAL(65537, *n);
}
TEST(sml_number, parse_unsigned32_optional) {
hex2binary("01", sml_buf_get_current_buf(buf));
u32 *n = sml_u32_parse(buf);
TEST_ASSERT_NULL(n);
TEST_ASSERT_EQUAL(1, buf->cursor);
}
TEST(sml_number, parse_unsigned64) {
hex2binary("690000000000000001", sml_buf_get_current_buf(buf));
u64 n = sml_u64_parse(buf);
TEST_ASSERT_EQUAL(1, n);
//u64 *n = sml_u64_parse(buf);
u64 *n = sml_u64_parse(buf);
TEST_ASSERT_EQUAL(1, *n);
}
TEST(sml_number, parse_unsigned64_fewer_bytes) {
hex2binary("67000000000001", sml_buf_get_current_buf(buf));
u64 n = sml_u64_parse(buf);
TEST_ASSERT_EQUAL(1, n);
u64 *n = sml_u64_parse(buf);
TEST_ASSERT_EQUAL(1, *n);
}
TEST(sml_number, parse_int8) {
hex2binary("52FF", sml_buf_get_current_buf(buf));
i8 n = sml_i8_parse(buf);
TEST_ASSERT_EQUAL(-1, n);
i8 *n = sml_i8_parse(buf);
TEST_ASSERT_EQUAL(-1, *n);
}
TEST(sml_number, parse_int16) {
hex2binary("53EC78", sml_buf_get_current_buf(buf));
i16 n = sml_i16_parse(buf);
TEST_ASSERT_EQUAL(-5000, n);
i16 *n = sml_i16_parse(buf);
TEST_ASSERT_EQUAL(-5000, *n);
}
TEST(sml_number, parse_int32) {
hex2binary("55FFFFFFFF", sml_buf_get_current_buf(buf));
i32 n = sml_i32_parse(buf);
TEST_ASSERT_EQUAL(-1, n);
hex2binary("55FFFFEC78", sml_buf_get_current_buf(buf));
i32 *n = sml_i32_parse(buf);
TEST_ASSERT_EQUAL(-5000, *n);
}
TEST(sml_number, parse_int64) {
hex2binary("59FFFFFFFFFFFFFFFF", sml_buf_get_current_buf(buf));
i64 n = sml_i64_parse(buf);
TEST_ASSERT_EQUAL(-1, n);
i64 *n = sml_i64_parse(buf);
TEST_ASSERT_EQUAL(-1, *n);
}
TEST(sml_number, parse_int64_fewer_bytes) {
hex2binary("58FFFFFFFFFFEC78", sml_buf_get_current_buf(buf));
i64 n = sml_i64_parse(buf);
TEST_ASSERT_EQUAL(-5000, n);
i64 *n = sml_i64_parse(buf);
TEST_ASSERT_EQUAL(-5000, *n);
}
TEST_GROUP_RUNNER(sml_number) {
@ -106,11 +112,13 @@ TEST_GROUP_RUNNER(sml_number) {
RUN_TEST_CASE(sml_number, parse_unsigned64);
RUN_TEST_CASE(sml_number, parse_unsigned32_fewer_bytes);
RUN_TEST_CASE(sml_number, parse_unsigned64_fewer_bytes);
RUN_TEST_CASE(sml_number, parse_unsigned32_optional);
RUN_TEST_CASE(sml_number, parse_int8);
RUN_TEST_CASE(sml_number, parse_int16);
RUN_TEST_CASE(sml_number, parse_int32);
RUN_TEST_CASE(sml_number, parse_int64);
RUN_TEST_CASE(sml_number, parse_int64_fewer_bytes);
}