--- /dev/null
+#include <check.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "progbuf.h"
+
+START_TEST (test_progbuf_alloc_version)
+{
+ int ret;
+ long message_tag;
+
+ ret = progbuf_get_message_tag (NULL, &message_tag);
+ ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+ progbuf_h buf = progbuf_alloc (1);
+
+ ck_assert (buf);
+
+ ret = progbuf_get_message_tag (buf, NULL);
+ ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+ ret = progbuf_get_message_tag (buf, &message_tag);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+ ck_assert (message_tag == 1);
+
+ size_t size;
+ ret = progbuf_get_message_buffer (buf, NULL, &size);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ ck_assert (size == 1);
+
+ ret = progbuf_free (buf);
+ ck_assert (ret == PROGBUF_SUCCESS);
+}
+END_TEST
+
+void
+parametric_test_progbuf_write_read_long (const long val,
+ const int expected_val_size)
+{
+ progbuf_h buf = progbuf_alloc (1);
+
+ ck_assert (buf);
+
+ long p_val = val;
+
+ int ret = progbuf_set_long (buf, p_val);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ size_t size;
+ ret = progbuf_get_message_buffer (buf, NULL, &size);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ ck_assert (size == 1 + 1 + expected_val_size);
+
+ progbuf_it_h iter = progbuf_iter_alloc (buf);
+
+ ck_assert (iter);
+
+ ret = progbuf_get_long (iter, &p_val);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+ ck_assert (val == p_val);
+
+ struct progbuf_it_s *iter_internal = iter;
+
+ ck_assert (iter_internal->read_pos == 1 + 1 + expected_val_size);
+
+ ret = progbuf_iter_free (iter);
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ ret = progbuf_free (buf);
+ ck_assert (ret == PROGBUF_SUCCESS);
+}
+
+START_TEST (test_progbuf_write_read_positive_long)
+{
+ parametric_test_progbuf_write_read_long (0, 1);
+ parametric_test_progbuf_write_read_long (1, 1);
+ parametric_test_progbuf_write_read_long (0x3F, 1);
+
+ parametric_test_progbuf_write_read_long (0x7F, 2);
+ parametric_test_progbuf_write_read_long (0x1FFF, 2);
+
+ parametric_test_progbuf_write_read_long (0x3FFF, 3);
+ parametric_test_progbuf_write_read_long (0xFFFFF, 3);
+
+ parametric_test_progbuf_write_read_long (0x1FFFFF, 4);
+ parametric_test_progbuf_write_read_long (0x7FFFFFF, 4);
+
+ parametric_test_progbuf_write_read_long (0xFFFFFFF, 5);
+ parametric_test_progbuf_write_read_long (0x7FFFFFFF, 5);
+}
+END_TEST
+
+START_TEST (test_progbuf_write_read_negative_long)
+{
+ parametric_test_progbuf_write_read_long (-1, 1);
+ parametric_test_progbuf_write_read_long (-0x3F, 1);
+
+ parametric_test_progbuf_write_read_long (-0x7F, 2);
+ parametric_test_progbuf_write_read_long (-0x1FFF, 2);
+
+ parametric_test_progbuf_write_read_long (-0x3FFF, 3);
+ parametric_test_progbuf_write_read_long (-0xFFFFF, 3);
+
+ parametric_test_progbuf_write_read_long (-0x1FFFFF, 4);
+ parametric_test_progbuf_write_read_long (-0x7FFFFFF, 4);
+
+ parametric_test_progbuf_write_read_long (-0xFFFFFFF, 5);
+ parametric_test_progbuf_write_read_long (-0x7FFFFFFF, 5);
+}
+END_TEST
+
+START_TEST (test_progbuf_write_read_ulong)
+{
+ progbuf_h buf = progbuf_alloc (1);
+
+ ck_assert (buf);
+
+ unsigned long val = 0xFFFFFFFF;
+ unsigned long p_val = val;
+
+ int ret = progbuf_set_ulong (buf, p_val);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ size_t size;
+
+ ret = progbuf_get_message_buffer (NULL, NULL, NULL);
+ ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+ ret = progbuf_get_message_buffer (NULL, NULL, &size);
+ ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+ ret = progbuf_get_message_buffer (buf, NULL, NULL);
+ ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+ ret = progbuf_get_message_buffer (buf, NULL, &size);
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ ck_assert (size == 1 + 6);
+
+ progbuf_it_h iter = progbuf_iter_alloc (buf);
+
+ ck_assert (iter);
+
+ ret = progbuf_get_ulong (iter, &p_val);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+ ck_assert (val == p_val);
+
+ struct progbuf_it_s *iter_internal = iter;
+
+ ck_assert (iter_internal->read_pos == 1 + 6);
+
+ ret = progbuf_iter_free (iter);
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ ret = progbuf_free (buf);
+ ck_assert (ret == PROGBUF_SUCCESS);
+}
+END_TEST
+
+void
+parametric_test_progbuf_write_read_longlong (const long long val,
+ const int expected_val_size)
+{
+ progbuf_h buf = progbuf_alloc (1);
+
+ ck_assert (buf);
+
+ long long p_val = val;
+
+ int ret = progbuf_set_longlong (buf, p_val);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ size_t size;
+ ret = progbuf_get_message_buffer (buf, NULL, &size);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ ck_assert (size == 1 + 1 + expected_val_size);
+
+ progbuf_it_h iter = progbuf_iter_alloc (buf);
+
+ ck_assert (iter);
+
+ ret = progbuf_get_longlong (iter, &p_val);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+ ck_assert (val == p_val);
+
+ struct progbuf_it_s *iter_internal = iter;
+
+ ck_assert (iter_internal->read_pos == 1 + 1 + expected_val_size);
+
+ ret = progbuf_iter_free (iter);
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ ret = progbuf_free (buf);
+ ck_assert (ret == PROGBUF_SUCCESS);
+}
+
+START_TEST (test_progbuf_write_read_positive_longlong)
+{
+ parametric_test_progbuf_write_read_longlong (0, 1);
+ parametric_test_progbuf_write_read_longlong (1, 1);
+ parametric_test_progbuf_write_read_longlong (0x3F, 1);
+
+ parametric_test_progbuf_write_read_longlong (0x7F, 2);
+ parametric_test_progbuf_write_read_longlong (0x1FFF, 2);
+
+ parametric_test_progbuf_write_read_longlong (0x3FFF, 3);
+ parametric_test_progbuf_write_read_longlong (0xFFFFF, 3);
+
+ parametric_test_progbuf_write_read_longlong (0x1FFFFF, 4);
+ parametric_test_progbuf_write_read_longlong (0x7FFFFFF, 4);
+
+ parametric_test_progbuf_write_read_longlong (0xFFFFFFF, 5);
+ parametric_test_progbuf_write_read_longlong (0x3FFFFFFFF, 5);
+
+ parametric_test_progbuf_write_read_longlong (0x7FFFFFFFF, 6);
+ parametric_test_progbuf_write_read_longlong (0x1FFFFFFFFFF, 6);
+
+ parametric_test_progbuf_write_read_longlong (0x3FFFFFFFFFF, 7);
+ parametric_test_progbuf_write_read_longlong (0xFFFFFFFFFFFF, 7);
+
+ parametric_test_progbuf_write_read_longlong (0x1FFFFFFFFFFFF, 8);
+ parametric_test_progbuf_write_read_longlong (0x7FFFFFFFFFFFFF, 8);
+
+ parametric_test_progbuf_write_read_longlong (0xFFFFFFFFFFFFFF, 9);
+ parametric_test_progbuf_write_read_longlong (0x3FFFFFFFFFFFFFFF, 9);
+
+ parametric_test_progbuf_write_read_longlong (0x7FFFFFFFFFFFFFFF, 10);
+}
+END_TEST
+
+START_TEST (test_progbuf_write_read_negative_longlong)
+{
+ parametric_test_progbuf_write_read_longlong (-1, 1);
+ parametric_test_progbuf_write_read_longlong (-0x3F, 1);
+
+ parametric_test_progbuf_write_read_longlong (-0x7F, 2);
+ parametric_test_progbuf_write_read_longlong (-0x1FFF, 2);
+
+ parametric_test_progbuf_write_read_longlong (-0x3FFF, 3);
+ parametric_test_progbuf_write_read_longlong (-0xFFFFF, 3);
+
+ parametric_test_progbuf_write_read_longlong (-0x1FFFFF, 4);
+ parametric_test_progbuf_write_read_longlong (-0x7FFFFFF, 4);
+
+ parametric_test_progbuf_write_read_longlong (-0xFFFFFFF, 5);
+ parametric_test_progbuf_write_read_longlong (-0x7FFFFFFF, 5);
+
+ parametric_test_progbuf_write_read_longlong (-0x7FFFFFFFF, 6);
+ parametric_test_progbuf_write_read_longlong (-0x1FFFFFFFFFF, 6);
+
+ parametric_test_progbuf_write_read_longlong (-0x3FFFFFFFFFF, 7);
+ parametric_test_progbuf_write_read_longlong (-0xFFFFFFFFFFFF, 7);
+
+ parametric_test_progbuf_write_read_longlong (-0x1FFFFFFFFFFFF, 8);
+ parametric_test_progbuf_write_read_longlong (-0x7FFFFFFFFFFFFF, 8);
+
+ parametric_test_progbuf_write_read_longlong (-0xFFFFFFFFFFFFFF, 9);
+ parametric_test_progbuf_write_read_longlong (-0x3FFFFFFFFFFFFFFF, 9);
+
+ parametric_test_progbuf_write_read_longlong (-0x7FFFFFFFFFFFFFFF, 10);
+}
+END_TEST
+
+START_TEST (test_progbuf_write_read_ulonglong)
+{
+ progbuf_h buf = progbuf_alloc (1);
+
+ ck_assert (buf);
+
+ unsigned long long val = 0xFFFFFFFFFFFFFFFF;
+ unsigned long long p_val = val;
+
+ int ret = progbuf_set_ulonglong (buf, p_val);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ size_t size;
+
+ ret = progbuf_get_message_buffer (NULL, NULL, NULL);
+ ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+ ret = progbuf_get_message_buffer (NULL, NULL, &size);
+ ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+ ret = progbuf_get_message_buffer (buf, NULL, NULL);
+ ck_assert (ret == PROGBUF_ERROR_NULL_PARAM);
+
+ ret = progbuf_get_message_buffer (buf, NULL, &size);
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ ck_assert (size == 1 + 1 + 10);
+
+ progbuf_it_h iter = progbuf_iter_alloc (buf);
+
+ ck_assert (iter);
+
+ ret = progbuf_get_ulonglong (iter, &p_val);
+
+ ck_assert (ret == PROGBUF_SUCCESS);
+ ck_assert (val == p_val);
+
+ struct progbuf_it_s *iter_internal = iter;
+
+ ck_assert (iter_internal->read_pos == 1 + 1 + 10);
+
+ ret = progbuf_iter_free (iter);
+ ck_assert (ret == PROGBUF_SUCCESS);
+
+ ret = progbuf_free (buf);
+ ck_assert (ret == PROGBUF_SUCCESS);
+}
+END_TEST
+
+static Suite *
+progbuf_suite (void)
+{
+ Suite *s;
+ TCase *tc_basic, *tc_long, *tc_longlong;
+
+ s = suite_create ("progbuf test suite");
+
+ tc_basic = tcase_create ("basic");
+
+ tcase_add_test (tc_basic, test_progbuf_alloc_version);
+
+ tc_long = tcase_create ("encode_long");
+
+ tcase_add_test (tc_long, test_progbuf_write_read_positive_long);
+ tcase_add_test (tc_long, test_progbuf_write_read_negative_long);
+ tcase_add_test (tc_long, test_progbuf_write_read_ulong);
+
+ tc_longlong = tcase_create ("encode_longlong");
+
+ tcase_add_test (tc_longlong, test_progbuf_write_read_positive_longlong);
+ tcase_add_test (tc_longlong, test_progbuf_write_read_negative_longlong);
+ tcase_add_test (tc_longlong, test_progbuf_write_read_ulonglong);
+
+ suite_add_tcase (s, tc_basic);
+ suite_add_tcase (s, tc_long);
+ suite_add_tcase (s, tc_longlong);
+
+ return s;
+}
+
+int
+main ()
+{
+ int number_failed;
+ Suite *s;
+ SRunner *sr;
+
+ s = progbuf_suite ();
+ sr = srunner_create (s);
+
+ srunner_run_all (sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed (sr);
+ srunner_free (sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
#include "common.h"
#include <stdlib.h>
+#include <string.h>
+
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef long long longlong;
+typedef unsigned long long ulonglong;
+
+#define DETERMINE_VAR_SIZE(type) \
+ static inline int determine_var_##type##_size (type value) \
+ { \
+ type mask; \
+ memset (&mask, 0xFF, sizeof (mask)); \
+ \
+ mask <<= 6; \
+ \
+ if ((value & mask) == 0) \
+ return 1; \
+ \
+ int s = 2; \
+ while (1) \
+ { \
+ mask <<= 7; \
+ \
+ if ((value & mask) == 0) \
+ return s; \
+ \
+ s++; \
+ } \
+ }
+
+#define READ_VAR_SIZE(type) \
+ static inline int read_var_##type (progbuf_it_h iter, type *value, \
+ int *negative) \
+ { \
+ type tmp = 0; \
+ size_t prev_read_pos = iter->read_pos; \
+ \
+ int i = 0; \
+ char byte; \
+ const int bitsize = sizeof (type) * 8; \
+ while (i < bitsize) \
+ { \
+ byte = iter->buf->buffer[iter->read_pos++]; \
+ if (i == 0) \
+ { \
+ *negative = byte & 0x40; \
+ tmp |= (type)(byte & 0x3F) << i; \
+ i += 6; \
+ } \
+ else \
+ { \
+ tmp |= (type)(byte & 0x7F) << i; \
+ i += 7; \
+ } \
+ \
+ if ((byte & 0x80) == 0) \
+ { \
+ *value = tmp; \
+ return 0; \
+ } \
+ } \
+ \
+ iter->read_pos = prev_read_pos; \
+ return -1; \
+ }
+
+#define WRITE_VAR_SIZE(type) \
+ static inline void write_var_##type (progbuf_h buf, type value, int size, \
+ int negative) \
+ { \
+ for (int i = 0; i < size - 1; ++i) \
+ { \
+ if (i == 0) \
+ { \
+ if (negative) \
+ { \
+ buf->buffer[buf->size] = (char)((value & 0x3F) | 0xC0); \
+ } \
+ else \
+ { \
+ buf->buffer[buf->size] = (char)((value & 0x3F) | 0x80); \
+ } \
+ value = (type)((type)value >> 6); \
+ } \
+ else \
+ { \
+ buf->buffer[buf->size + i] = (char)((value & 0x7F) | 0x80); \
+ value = (type)((type)value >> 7); \
+ } \
+ } \
+ \
+ if (size == 1 && negative) \
+ { \
+ buf->buffer[buf->size] = (char)value | 0x40; \
+ } \
+ else \
+ { \
+ buf->buffer[buf->size + (size - 1)] = (char)value; \
+ } \
+ \
+ buf->size += size; \
+ }
+
+static inline int
+check_buffer_and_expand (progbuf_h buf, int size)
+{
+ if (buf->size + size > buf->capacity)
+ {
+ char *newbuf = malloc (buf->capacity * 2);
+ if (!newbuf)
+ return PROGBUF_ERROR_MEM_ALLOC;
+
+ memcpy (newbuf, buf->buffer, buf->capacity);
+ free (buf->buffer);
+ buf->buffer = newbuf;
+ buf->capacity *= 2;
+ }
+ return 0;
+}
+
+DETERMINE_VAR_SIZE (uint)
+READ_VAR_SIZE (uint)
+WRITE_VAR_SIZE (uint)
+
+DETERMINE_VAR_SIZE (ulong)
+READ_VAR_SIZE (ulong)
+WRITE_VAR_SIZE (ulong)
+
+DETERMINE_VAR_SIZE (ulonglong)
+READ_VAR_SIZE (ulonglong)
+WRITE_VAR_SIZE (ulonglong)
+
+#define PROGBUF_SET(type, utype) \
+ int progbuf_set_##type (progbuf_h buf, type value) \
+ { \
+ int val_size, ret; \
+ \
+ if (!buf) \
+ return PROGBUF_ERROR_NULL_PARAM; \
+ \
+ val_size = determine_var_##utype##_size (ABS (value)); \
+ ret = check_buffer_and_expand (buf, val_size + 1); \
+ if (ret != 0) \
+ return ret; \
+ \
+ buf->buffer[buf->size] = PROGBUF_TYPE_VAR_INT; \
+ buf->size++; \
+ \
+ write_var_##utype (buf, ABS (value), val_size, value < 0); \
+ \
+ return PROGBUF_SUCCESS; \
+ }
+
+#define PROGBUF_GET(type, utype) \
+ int progbuf_get_##type (progbuf_it_h iter, type *value) \
+ { \
+ if (!iter || !value) \
+ return PROGBUF_ERROR_NULL_PARAM; \
+ \
+ if (iter->read_pos >= iter->buf->size) \
+ return PROGBUF_ERROR_END_OF_ITER; \
+ \
+ char val_type = iter->buf->buffer[iter->read_pos]; \
+ \
+ if ((val_type & PROGBUF_TYPE_VAR_INT) != PROGBUF_TYPE_VAR_INT) \
+ return PROGBUF_ERROR_UNEXPECTED_TYPE; \
+ \
+ iter->read_pos++; \
+ \
+ utype u_value; \
+ int negative; \
+ if (read_var_##utype (iter, &u_value, &negative) != 0) \
+ { \
+ iter->read_pos--; \
+ return PROGBUF_ERROR_READ; \
+ } \
+ \
+ *value = (negative ? -u_value : u_value); \
+ \
+ return PROGBUF_SUCCESS; \
+ }
+
+PROGBUF_SET (int, uint)
+PROGBUF_GET (int, uint)
+
+PROGBUF_SET (uint, uint)
+PROGBUF_GET (uint, uint)
+
+PROGBUF_SET (long, ulong)
+PROGBUF_GET (long, ulong)
+
+PROGBUF_SET (ulong, ulong)
+PROGBUF_GET (ulong, ulong)
+
+PROGBUF_SET (longlong, ulonglong)
+PROGBUF_GET (longlong, ulonglong)
+
+PROGBUF_SET (ulonglong, ulonglong)
+PROGBUF_GET (ulonglong, ulonglong)
progbuf_h
-progbuf_alloc (int message_tag, int version)
+progbuf_alloc (long message_tag)
{
- struct progbuf_s *buf = calloc (1, sizeof (struct progbuf_s));
+ struct progbuf_s *buf = malloc (sizeof (struct progbuf_s));
+
+ if (!buf)
+ return 0;
+
+ buf->buffer = malloc (PROGBUF_INIT_BUFSIZ);
+ if (!buf->buffer)
+ {
+ free (buf);
+ return 0;
+ }
+
+ buf->capacity = PROGBUF_INIT_BUFSIZ;
+ buf->size = 0;
+ buf->message_tag = message_tag;
+
+ int tag_size = determine_var_ulong_size (ABS (message_tag));
+ write_var_ulong (buf, ABS (message_tag), tag_size, message_tag < 0);
+ buf->header_size = tag_size;
+
return buf;
}
-void
+progbuf_it_h
+progbuf_iter_alloc (progbuf_h buf)
+{
+ if (!buf)
+ return 0;
+
+ struct progbuf_it_s *iter = malloc (sizeof (struct progbuf_it_s));
+
+ if (!iter)
+ return 0;
+
+ iter->buf = buf;
+ iter->read_pos = buf->header_size;
+
+ return iter;
+}
+
+int
progbuf_free (progbuf_h buf)
{
- if (buf)
+ if (!buf)
+ return PROGBUF_ERROR_NULL_PARAM;
+
+ free (buf->buffer);
+ free (buf);
+
+ return PROGBUF_SUCCESS;
+}
+
+int
+progbuf_iter_free (progbuf_it_h iter)
+{
+ if (!iter)
+ return PROGBUF_ERROR_NULL_PARAM;
+
+ free (iter);
+
+ return PROGBUF_SUCCESS;
+}
+
+int
+progbuf_get_message_tag (progbuf_h buf, long *message_tag)
+{
+ if (!buf || !message_tag)
+ return PROGBUF_ERROR_NULL_PARAM;
+
+ *message_tag = buf->message_tag;
+
+ return PROGBUF_SUCCESS;
+}
+
+int
+progbuf_get_message_buffer (progbuf_h buf, char **buffer, size_t *size)
+{
+ if (!buf || (!buffer && !size))
+ return PROGBUF_ERROR_NULL_PARAM;
+
+ if (buffer)
{
- if (buf->buffer)
- free (buf->buffer);
+ *buffer = buf->buffer;
+ }
- free (buf);
+ if (size)
+ {
+ *size = buf->size;
}
+
+ return 0;
}
int
-progbuf_set_int (progbuf_h buf, int value)
+progbuf_iter_reset (progbuf_it_h iter)
{
- return -1;
+ if (!iter)
+ return PROGBUF_ERROR_NULL_PARAM;
+
+ iter->read_pos = iter->buf->header_size;
+
+ return PROGBUF_SUCCESS;
}