Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

tcobsv1Decode.c 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*! \file tcobsv1Decode.c
  2. \author Thomas.Hoehenleitner [at] seerose.net
  3. \details See ./TCOBSv1Specification.md.
  4. *******************************************************************************/
  5. #include <stdint.h>
  6. #include <stddef.h>
  7. #include <string.h> // memcpy
  8. #include "tcobs.h"
  9. #include "tcobsv1Internal.h"
  10. static int sigilAndOffset(uint8_t* sigil, uint8_t b);
  11. static uint8_t repeatByte(int offset, uint8_t* in, int len);
  12. int TCOBSDecode(void* __restrict output, size_t max, const void* __restrict input, size_t length) {
  13. uint8_t* in = (uint8_t*)input;
  14. int ilen = (int)length; // remaining input length
  15. uint8_t* out = (uint8_t*)output;
  16. int olen = 0; // output length
  17. while (ilen > 0) {
  18. uint8_t next = in[ilen - 1]; // get next sigil byte (starting from the end)
  19. uint8_t sigil;
  20. uint8_t r;
  21. int offset = sigilAndOffset(&sigil, next);
  22. if (offset + 1 > ilen) {
  23. return INPUT_DATA_CORRUPTED - __LINE__;
  24. }
  25. ilen -= 1; // remove sigil byte from buffer
  26. switch (sigil) {
  27. case N:
  28. goto copyBytes;
  29. case Z3:
  30. olen += 1;
  31. out[max - olen] = 0;
  32. // fallthrough
  33. case Z2:
  34. olen += 1;
  35. out[max - olen] = 0;
  36. // fallthrough
  37. case Z1:
  38. olen += 1;
  39. out[max - olen] = 0;
  40. goto copyBytes;
  41. case F4:
  42. olen += 1;
  43. out[max - olen] = 0xFF;
  44. // fallthrough
  45. case F3:
  46. olen += 1;
  47. out[max - olen] = 0xFF;
  48. // fallthrough
  49. case F2:
  50. olen += 1;
  51. out[max - olen] = 0xFF;
  52. olen += 1;
  53. out[max - olen] = 0xFF;
  54. goto copyBytes;
  55. case R4:
  56. olen += 1;
  57. out[max - olen] = repeatByte(offset, in, ilen);
  58. // fallthrough
  59. case R3:
  60. olen += 1;
  61. out[max - olen] = repeatByte(offset, in, ilen);
  62. // fallthrough
  63. case R2:
  64. r = repeatByte(offset, in, ilen);
  65. olen += 1;
  66. out[max - olen] = r;
  67. olen += 1;
  68. out[max - olen] = r;
  69. goto copyBytes;
  70. default:
  71. return INPUT_DATA_CORRUPTED - __LINE__;
  72. }
  73. copyBytes: {
  74. uint8_t* to = out + max - olen - offset; // to := len(d) - n - offset
  75. uint8_t* from = in + ilen - offset; // from := len(in) - offset // sigil byte is already removed
  76. if (to < out) {
  77. return OUT_BUFFER_TOO_SMALL - __LINE__;
  78. }
  79. memcpy(to, from, offset); // n += copy(d[to:], in[from:])
  80. olen += offset;
  81. ilen -= offset; // in = in[:len(in)-offset] // remove copied bytes
  82. continue;
  83. }
  84. }
  85. return olen;
  86. }
  87. // sigilAndOffset interprets b as sigil byte with offset, fills sigil and returns offset.
  88. // For details see TCOBSv1Specification.md.
  89. static int sigilAndOffset(uint8_t* sigil, uint8_t b) {
  90. int offset;
  91. *sigil = b & 0xE0; // 0x11100000
  92. if (*sigil == 0) {
  93. *sigil = b & 0xF8; // 0x11111000
  94. offset = 7 & b; // 0x00000111
  95. } else {
  96. offset = 0x1F & b; // 0x00011111
  97. }
  98. return offset;
  99. }
  100. // repeatByte returns the value to repeat
  101. static uint8_t repeatByte(int offset, uint8_t* in, int len) {
  102. if (offset == 0) { // left byte of Ri is a sigil byte (probably N)
  103. return in[len - 2]; // a buffer cannot start with Ri
  104. } else {
  105. return in[len - 1];
  106. }
  107. }