Huffman.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "CrySystem_precompiled.h"
  9. #include "Huffman.h"
  10. void HuffmanCoder::BitStreamBuilder::AddBits(uint32 value, uint32 numBits)
  11. {
  12. if (numBits > 24)
  13. {
  14. AddBits(static_cast<uint8>((value >> 24) & 0x000000ff), numBits - 24);
  15. numBits = 24;
  16. }
  17. if (numBits > 16)
  18. {
  19. AddBits(static_cast<uint8>((value >> 16) & 0x000000ff), numBits - 16);
  20. numBits = 16;
  21. }
  22. if (numBits > 8)
  23. {
  24. AddBits(static_cast<uint8>((value >> 8) & 0x000000ff), numBits - 8);
  25. numBits = 8;
  26. }
  27. AddBits(static_cast<uint8>(value & 0x000000ff), numBits);
  28. }
  29. void HuffmanCoder::BitStreamBuilder::AddBits(uint8 value, uint32 numBits)
  30. {
  31. if (m_mode != eM_WRITE)
  32. {
  33. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Trying to write to a read only BitStreamBuilder");
  34. return;
  35. }
  36. uint8 mask;
  37. mask = (uint8)(1 << (numBits - 1));
  38. while (mask != 0)
  39. {
  40. //CryLogAlways("mask is %u", mask);
  41. if (mask & value)
  42. {
  43. //CryLogAlways("Buffer value was %u", *m_pBufferCursor.ptr);
  44. *(m_pBufferCursor.ptr) |= m_mask;
  45. //CryLogAlways("Buffer value now %u", *m_pBufferCursor.ptr);
  46. }
  47. //CryLogAlways("m_mask was %u", m_mask);
  48. m_mask = m_mask >> 1;
  49. //CryLogAlways("m_mask now %u", m_mask);
  50. if (m_mask == 0)
  51. {
  52. if (m_pBufferCursor.ptr == m_pBufferEnd.ptr)
  53. {
  54. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Bit Stream has consumed the last byte of the buffer and is requesting another. This stream will be truncated here.");
  55. return;
  56. }
  57. //CryLogAlways("Buffer cursor was %u (%p)", *m_pBufferCursor.ptr, m_pBufferCursor.ptr);
  58. m_pBufferCursor.ptr++;
  59. //CryLogAlways("Buffer cursor now %u (%p)", *m_pBufferCursor.ptr, m_pBufferCursor.ptr);
  60. m_mask = 0x80;
  61. }
  62. mask = mask >> 1L;
  63. }
  64. }
  65. //Returns 1 or 0 for valid values. Returns 2 if the buffer has run out or is the wrong type of builder.
  66. uint8 HuffmanCoder::BitStreamBuilder::GetBit()
  67. {
  68. if (m_mode != eM_READ)
  69. {
  70. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Trying to read from a write only BitStreamBuilder");
  71. return 2;
  72. }
  73. uint8 value = 0;
  74. if (m_mask == 0)
  75. {
  76. if (m_pBufferCursor.const_ptr == m_pBufferEnd.const_ptr)
  77. {
  78. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Bit Stream has consumed the last byte of the buffer and is requesting another. This stream will be truncated here.");
  79. return 2;
  80. }
  81. //CryLogAlways("Buffer cursor was %u (%p)", *m_pBufferCursor.const_ptr, m_pBufferCursor.const_ptr);
  82. m_pBufferCursor.const_ptr++;
  83. //CryLogAlways("Buffer cursor now %u (%p)", *m_pBufferCursor.const_ptr, m_pBufferCursor.const_ptr);
  84. m_mask = 0x80;
  85. }
  86. if (m_mask & *(m_pBufferCursor.const_ptr))
  87. {
  88. value = 1;
  89. }
  90. //CryLogAlways("m_mask was %u", m_mask);
  91. m_mask = m_mask >> 1;
  92. //CryLogAlways("m_mask now %u", m_mask);
  93. return value;
  94. }
  95. void HuffmanCoder::Init()
  96. {
  97. SAFE_DELETE_ARRAY(m_TreeNodes);
  98. SAFE_DELETE_ARRAY(m_Codes);
  99. m_Counts = new uint32[MAX_NUM_SYMBOLS];
  100. memset(m_Counts, 0, sizeof(uint32) * MAX_NUM_SYMBOLS);
  101. m_State = eHCS_OPEN;
  102. }
  103. //Adds the values of an array of chars to the counts
  104. void HuffmanCoder::Update(const uint8* const pSource, const size_t numBytes)
  105. {
  106. if (m_State != eHCS_OPEN)
  107. {
  108. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Trying to update a Huffman Coder that has not been initialized, or has been finalized");
  109. return;
  110. }
  111. size_t i;
  112. for (i = 0; i < numBytes; i++)
  113. {
  114. const int symbol = pSource[i];
  115. m_Counts[symbol]++;
  116. }
  117. }
  118. void HuffmanCoder::Finalize()
  119. {
  120. if (m_State != eHCS_OPEN)
  121. {
  122. CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Trying to finalize a Huffman Coder that has not been initialized, or has been finalized");
  123. return;
  124. }
  125. //Construct the tree
  126. m_TreeNodes = new HuffmanTreeNode[MAX_NUM_NODES];
  127. memset(m_TreeNodes, 0, sizeof(HuffmanTreeNode) * MAX_NUM_NODES);
  128. m_Codes = new HuffmanSymbolCode[MAX_NUM_CODES];
  129. memset(m_Codes, 0, sizeof(HuffmanSymbolCode) * MAX_NUM_CODES);
  130. ScaleCountsAndUpdateNodes();
  131. m_RootNode = BuildTree();
  132. ConvertTreeToCode(m_TreeNodes, m_Codes, 0, 0, m_RootNode);
  133. //Finalize the coder so that it won't accept any more strings
  134. m_State = eHCS_FINAL;
  135. //Counts are no longer needed
  136. SAFE_DELETE_ARRAY(m_Counts);
  137. }
  138. void HuffmanCoder::CompressInput(const uint8* const pInput, const size_t numBytes, uint8* const pOutput, size_t* const outputSize)
  139. {
  140. BitStreamBuilder streamBuilder(pOutput, pOutput + (*outputSize));
  141. for (size_t i = 0; i < numBytes; i++)
  142. {
  143. const int symbol = pInput[i];
  144. const uint32 value = m_Codes[symbol].value;
  145. const uint32 numBits = m_Codes[symbol].numBits;
  146. /*char szBits[33];
  147. memset(szBits, '0', 33);
  148. for( uint32 j = 0; j < numBits; j++ )
  149. {
  150. if( (value & (uint32)(1<<j)) != 0 )
  151. {
  152. szBits[31-j] = '1';
  153. }
  154. else
  155. {
  156. szBits[31-j] = '0';
  157. }
  158. }
  159. szBits[32] = 0;
  160. CryLogAlways("%c - %s (%u)", value, szBits, numBits);*/
  161. streamBuilder.AddBits(value, numBits);
  162. }
  163. streamBuilder.AddBits(m_Codes[END_OF_STREAM].value, m_Codes[END_OF_STREAM].numBits);
  164. *outputSize = (streamBuilder.m_pBufferCursor.ptr - streamBuilder.m_pBufferStart.ptr) + 1;
  165. }
  166. size_t HuffmanCoder::UncompressInput(const uint8* const pInput, const size_t numBytes, uint8* const pOutput, const size_t maxOutputSize)
  167. {
  168. size_t numOutputBytes = 0;
  169. BitStreamBuilder streamBuilder(pInput, pInput + numBytes);
  170. while (1)
  171. {
  172. int code;
  173. int node = m_RootNode;
  174. do
  175. {
  176. uint8 bitValue = streamBuilder.GetBit();
  177. #if 0
  178. CryLogAlways("bit=%ld\n", bitValue);
  179. #endif
  180. if (bitValue == 0)
  181. {
  182. node = m_TreeNodes[node].child0;
  183. }
  184. else
  185. {
  186. node = m_TreeNodes[node].child1;
  187. }
  188. } while (node > END_OF_STREAM);
  189. if (node == END_OF_STREAM)
  190. {
  191. pOutput[numOutputBytes] = '\0';
  192. break;
  193. }
  194. code = node;
  195. #if 0
  196. {
  197. CryLogAlways("%c", code);
  198. if (code == '\0')
  199. {
  200. CryLogAlways("EOM");
  201. }
  202. }
  203. #endif
  204. pOutput[numOutputBytes] = (char)code;
  205. numOutputBytes++;
  206. if (numOutputBytes >= maxOutputSize)
  207. {
  208. pOutput[maxOutputSize - 1] = '\0';
  209. break;
  210. }
  211. }
  212. return numOutputBytes;
  213. }
  214. //Private functions
  215. void HuffmanCoder::ScaleCountsAndUpdateNodes()
  216. {
  217. unsigned long maxCount = 0;
  218. int i;
  219. for (i = 0; i < MAX_NUM_SYMBOLS; i++)
  220. {
  221. const unsigned long count = m_Counts[i];
  222. if (count > maxCount)
  223. {
  224. maxCount = count;
  225. }
  226. }
  227. if (maxCount == 0)
  228. {
  229. m_Counts[0] = 1;
  230. maxCount = 1;
  231. }
  232. maxCount = maxCount / MAX_NUM_SYMBOLS;
  233. maxCount = maxCount + 1;
  234. for (i = 0; i < MAX_NUM_SYMBOLS; i++)
  235. {
  236. const unsigned long count = m_Counts[i];
  237. unsigned int scaledCount = (unsigned int)(count / maxCount);
  238. if ((scaledCount == 0) && (count != 0))
  239. {
  240. scaledCount = 1;
  241. }
  242. m_TreeNodes[i].count = scaledCount;
  243. m_TreeNodes[i].child0 = END_OF_STREAM;
  244. m_TreeNodes[i].child1 = END_OF_STREAM;
  245. }
  246. m_TreeNodes[END_OF_STREAM].count = 1;
  247. m_TreeNodes[END_OF_STREAM].child0 = END_OF_STREAM;
  248. m_TreeNodes[END_OF_STREAM].child1 = END_OF_STREAM;
  249. }
  250. //Jake's file IO code. Kept in case we make the compression and table generation an offline task
  251. /* Format is: startSymbol, stopSymbol, count0, count1, count2, ... countN, ..., 0 */
  252. /* When finding the start, stop symbols only break out if find more than 3 0's in the counts */
  253. /*static void outputCounts(FILE* const pFile, const HuffmanTreeNode* const pNodes)
  254. {
  255. int first = 0;
  256. int last;
  257. int next;
  258. while ((first < MAX_NUM_SYMBOLS) && (pNodes[first].count == 0))
  259. {
  260. first++;
  261. }
  262. last = first;
  263. next = first;
  264. for (; first < MAX_NUM_SYMBOLS; first = next)
  265. {
  266. int i;
  267. last = first+1;
  268. while (1)
  269. {
  270. for (; last < MAX_NUM_SYMBOLS; last++)
  271. {
  272. if (pNodes[last].count == 0)
  273. {
  274. break;
  275. }
  276. }
  277. last--;
  278. for (next = last+1; next < MAX_NUM_SYMBOLS; next++)
  279. {
  280. if (pNodes[next].count != 0)
  281. {
  282. break;
  283. }
  284. }
  285. if (next == MAX_NUM_SYMBOLS)
  286. {
  287. break;
  288. }
  289. if ((next-last) > 3)
  290. {
  291. break;
  292. }
  293. last = next;
  294. }
  295. putc(first, pFile);
  296. putc(last, pFile);
  297. for (i = first; i <= last; i++)
  298. {
  299. const unsigned int count = pNodes[i].count;
  300. putc((int)count, pFile);
  301. }
  302. }
  303. putc(0xFF, pFile);
  304. putc(0xFF, pFile);
  305. putc((int)(pNodes[0xFF].count), pFile);
  306. }*/
  307. /*static void inputCounts(FILE* const pFile, HuffmanTreeNode* const pNodes)
  308. {
  309. while (1)
  310. {
  311. int i;
  312. const int first = getc(pFile);
  313. const int last = getc(pFile);
  314. for (i = first; i <= last; i++)
  315. {
  316. const int count = getc(pFile);
  317. pNodes[i].count = (size_t)count;
  318. pNodes[i].child0 = END_OF_STREAM;
  319. pNodes[i].child1 = END_OF_STREAM;
  320. }
  321. if ((first == last) && (first == 0xFF))
  322. {
  323. break;
  324. }
  325. }
  326. pNodes[END_OF_STREAM].count = 1;
  327. pNodes[END_OF_STREAM].child0 = END_OF_STREAM;
  328. pNodes[END_OF_STREAM].child1 = END_OF_STREAM;
  329. }*/
  330. int HuffmanCoder::BuildTree()
  331. {
  332. int min1;
  333. int min2;
  334. int nextFree;
  335. m_TreeNodes[MAX_NODE].count = 0xFFFFFFF;
  336. for (nextFree = END_OF_STREAM + 1;; nextFree++)
  337. {
  338. int i;
  339. min1 = MAX_NODE;
  340. min2 = MAX_NODE;
  341. for (i = 0; i < nextFree; i++)
  342. {
  343. const unsigned int count = m_TreeNodes[i].count;
  344. if (count != 0)
  345. {
  346. if (count < m_TreeNodes[min1].count)
  347. {
  348. min2 = min1;
  349. min1 = i;
  350. }
  351. else if (count < m_TreeNodes[min2].count)
  352. {
  353. min2 = i;
  354. }
  355. }
  356. }
  357. if (min2 == MAX_NODE)
  358. {
  359. break;
  360. }
  361. m_TreeNodes[nextFree].count = m_TreeNodes[min1].count + m_TreeNodes[min2].count;
  362. m_TreeNodes[min1].savedCount = m_TreeNodes[min1].count;
  363. m_TreeNodes[min1].count = 0;
  364. m_TreeNodes[min2].savedCount = m_TreeNodes[min2].count;
  365. m_TreeNodes[min2].count = 0;
  366. m_TreeNodes[nextFree].child0 = min1;
  367. m_TreeNodes[nextFree].child1 = min2;
  368. m_TreeNodes[nextFree].savedCount = 0;
  369. }
  370. nextFree--;
  371. m_TreeNodes[nextFree].savedCount = m_TreeNodes[nextFree].count;
  372. return nextFree;
  373. }
  374. void HuffmanCoder::ConvertTreeToCode(const HuffmanTreeNode* const pNodes, HuffmanSymbolCode* const pCodes,
  375. const unsigned int value, const unsigned int numBits, const int node)
  376. {
  377. unsigned int nextValue;
  378. unsigned int nextNumBits;
  379. if (node <= END_OF_STREAM)
  380. {
  381. pCodes[node].value = value;
  382. pCodes[node].numBits = numBits;
  383. return;
  384. }
  385. nextValue = value << 1;
  386. nextNumBits = numBits + 1;
  387. ConvertTreeToCode(pNodes, pCodes, nextValue, nextNumBits, pNodes[node].child0);
  388. nextValue = nextValue | 0x1;
  389. ConvertTreeToCode(pNodes, pCodes, nextValue, nextNumBits, pNodes[node].child1);
  390. }
  391. /*static void printChar(const int c)
  392. {
  393. if (c >= ' ' && c < 127)
  394. {
  395. printf("'%c'", c);
  396. }
  397. else
  398. {
  399. printf("0x%03X", c);
  400. }
  401. }
  402. static void printModel(const HuffmanTreeNode* const pNodes, const HuffmanSymbolCode* const pCodes)
  403. {
  404. int i;
  405. for (i = 0; i < MAX_NODE; i++)
  406. {
  407. const unsigned int count = pNodes[i].savedCount;
  408. if (count != 0)
  409. {
  410. printf("node=");
  411. printChar(i);
  412. printf(" count=%3d", count);
  413. printf(" child0=");
  414. printChar(pNodes[i].child0);
  415. printf(" child1=");
  416. printChar(pNodes[i].child1);
  417. if (pCodes && (i <= END_OF_STREAM))
  418. {
  419. printf(" Huffman code=");
  420. binaryFilePrint(stdout, pCodes[i].value, pCodes[i].numBits);
  421. }
  422. printf("\n");
  423. }
  424. }
  425. }*/