您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

tcobsv1Encode.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. /*! \file tcobsv1Encode.c
  2. \author Thomas.Hoehenleitner [at] seerose.net
  3. \details See ./TCOBSv1Specification.md.
  4. *******************************************************************************/
  5. #include <stdint.h>
  6. #include <stddef.h>
  7. #include "tcobs.h"
  8. #include "tcobsv1Internal.h"
  9. // lint -e801 Info 801: Use of goto is deprecated
  10. //! ASSERT checks for a true condition, otherwise stop.
  11. //! This macro was used during development to verify the code.
  12. #define ASSERT(condition) // do{ if( !(condition) ){ for(;;){} } }while(0);
  13. //! OUTB writes a non-sigil byte to output and increments offset.
  14. //! If offset reaches 31, a NOP sigil byte is inserted and offset is then set to 0.
  15. #define OUTB(by) \
  16. { \
  17. *o++ = by; \
  18. offset++; \
  19. ASSERT(offset <= 31); \
  20. if (offset == 31) { \
  21. *o++ = N | 31; \
  22. offset = 0; \
  23. } \
  24. }
  25. //! OUT_zeroSigil writes one of the sigil bytes Z1, Z3, Z3
  26. //! according to zeroCount and sets zeroCount=0 and offset=0.
  27. #define OUT_zeroSigil \
  28. { \
  29. ASSERT(b_1 == 0); \
  30. ASSERT((fullCount | reptCount) == 0); \
  31. ASSERT(1 <= zeroCount && zeroCount <= 3); \
  32. ASSERT(offset <= 31); \
  33. *o++ = (zeroCount << 5) | offset; \
  34. offset = 0; \
  35. zeroCount = 0; \
  36. }
  37. //! OUT_fullSigil writes one of the sigil bytes F2, F3, F4
  38. //! according to fullCount and sets fullCount=0 and offset=0.
  39. #define OUT_fullSigil \
  40. { \
  41. ASSERT(b_1 == 0xFF); \
  42. ASSERT((zeroCount | reptCount) == 0); \
  43. ASSERT(2 <= fullCount && fullCount <= 4); \
  44. ASSERT(offset <= 31); \
  45. *o++ = 0x80 | (fullCount << 5) | offset; \
  46. offset = 0; \
  47. fullCount = 0; \
  48. }
  49. //! OUT_reptSigil writes one of the sigil bytes R2, R3, R4
  50. //! according to reptCount and sets reptCount=0 and offset=0.
  51. //! If offset is bigger than 7 a NOP sigil byte is inserted.
  52. #define OUT_reptSigil \
  53. { \
  54. ASSERT((zeroCount | fullCount) == 0); \
  55. ASSERT(2 <= reptCount && reptCount <= 4); \
  56. ASSERT(offset <= 31); \
  57. if (offset > 7) { \
  58. *o++ = N | offset; \
  59. offset = 0; \
  60. } \
  61. *o++ = ((reptCount - 1) << 3) | offset; \
  62. offset = 0; \
  63. reptCount = 0; \
  64. }
  65. int TCOBSEncode(void* __restrict output, const void* __restrict input, size_t length) {
  66. uint8_t* o = output; // write pointer
  67. uint8_t* out = output;
  68. uint8_t const* i = input; // read pointer
  69. uint8_t const* limit = (uint8_t*)input + length; // read limit
  70. uint8_t zeroCount = 0; // counts zero bytes 1-3 for Z1-Z3
  71. uint8_t fullCount = 0; // counts 0xFF bytes 1-4 for FF and F2-F4
  72. uint8_t reptCount = 0; // counts repeat bytes 1-4 for !00 and R2-R4,
  73. uint8_t b_1 = 0; // previous byte
  74. uint8_t b = 0; // current byte
  75. uint8_t offset = 0; // link to next sigil or buffer start looking backwards
  76. // comment syntax:
  77. // Sigil bytes chaining is done with offset and not shown explicitly.
  78. // All left from comma is already written to o and if, only partially shown.
  79. // n is 0...3|4 and m is n+1, representing count number.
  80. // zn, fn, rn right from comma is count in variables, if not shown, then 0.
  81. // At any moment only one of the 3 counters can be different from 0.
  82. // Zn, Fn, Rn, Nn are (written) sigil bytes.
  83. // Between comma and dot are the 2 values b_1 and b.
  84. // 3 dots ... means it is unknown if bytes follow.
  85. // !00 is a byte != 00.
  86. // !FF is a byte != FF.
  87. // aa is not 00 and not FF and all aa in a row are equal.
  88. // xx yy and zz are any bytes.
  89. // Invalid b_1 and b are displayed as --.
  90. if (length >= 2) { // , -- --. xx yy ...
  91. b = *i++; // , -- xx. yy ...
  92. for (;;) { // , zn|fn|rn -- xx. yy ...
  93. b_1 = b; // , xx --. yy ...
  94. b = *i++; // , xx yy. ...
  95. if (limit - i > 0) { // , xx yy. zz ...
  96. // , z0 00 00. -> , z1 -- 00.
  97. // , z0 00 00. 00 -> , z2 -- 00.
  98. if ((b_1 | b) == 0) { // , zn 00 00. zz ...
  99. zeroCount++; // , zm -- 00. zz ...
  100. if (zeroCount == 2) { // , z2 -- 00. zz ...
  101. zeroCount = 3; // , z3 -- --. zz ...
  102. OUT_zeroSigil // Z3, -- --. zz ...
  103. b = *i++; // , -- zz. ...
  104. if (limit - i == 0) { // , -- zz.
  105. goto lastByte;
  106. }
  107. // , -- xx. yy ...
  108. }
  109. continue; // , zn -- xx. yy ...
  110. }
  111. // , f0 FF FF. -> , f1 -- FF.
  112. // , f0 FF FF. FF -> , f2 -- FF.
  113. // , f0 FF FF. FF FF -> , f3 -- FF.
  114. if ((b_1 & b) == 0xFF) { // , fn FF FF. zz ...
  115. fullCount++; // , fm -- FF. zz ...
  116. if (fullCount == 3) { // , f3 -- FF. zz ...
  117. fullCount = 4; // , f4 -- --. zz ...
  118. OUT_fullSigil // F4, -- --. zz ...
  119. b = *i++; // , -- zz. ...
  120. if (limit - i == 0) { // , -- zz.
  121. goto lastByte;
  122. }
  123. // , -- xx. yy ...
  124. }
  125. continue; // , fn -- xx. yy ...
  126. }
  127. // , r0 aa aa. -> , r1 -- aa.
  128. // , r0 aa aa. aa -> , r2 -- aa.
  129. // , r0 aa aa. aa aa -> , r3 -- aa.
  130. // , r0 aa aa. aa aa aa -> , r4 -- aa.
  131. if (b_1 == b) { // , rn aa aa. xx ...
  132. ASSERT(b_1 != 0);
  133. ASSERT(b_1 != 0xFF);
  134. reptCount++; // , rm -- aa. xx ...
  135. if (reptCount == 4) { // , r4 -- aa. xx ...
  136. OUTB(b) // aa, r4 -- --. xx ...
  137. OUT_reptSigil // aa R4, -- --. xx ...
  138. b = *i++; // , -- xx. ...
  139. if (limit - i == 0) { // , -- xx.
  140. goto lastByte;
  141. }
  142. // , -- xx. yy ...
  143. }
  144. continue; // , r1|r2|r3 -- aa. yy ...
  145. } // OR // , -- xx. yy ...
  146. // , zn|fn|rn xx yy. zz ... (at this point is b_1 != b)
  147. // handle counts
  148. if (zeroCount) { // , z1|z2 00 aa. xx ...
  149. ASSERT(1 <= zeroCount && zeroCount <= 2)
  150. ASSERT(b_1 == 0)
  151. ASSERT(b_1 != b)
  152. zeroCount++; // , z2|z3 -- aa. xx ...
  153. OUT_zeroSigil // Z2|Z3, -- aa. xx ...
  154. continue;
  155. }
  156. if (fullCount) { // , f1|f2|f3 FF !FF. xx ...
  157. ASSERT(1 <= fullCount && fullCount <= 3)
  158. ASSERT(b_1 == 0xFF)
  159. ASSERT(b_1 != b)
  160. fullCount++; // , f2|f3|f4 -- !FF. xx ...
  161. OUT_fullSigil // Fn, -- !FF. xx ...
  162. continue;
  163. }
  164. if (reptCount) { // , r1|r2|r3 aa !aa. xx ...
  165. ASSERT(1 <= reptCount && reptCount <= 3)
  166. ASSERT(b_1 != 0)
  167. ASSERT(b_1 != 0xFF)
  168. ASSERT(b_1 != b)
  169. if (reptCount == 1) { // , r1 aa !aa. xx ...
  170. reptCount = 0; // clear
  171. OUTB(b_1) // aa, r0 aa !aa. xx ...
  172. OUTB(b_1) // aa aa, -- !aa. xx ...
  173. continue;
  174. }
  175. *o++ = b_1; // aa, r2|r3 -- !aa. xx ...
  176. offset++;
  177. OUT_reptSigil // aa R1|R2|R3, -- !aa. xx ...
  178. continue;
  179. }
  180. // at this point all counts are 0, b_1 != b and b_1 = xx, b == yy
  181. ASSERT(zeroCount == 0)
  182. ASSERT(fullCount == 0)
  183. ASSERT(reptCount == 0)
  184. ASSERT(b_1 != b)
  185. // , xx yy. zz ...
  186. if (b_1 == 0) { // , 00 !00. xx ...
  187. ASSERT(b != 0)
  188. zeroCount++; // , z1 -- !00. xx ...
  189. OUT_zeroSigil continue; // Z1, -- !00. xx ...
  190. }
  191. if (b_1 == 0xFF) { // , FF !FF. xx ...
  192. ASSERT(b != 0xFF)
  193. OUTB(0xFF); // FF, -- !FF. xx ...
  194. continue;
  195. }
  196. // , aa xx. yy ...
  197. ASSERT(1 <= b_1 && b_1 <= 0xFE)
  198. OUTB(b_1) // aa, -- xx. yy ...
  199. continue;
  200. } else { // last 2 bytes
  201. // , zn|fn|rn xx yy.
  202. if ((zeroCount | fullCount | reptCount) == 0) { // , xx yy.
  203. if (b_1 == 0 && b == 0) { // , 00 00.
  204. *o++ = Z2 | offset; // Z2, -- --.
  205. return o - out;
  206. }
  207. if (b_1 == 0xFF && b == 0xFF) { // , FF FF.
  208. *o++ = F2 | offset; // F2, -- --.
  209. return o - out;
  210. }
  211. if (b_1 == 0) { // , 00 xx.
  212. zeroCount = 1; // , z1 -- xx.
  213. OUT_zeroSigil // Z1, -- xx.
  214. goto lastByte;
  215. }
  216. // , aa xx.
  217. ASSERT(b_1 != 0)
  218. OUTB(b_1) // aa, -- xx.
  219. goto lastByte;
  220. }
  221. // At this point exactly one count was incremented.
  222. // If a count is >0 it is necessarily related to b_1.
  223. if (zeroCount == 1) { // , z1 00 yy
  224. ASSERT(fullCount == 0)
  225. ASSERT(reptCount == 0)
  226. ASSERT(b_1 == 0)
  227. if (b != 0) { // , z1 00 !00.
  228. zeroCount++; // , z2 -- !00.
  229. OUT_zeroSigil // Z2, -- !00.
  230. goto lastByte;
  231. }
  232. if (b == 0) { // , z1 00 00.
  233. *o++ = Z3 | offset; // Z3, -- --.
  234. return o - out;
  235. }
  236. ASSERT(0)
  237. }
  238. if (zeroCount == 2) { // , z2 00 !00.
  239. ASSERT(fullCount == 0)
  240. ASSERT(reptCount == 0)
  241. ASSERT(b_1 == 0)
  242. ASSERT(b != 0)
  243. zeroCount = 3; // , z3 -- aa.
  244. OUT_zeroSigil // Z3, -- aa.
  245. goto lastByte;
  246. }
  247. if (fullCount == 1) { // , f1 FF yy.
  248. ASSERT(zeroCount == 0)
  249. ASSERT(reptCount == 0)
  250. ASSERT(b_1 == 0xFF)
  251. if (b == 0xFF) { // , f1 FF FF.
  252. ASSERT(offset <= 31);
  253. *o++ = F3 | offset; // F3, -- --.
  254. return o - out;
  255. }
  256. fullCount = 2; // , f2 -- yy.
  257. OUT_fullSigil // F2, -- yy.
  258. goto lastByte;
  259. }
  260. if (fullCount == 2) { // , f2 FF yy.
  261. ASSERT(zeroCount == 0)
  262. ASSERT(reptCount == 0)
  263. ASSERT(b_1 == 0xFF)
  264. if (b == 0xFF) { // , f2 FF FF.
  265. ASSERT(offset <= 31);
  266. *o++ = F4 | offset; // F4, -- --.
  267. return o - out;
  268. }
  269. // , f2 FF !FF
  270. fullCount++; // , f3 -- !FF.
  271. OUT_fullSigil // F3, -- !FF.
  272. goto lastByte;
  273. }
  274. if (fullCount == 3) { // , f3 FF yy.
  275. ASSERT(zeroCount == 0)
  276. ASSERT(reptCount == 0)
  277. ASSERT(b_1 == 0xFF)
  278. if (b == 0xFF) { // , f3 FF FF.
  279. OUT_fullSigil // F3, FF FF.
  280. ASSERT(offset <= 31);
  281. *o++ = F2 | offset; // F3 F2, -- --.
  282. return o - out; // option: F4 FF, -- --. is also right
  283. }
  284. // , f3 FF !FF.
  285. fullCount = 4; // , f4 -- xx.
  286. OUT_fullSigil // F4, -- xx.
  287. goto lastByte;
  288. }
  289. if (reptCount == 1) { // , r1 aa yy.
  290. ASSERT(zeroCount == 0)
  291. ASSERT(fullCount == 0)
  292. ASSERT(b_1 != 0)
  293. ASSERT(b_1 != 0xFF)
  294. if (b_1 == b) { // , r1 aa aa.
  295. OUTB(b_1) // aa, r1 -- aa.
  296. ASSERT(offset <= 31);
  297. if (offset > 7) {
  298. *o++ = N | offset;
  299. offset = 0;
  300. }
  301. *o++ = R2 | offset; // aa R2, -- --.
  302. return o - out;
  303. }
  304. OUTB(b_1) // aa, r0 aa -- yy.
  305. OUTB(b_1) // aa aa, -- yy.
  306. goto lastByte;
  307. }
  308. if (reptCount == 2) { // , r2 aa yy.
  309. ASSERT(zeroCount == 0)
  310. ASSERT(fullCount == 0)
  311. ASSERT(b_1 != 0)
  312. ASSERT(b_1 != 0xFF)
  313. if (b_1 == b) { // , r2 aa aa.
  314. OUTB(b_1) // aa, r2 -- aa.
  315. ASSERT(offset <= 31);
  316. if (offset > 7) {
  317. *o++ = N | offset;
  318. offset = 0;
  319. }
  320. *o++ = R3 | offset; // aa R3, -- --.
  321. return o - out;
  322. }
  323. OUTB(b_1) // aa, r2 -- yy.
  324. OUT_reptSigil // aa R2, -- xx.
  325. goto lastByte;
  326. }
  327. if (reptCount == 3) { // , r3 aa yy.
  328. ASSERT(zeroCount == 0)
  329. ASSERT(fullCount == 0)
  330. ASSERT(b_1 != 0)
  331. ASSERT(b_1 != 0xFF)
  332. OUTB(b_1) // aa, r3 -- yy.
  333. if (b_1 == b) { // , r3 aa aa.
  334. ASSERT(offset <= 31);
  335. if (offset > 7) {
  336. *o++ = N | offset;
  337. offset = 0;
  338. }
  339. *o++ = R4 | offset; // aa R4, -- --.
  340. return o - out;
  341. }
  342. // aa, r3 -- yy.
  343. OUT_reptSigil // aa R3, -- xx.
  344. goto lastByte;
  345. }
  346. ASSERT(0) // will not be reached
  347. }
  348. }
  349. }
  350. if (length == 0) { // , -- --.
  351. return 0;
  352. }
  353. if (length == 1) { // , . xx
  354. b = *i; // , -- xx.
  355. goto lastByte;
  356. }
  357. lastByte: // , -- xx.
  358. if (b == 0) { // , -- 00.
  359. ASSERT(offset <= 31);
  360. *o++ = Z1 | offset; // Z1, -- --.
  361. return o - out;
  362. } else { // , -- aa.
  363. *o++ = b; // aa|ff, -- --.
  364. offset++;
  365. ASSERT(offset <= 31);
  366. *o++ = N | offset; // aa Nn, -- --.
  367. return o - out;
  368. }
  369. }