1
0

Message.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifndef Message_H
  16. #define Message_H
  17. #include "exception/Except.h"
  18. #include <stdint.h>
  19. #include "memory/Allocator.h"
  20. #include "util/Bits.h"
  21. #include "util/UniqueName.h"
  22. struct Message
  23. {
  24. /** The length of the message. */
  25. int32_t length;
  26. /** The number of bytes of padding BEFORE where bytes begins. */
  27. int32_t padding;
  28. /** The content. */
  29. uint8_t* bytes;
  30. /** Amount of bytes of storage space available in the message. */
  31. int32_t capacity;
  32. /** The allocator which allocated space for this message. */
  33. struct Allocator* alloc;
  34. };
  35. #define Message_STACK(name, messageLength, amountOfPadding) \
  36. uint8_t UniqueName_get()[messageLength + amountOfPadding]; \
  37. name = &(struct Message){ \
  38. .length = messageLength, \
  39. .bytes = UniqueName_last() + amountOfPadding, \
  40. .padding = amountOfPadding, \
  41. .capacity = messageLength \
  42. }
  43. static inline struct Message* Message_new(uint32_t messageLength,
  44. uint32_t amountOfPadding,
  45. struct Allocator* alloc)
  46. {
  47. uint8_t* buff = Allocator_malloc(alloc, messageLength + amountOfPadding);
  48. struct Message* out = Allocator_malloc(alloc, sizeof(struct Message));
  49. out->bytes = &buff[amountOfPadding];
  50. out->length = out->capacity = messageLength;
  51. out->padding = amountOfPadding;
  52. out->alloc = alloc;
  53. return out;
  54. }
  55. static inline struct Message* Message_clone(struct Message* toClone, struct Allocator* alloc)
  56. {
  57. Assert_true(toClone->capacity >= toClone->length);
  58. int32_t len = toClone->capacity + toClone->padding;
  59. uint8_t* allocation = Allocator_malloc(alloc, len + 8);
  60. while (((uintptr_t)allocation % 8) != (((uintptr_t)toClone->bytes - toClone->padding) % 8)) {
  61. allocation++;
  62. }
  63. Bits_memcpy(allocation, toClone->bytes - toClone->padding, len);
  64. return Allocator_clone(alloc, (&(struct Message) {
  65. .length = toClone->length,
  66. .padding = toClone->padding,
  67. .bytes = allocation + toClone->padding,
  68. .capacity = toClone->capacity,
  69. .alloc = alloc
  70. }));
  71. }
  72. static inline void Message_copyOver(struct Message* output,
  73. struct Message* input,
  74. struct Allocator* allocator)
  75. {
  76. size_t inTotalLength = input->length + input->padding;
  77. size_t outTotalLength = output->length + output->padding;
  78. uint8_t* allocation = output->bytes - output->padding;
  79. if (inTotalLength > outTotalLength) {
  80. allocation = Allocator_realloc(allocator, allocation, inTotalLength);
  81. }
  82. Bits_memcpy(allocation, input->bytes - input->padding, inTotalLength);
  83. output->bytes = allocation + input->padding;
  84. output->length = input->length;
  85. output->padding = input->padding;
  86. }
  87. /**
  88. * Pretend to shift the content forward by amount.
  89. * Really it shifts the bytes value backward.
  90. */
  91. static inline int Message_shift(struct Message* toShift, int32_t amount, struct Except* eh)
  92. {
  93. if (amount > 0 && toShift->padding < amount) {
  94. Except_throw(eh, "buffer overflow");
  95. } else if (toShift->length < (-amount)) {
  96. Except_throw(eh, "buffer underflow");
  97. }
  98. toShift->length += amount;
  99. toShift->capacity += amount;
  100. toShift->bytes -= amount;
  101. toShift->padding -= amount;
  102. return 1;
  103. }
  104. static inline void Message_reset(struct Message* toShift)
  105. {
  106. Assert_true(toShift->length <= toShift->capacity);
  107. toShift->length = toShift->capacity;
  108. Message_shift(toShift, -toShift->length, NULL);
  109. }
  110. static inline void Message_push(struct Message* restrict msg,
  111. const void* restrict object,
  112. size_t size,
  113. struct Except* eh)
  114. {
  115. Message_shift(msg, (int)size, eh);
  116. if (object) {
  117. Bits_memcpy(msg->bytes, object, size);
  118. } else {
  119. Bits_memset(msg->bytes, 0x00, size);
  120. }
  121. }
  122. static inline void Message_pop(struct Message* restrict msg,
  123. void* restrict object,
  124. size_t size,
  125. struct Except* eh)
  126. {
  127. Message_shift(msg, -((int)size), eh);
  128. if (object) {
  129. Bits_memcpy(object, &msg->bytes[-((int)size)], size);
  130. }
  131. }
  132. #define Message_popGeneric(size) \
  133. static inline uint ## size ## _t Message_pop ## size (struct Message* msg, struct Except* eh) \
  134. { \
  135. uint ## size ## _t out; \
  136. Message_pop(msg, &out, (size)/8, eh); \
  137. return Endian_bigEndianToHost ## size (out); \
  138. }
  139. Message_popGeneric(8)
  140. Message_popGeneric(16)
  141. Message_popGeneric(32)
  142. Message_popGeneric(64)
  143. #define Message_pushGeneric(size) \
  144. static inline void Message_push ## size \
  145. (struct Message* msg, uint ## size ## _t dat, struct Except* eh) \
  146. { \
  147. uint ## size ## _t x = Endian_hostToBigEndian ## size (dat); \
  148. Message_push(msg, &x, (size)/8, eh); \
  149. }
  150. Message_pushGeneric(8)
  151. Message_pushGeneric(16)
  152. Message_pushGeneric(32)
  153. Message_pushGeneric(64)
  154. #endif