encoder.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #include <stddef.h>
  2. #include <stdlib.h>
  3. #include "sysdep.h"
  4. #include "constants.h"
  5. #include <limits.h>
  6. #include <string.h>
  7. #ifdef __cplusplus
  8. extern "C" {
  9. #endif
  10. typedef struct erlpack_buffer {
  11. char *buf;
  12. size_t length;
  13. size_t allocated_size;
  14. } erlpack_buffer;
  15. static inline int erlpack_buffer_write(erlpack_buffer *pk, const char *bytes,
  16. size_t l) {
  17. char *buf = pk->buf;
  18. size_t allocated_size = pk->allocated_size;
  19. size_t length = pk->length;
  20. if (length + l > allocated_size) {
  21. // Grow buffer 2x to avoid excessive re-allocations.
  22. allocated_size = (length + l) * 2;
  23. buf = (char *)realloc(buf, allocated_size);
  24. if (!buf)
  25. return -1;
  26. }
  27. memcpy(buf + length, bytes, l);
  28. length += l;
  29. pk->buf = buf;
  30. pk->allocated_size = allocated_size;
  31. pk->length = length;
  32. return 0;
  33. }
  34. #define erlpack_append(pk, buf, len) \
  35. return erlpack_buffer_write(pk, (const char *)buf, len)
  36. static inline int erlpack_append_version(erlpack_buffer *b) {
  37. static unsigned char buf[1] = {FORMAT_VERSION};
  38. erlpack_append(b, buf, 1);
  39. }
  40. static inline int erlpack_append_nil(erlpack_buffer *b) {
  41. static unsigned char buf[5] = {SMALL_ATOM_EXT, 3, 'n', 'i', 'l'};
  42. erlpack_append(b, buf, 5);
  43. }
  44. static inline int erlpack_append_false(erlpack_buffer *b) {
  45. static unsigned char buf[7] = {SMALL_ATOM_EXT, 5, 'f', 'a', 'l', 's', 'e'};
  46. erlpack_append(b, buf, 7);
  47. }
  48. static inline int erlpack_append_true(erlpack_buffer *b) {
  49. static unsigned char buf[6] = {SMALL_ATOM_EXT, 4, 't', 'r', 'u', 'e'};
  50. erlpack_append(b, buf, 6);
  51. }
  52. static inline int erlpack_append_small_integer(erlpack_buffer *b,
  53. unsigned char d) {
  54. unsigned char buf[2] = {SMALL_INTEGER_EXT, d};
  55. erlpack_append(b, buf, 2);
  56. }
  57. static inline int erlpack_append_integer(erlpack_buffer *b, int32_t d) {
  58. unsigned char buf[5];
  59. buf[0] = INTEGER_EXT;
  60. _erlpack_store32(buf + 1, d);
  61. erlpack_append(b, buf, 5);
  62. }
  63. static inline int erlpack_append_unsigned_long_long(erlpack_buffer *b,
  64. unsigned long long d) {
  65. unsigned char buf[1 + 2 + sizeof(unsigned long long)];
  66. buf[0] = SMALL_BIG_EXT;
  67. unsigned char bytes_enc = 0;
  68. while (d > 0) {
  69. buf[3 + bytes_enc] = d & 0xFF;
  70. d >>= 8;
  71. bytes_enc++;
  72. }
  73. buf[1] = bytes_enc;
  74. buf[2] = 0;
  75. erlpack_append(b, buf, 1 + 2 + bytes_enc);
  76. }
  77. static inline int erlpack_append_long_long(erlpack_buffer *b, long long d) {
  78. unsigned char buf[1 + 2 + sizeof(unsigned long long)];
  79. buf[0] = SMALL_BIG_EXT;
  80. buf[2] = d < 0 ? 1 : 0;
  81. unsigned long long ull = d < 0 ? -d : d;
  82. unsigned char bytes_enc = 0;
  83. while (ull > 0) {
  84. buf[3 + bytes_enc] = ull & 0xFF;
  85. ull >>= 8;
  86. bytes_enc++;
  87. }
  88. buf[1] = bytes_enc;
  89. erlpack_append(b, buf, 1 + 2 + bytes_enc);
  90. }
  91. typedef union {
  92. uint64_t ui64;
  93. double df;
  94. } typePunner;
  95. static inline int erlpack_append_double(erlpack_buffer *b, double f) {
  96. unsigned char buf[1 + 8] = {0};
  97. buf[0] = NEW_FLOAT_EXT;
  98. typePunner p;
  99. p.df = f;
  100. _erlpack_store64(buf + 1, p.ui64);
  101. erlpack_append(b, buf, 1 + 8);
  102. }
  103. static inline int erlpack_append_atom(erlpack_buffer *b, const char *bytes, size_t size) {
  104. if (size < 255) {
  105. unsigned char buf[2] = {SMALL_ATOM_EXT, (unsigned char)size};
  106. int ret = erlpack_buffer_write(b, (const char *)buf, 2);
  107. if (ret < 0)
  108. return ret;
  109. erlpack_append(b, bytes, size);
  110. } else {
  111. unsigned char buf[3];
  112. buf[0] = ATOM_EXT;
  113. if (size > 0xFFFF) {
  114. return 1;
  115. }
  116. _erlpack_store16(buf + 1, size);
  117. int ret = erlpack_buffer_write(b, (const char *)buf, 3);
  118. if (ret < 0)
  119. return ret;
  120. erlpack_append(b, bytes, size);
  121. }
  122. }
  123. static inline int erlpack_append_binary(erlpack_buffer *b, const char *bytes, size_t size) {
  124. unsigned char buf[5];
  125. buf[0] = BINARY_EXT;
  126. _erlpack_store32(buf + 1, size);
  127. int ret = erlpack_buffer_write(b, (const char *)buf, 5);
  128. if (ret < 0)
  129. return ret;
  130. erlpack_append(b, bytes, size);
  131. }
  132. static inline int erlpack_append_string(erlpack_buffer *b, const char *bytes, size_t size) {
  133. unsigned char buf[3];
  134. buf[0] = STRING_EXT;
  135. _erlpack_store16(buf + 1, size);
  136. int ret = erlpack_buffer_write(b, (const char *)buf, 3);
  137. if (ret < 0)
  138. return ret;
  139. erlpack_append(b, bytes, size);
  140. }
  141. static inline int erlpack_append_tuple_header(erlpack_buffer *b, size_t size) {
  142. if (size < 256) {
  143. unsigned char buf[2];
  144. buf[0] = SMALL_TUPLE_EXT;
  145. buf[1] = (unsigned char)size;
  146. erlpack_append(b, buf, 2);
  147. } else {
  148. unsigned char buf[5];
  149. buf[0] = LARGE_TUPLE_EXT;
  150. _erlpack_store32(buf + 1, size);
  151. erlpack_append(b, buf, 5);
  152. }
  153. }
  154. static inline int erlpack_append_nil_ext(erlpack_buffer *b) {
  155. static unsigned char buf[1] = {NIL_EXT};
  156. erlpack_append(b, buf, 1);
  157. }
  158. static inline int erlpack_append_list_header(erlpack_buffer *b, size_t size) {
  159. unsigned char buf[5];
  160. buf[0] = LIST_EXT;
  161. _erlpack_store32(buf + 1, size);
  162. erlpack_append(b, buf, 5);
  163. }
  164. static inline int erlpack_append_map_header(erlpack_buffer *b, size_t size) {
  165. unsigned char buf[5];
  166. buf[0] = MAP_EXT;
  167. _erlpack_store32(buf + 1, size);
  168. erlpack_append(b, buf, 5);
  169. }
  170. #ifdef __cplusplus
  171. }
  172. #endif