dictbuf.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*++
  2. Copyright (c) Alex Ionescu. All rights reserved.
  3. Module Name:
  4. dictbuf.c
  5. Abstract:
  6. This module implements the management of the LZMA "history buffer" which is
  7. often called the "dictionary". Routines for writing into the history buffer
  8. as well as for reading back from it are implemented, as well as mechanisms
  9. for repeating previous symbols forward into the dictionary. This forms the
  10. basis for LZMA match distance-length pairs that are found and decompressed.
  11. Note that for simplicity's sake, the dictionary is stored directly in the
  12. output buffer, such that no "flushing" or copying is needed back and forth.
  13. Author:
  14. Alex Ionescu (@aionescu) 15-Apr-2020 - Initial version
  15. Environment:
  16. Windows & Linux, user mode and kernel mode.
  17. --*/
  18. #include "minlzlib.h"
  19. //
  20. // State used for the history buffer (dictionary)
  21. //
  22. typedef struct _DICTIONARY_STATE
  23. {
  24. //
  25. // Buffer, start position, current position, and offset limit in the buffer
  26. //
  27. uint8_t* Buffer;
  28. uint32_t BufferSize;
  29. uint32_t Start;
  30. uint32_t Offset;
  31. uint32_t Limit;
  32. } DICTIONARY_STATE, *PDICTIONARY_STATE;
  33. DICTIONARY_STATE Dictionary;
  34. void
  35. DtInitialize (
  36. uint8_t* HistoryBuffer,
  37. uint32_t Size,
  38. uint32_t Offset
  39. )
  40. {
  41. //
  42. // Initialize the buffer and reset the position
  43. //
  44. Dictionary.Buffer = HistoryBuffer;
  45. Dictionary.Offset = Offset;
  46. Dictionary.BufferSize = Size;
  47. }
  48. bool
  49. DtSetLimit (
  50. uint32_t Limit
  51. )
  52. {
  53. //
  54. // Make sure that the passed in dictionary limit fits within the size, and
  55. // then set this as the new limit. Save the starting point (current offset)
  56. //
  57. if ((Dictionary.Offset + Limit) > Dictionary.BufferSize)
  58. {
  59. return false;
  60. }
  61. Dictionary.Limit = Dictionary.Offset + Limit;
  62. Dictionary.Start = Dictionary.Offset;
  63. return true;
  64. }
  65. bool
  66. DtIsComplete (
  67. uint32_t* BytesProcessed
  68. )
  69. {
  70. //
  71. // Return bytes processed and if the dictionary has been fully written to
  72. //
  73. *BytesProcessed = Dictionary.Offset - Dictionary.Start;
  74. return (Dictionary.Offset == Dictionary.Limit);
  75. }
  76. bool
  77. DtCanWrite (
  78. uint32_t* Position
  79. )
  80. {
  81. //
  82. // Return our position and make sure it's not beyond the uncompressed size
  83. //
  84. *Position = Dictionary.Offset;
  85. return (Dictionary.Offset < Dictionary.Limit);
  86. }
  87. uint8_t
  88. DtGetSymbol (
  89. uint32_t Distance
  90. )
  91. {
  92. //
  93. // If the dictionary is still empty, just return 0, otherwise, return the
  94. // symbol that is Distance bytes backward.
  95. //
  96. if (Distance > Dictionary.Offset)
  97. {
  98. return 0;
  99. }
  100. return Dictionary.Buffer[Dictionary.Offset - Distance];
  101. }
  102. void
  103. DtPutSymbol (
  104. uint8_t Symbol
  105. )
  106. {
  107. //
  108. // Write the symbol and advance our position
  109. //
  110. Dictionary.Buffer[Dictionary.Offset++] = Symbol;
  111. }
  112. bool
  113. DtRepeatSymbol (
  114. uint32_t Length,
  115. uint32_t Distance
  116. )
  117. {
  118. //
  119. // Make sure we never get asked to write past the end of the dictionary. We
  120. // should also not allow the distance to go beyond the current offset since
  121. // DtGetSymbol will return 0 thinking the dictionary is empty.
  122. //
  123. if (((Length + Dictionary.Offset) > Dictionary.Limit) ||
  124. (Distance > Dictionary.Offset))
  125. {
  126. return false;
  127. }
  128. //
  129. // Now rewrite the stream of past symbols forward into the dictionary.
  130. //
  131. do
  132. {
  133. DtPutSymbol(DtGetSymbol(Distance));
  134. } while (--Length > 0);
  135. return true;
  136. }