asn_bit_data.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * Copyright (c) 2005-2017 Lev Walkin <vlm@lionet.info>.
  3. * All rights reserved.
  4. * Redistribution and modifications are permitted subject to BSD license.
  5. */
  6. #include <asn_system.h>
  7. #include <asn_internal.h>
  8. #include <asn_bit_data.h>
  9. /*
  10. * Create a contiguous non-refillable bit data structure.
  11. * Can be freed by FREEMEM().
  12. */
  13. asn_bit_data_t *
  14. asn_bit_data_new_contiguous(const void *data, size_t size_bits) {
  15. size_t size_bytes = (size_bits + 7) / 8;
  16. asn_bit_data_t *pd;
  17. uint8_t *bytes;
  18. /* Get the extensions map */
  19. pd = CALLOC(1, sizeof(*pd) + size_bytes + 1);
  20. if(!pd) {
  21. return NULL;
  22. }
  23. bytes = (void *)(((char *)pd) + sizeof(*pd));
  24. memcpy(bytes, data, size_bytes);
  25. bytes[size_bytes] = 0;
  26. pd->buffer = bytes;
  27. pd->nboff = 0;
  28. pd->nbits = size_bits;
  29. return pd;
  30. }
  31. char *
  32. asn_bit_data_string(asn_bit_data_t *pd) {
  33. static char buf[2][32];
  34. static int n;
  35. n = (n+1) % 2;
  36. snprintf(buf[n], sizeof(buf[n]),
  37. "{m=%" ASN_PRI_SIZE " span %" ASN_PRI_SIZE "[%" ASN_PRI_SIZE
  38. "..%" ASN_PRI_SIZE "] (%" ASN_PRI_SIZE ")}",
  39. pd->moved, ((uintptr_t)(pd->buffer) & 0xf), pd->nboff, pd->nbits,
  40. pd->nbits - pd->nboff);
  41. return buf[n];
  42. }
  43. void
  44. asn_get_undo(asn_bit_data_t *pd, int nbits) {
  45. if((ssize_t)pd->nboff < nbits) {
  46. assert((ssize_t)pd->nboff < nbits);
  47. } else {
  48. pd->nboff -= nbits;
  49. pd->moved -= nbits;
  50. }
  51. }
  52. /*
  53. * Extract a small number of bits (<= 31) from the specified PER data pointer.
  54. */
  55. int32_t
  56. asn_get_few_bits(asn_bit_data_t *pd, int nbits) {
  57. size_t off; /* Next after last bit offset */
  58. ssize_t nleft; /* Number of bits left in this stream */
  59. uint32_t accum;
  60. const uint8_t *buf;
  61. if(nbits < 0)
  62. return -1;
  63. nleft = pd->nbits - pd->nboff;
  64. if(nbits > nleft) {
  65. int32_t tailv, vhead;
  66. if(!pd->refill || nbits > 31) return -1;
  67. /* Accumulate unused bytes before refill */
  68. ASN_DEBUG("Obtain the rest %d bits (want %d)",
  69. (int)nleft, (int)nbits);
  70. tailv = asn_get_few_bits(pd, nleft);
  71. if(tailv < 0) return -1;
  72. /* Refill (replace pd contents with new data) */
  73. if(pd->refill(pd))
  74. return -1;
  75. nbits -= nleft;
  76. vhead = asn_get_few_bits(pd, nbits);
  77. /* Combine the rest of previous pd with the head of new one */
  78. tailv = (tailv << nbits) | vhead; /* Could == -1 */
  79. return tailv;
  80. }
  81. /*
  82. * Normalize position indicator.
  83. */
  84. if(pd->nboff >= 8) {
  85. pd->buffer += (pd->nboff >> 3);
  86. pd->nbits -= (pd->nboff & ~0x07);
  87. pd->nboff &= 0x07;
  88. }
  89. pd->moved += nbits;
  90. pd->nboff += nbits;
  91. off = pd->nboff;
  92. buf = pd->buffer;
  93. /*
  94. * Extract specified number of bits.
  95. */
  96. if(off <= 8)
  97. accum = nbits ? (buf[0]) >> (8 - off) : 0;
  98. else if(off <= 16)
  99. accum = ((buf[0] << 8) + buf[1]) >> (16 - off);
  100. else if(off <= 24)
  101. accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off);
  102. else if(off <= 31)
  103. accum = (((uint32_t)buf[0] << 24) + (buf[1] << 16)
  104. + (buf[2] << 8) + (buf[3])) >> (32 - off);
  105. else if(nbits <= 31) {
  106. asn_bit_data_t tpd = *pd;
  107. /* Here are we with our 31-bits limit plus 1..7 bits offset. */
  108. asn_get_undo(&tpd, nbits);
  109. /* The number of available bits in the stream allow
  110. * for the following operations to take place without
  111. * invoking the ->refill() function */
  112. accum = asn_get_few_bits(&tpd, nbits - 24) << 24;
  113. accum |= asn_get_few_bits(&tpd, 24);
  114. } else {
  115. asn_get_undo(pd, nbits);
  116. return -1;
  117. }
  118. accum &= (((uint32_t)1 << nbits) - 1);
  119. ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]",
  120. (int)nbits, (int)nleft,
  121. (int)pd->moved,
  122. (((long)pd->buffer) & 0xf),
  123. (int)pd->nboff, (int)pd->nbits,
  124. ((pd->buffer != NULL)?pd->buffer[0]:0),
  125. (int)(pd->nbits - pd->nboff),
  126. (int)accum);
  127. return accum;
  128. }
  129. /*
  130. * Extract a large number of bits from the specified PER data pointer.
  131. */
  132. int
  133. asn_get_many_bits(asn_bit_data_t *pd, uint8_t *dst, int alright, int nbits) {
  134. int32_t value;
  135. if(alright && (nbits & 7)) {
  136. /* Perform right alignment of a first few bits */
  137. value = asn_get_few_bits(pd, nbits & 0x07);
  138. if(value < 0) return -1;
  139. *dst++ = value; /* value is already right-aligned */
  140. nbits &= ~7;
  141. }
  142. while(nbits) {
  143. if(nbits >= 24) {
  144. value = asn_get_few_bits(pd, 24);
  145. if(value < 0) return -1;
  146. *(dst++) = value >> 16;
  147. *(dst++) = value >> 8;
  148. *(dst++) = value;
  149. nbits -= 24;
  150. } else {
  151. value = asn_get_few_bits(pd, nbits);
  152. if(value < 0) return -1;
  153. if(nbits & 7) { /* implies left alignment */
  154. value <<= 8 - (nbits & 7),
  155. nbits += 8 - (nbits & 7);
  156. if(nbits > 24)
  157. *dst++ = value >> 24;
  158. }
  159. if(nbits > 16)
  160. *dst++ = value >> 16;
  161. if(nbits > 8)
  162. *dst++ = value >> 8;
  163. *dst++ = value;
  164. break;
  165. }
  166. }
  167. return 0;
  168. }
  169. /*
  170. * Put a small number of bits (<= 31).
  171. */
  172. int
  173. asn_put_few_bits(asn_bit_outp_t *po, uint32_t bits, int obits) {
  174. size_t off; /* Next after last bit offset */
  175. size_t omsk; /* Existing last byte meaningful bits mask */
  176. uint8_t *buf;
  177. if(obits <= 0 || obits >= 32) return obits ? -1 : 0;
  178. ASN_DEBUG("[PER put %d bits %x to %p+%d bits]",
  179. obits, (int)bits, (void *)po->buffer, (int)po->nboff);
  180. /*
  181. * Normalize position indicator.
  182. */
  183. if(po->nboff >= 8) {
  184. po->buffer += (po->nboff >> 3);
  185. po->nbits -= (po->nboff & ~0x07);
  186. po->nboff &= 0x07;
  187. }
  188. /*
  189. * Flush whole-bytes output, if necessary.
  190. */
  191. if(po->nboff + obits > po->nbits) {
  192. size_t complete_bytes;
  193. if(!po->buffer) po->buffer = po->tmpspace;
  194. complete_bytes = (po->buffer - po->tmpspace);
  195. ASN_DEBUG("[PER output %ld complete + %ld]",
  196. (long)complete_bytes, (long)po->flushed_bytes);
  197. if(po->output(po->tmpspace, complete_bytes, po->op_key) < 0)
  198. return -1;
  199. if(po->nboff)
  200. po->tmpspace[0] = po->buffer[0];
  201. po->buffer = po->tmpspace;
  202. po->nbits = 8 * sizeof(po->tmpspace);
  203. po->flushed_bytes += complete_bytes;
  204. }
  205. /*
  206. * Now, due to sizeof(tmpspace), we are guaranteed large enough space.
  207. */
  208. buf = po->buffer;
  209. omsk = ~((1 << (8 - po->nboff)) - 1);
  210. off = (po->nboff + obits);
  211. /* Clear data of debris before meaningful bits */
  212. bits &= (((uint32_t)1 << obits) - 1);
  213. ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits,
  214. (int)bits, (int)bits,
  215. (int)po->nboff, (int)off,
  216. buf[0], (int)(omsk&0xff),
  217. (int)(buf[0] & omsk));
  218. if(off <= 8) /* Completely within 1 byte */
  219. po->nboff = off,
  220. bits <<= (8 - off),
  221. buf[0] = (buf[0] & omsk) | bits;
  222. else if(off <= 16)
  223. po->nboff = off,
  224. bits <<= (16 - off),
  225. buf[0] = (buf[0] & omsk) | (bits >> 8),
  226. buf[1] = bits;
  227. else if(off <= 24)
  228. po->nboff = off,
  229. bits <<= (24 - off),
  230. buf[0] = (buf[0] & omsk) | (bits >> 16),
  231. buf[1] = bits >> 8,
  232. buf[2] = bits;
  233. else if(off <= 31)
  234. po->nboff = off,
  235. bits <<= (32 - off),
  236. buf[0] = (buf[0] & omsk) | (bits >> 24),
  237. buf[1] = bits >> 16,
  238. buf[2] = bits >> 8,
  239. buf[3] = bits;
  240. else {
  241. if(asn_put_few_bits(po, bits >> (obits - 24), 24)) return -1;
  242. if(asn_put_few_bits(po, bits, obits - 24)) return -1;
  243. }
  244. ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]",
  245. (int)bits, (int)bits, buf[0],
  246. (long)(po->buffer - po->tmpspace));
  247. return 0;
  248. }
  249. /*
  250. * Output a large number of bits.
  251. */
  252. int
  253. asn_put_many_bits(asn_bit_outp_t *po, const uint8_t *src, int nbits) {
  254. while(nbits) {
  255. uint32_t value;
  256. if(nbits >= 24) {
  257. value = (src[0] << 16) | (src[1] << 8) | src[2];
  258. src += 3;
  259. nbits -= 24;
  260. if(asn_put_few_bits(po, value, 24))
  261. return -1;
  262. } else {
  263. value = src[0];
  264. if(nbits > 8)
  265. value = (value << 8) | src[1];
  266. if(nbits > 16)
  267. value = (value << 8) | src[2];
  268. if(nbits & 0x07)
  269. value >>= (8 - (nbits & 0x07));
  270. if(asn_put_few_bits(po, value, nbits))
  271. return -1;
  272. break;
  273. }
  274. }
  275. return 0;
  276. }
  277. int
  278. asn_put_aligned_flush(asn_bit_outp_t *po) {
  279. uint32_t unused_bits = (0x7 & (8 - (po->nboff & 0x07)));
  280. size_t complete_bytes =
  281. (po->buffer ? po->buffer - po->tmpspace : 0) + ((po->nboff + 7) >> 3);
  282. if(unused_bits) {
  283. po->buffer[po->nboff >> 3] &= ~0u << unused_bits;
  284. }
  285. if(po->output(po->tmpspace, complete_bytes, po->op_key) < 0) {
  286. return -1;
  287. } else {
  288. po->buffer = po->tmpspace;
  289. po->nboff = 0;
  290. po->nbits = 8 * sizeof(po->tmpspace);
  291. po->flushed_bytes += complete_bytes;
  292. return 0;
  293. }
  294. }