summaryrefslogtreecommitdiff
path: root/tools/src/minilzlib/dictbuf.c
diff options
context:
space:
mode:
authormagh <magh@maghmogh.com>2023-03-06 18:44:55 -0600
committermagh <magh@maghmogh.com>2023-03-06 18:44:55 -0600
commite80d9d8871b325a04b18f90a9ea4bb7fd148fb25 (patch)
tree79dbdb8506b7ff1e92549188d1b94cfc0b3503ae /tools/src/minilzlib/dictbuf.c
add m1n1HEADmaster
Diffstat (limited to 'tools/src/minilzlib/dictbuf.c')
-rw-r--r--tools/src/minilzlib/dictbuf.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/tools/src/minilzlib/dictbuf.c b/tools/src/minilzlib/dictbuf.c
new file mode 100644
index 0000000..02875dc
--- /dev/null
+++ b/tools/src/minilzlib/dictbuf.c
@@ -0,0 +1,155 @@
+/*++
+
+Copyright (c) Alex Ionescu. All rights reserved.
+
+Module Name:
+
+ dictbuf.c
+
+Abstract:
+
+ This module implements the management of the LZMA "history buffer" which is
+ often called the "dictionary". Routines for writing into the history buffer
+ as well as for reading back from it are implemented, as well as mechanisms
+ for repeating previous symbols forward into the dictionary. This forms the
+ basis for LZMA match distance-length pairs that are found and decompressed.
+ Note that for simplicity's sake, the dictionary is stored directly in the
+ output buffer, such that no "flushing" or copying is needed back and forth.
+
+Author:
+
+ Alex Ionescu (@aionescu) 15-Apr-2020 - Initial version
+
+Environment:
+
+ Windows & Linux, user mode and kernel mode.
+
+--*/
+
+#include "minlzlib.h"
+
+//
+// State used for the history buffer (dictionary)
+//
+typedef struct _DICTIONARY_STATE
+{
+ //
+ // Buffer, start position, current position, and offset limit in the buffer
+ //
+ uint8_t* Buffer;
+ uint32_t BufferSize;
+ uint32_t Start;
+ uint32_t Offset;
+ uint32_t Limit;
+} DICTIONARY_STATE, *PDICTIONARY_STATE;
+DICTIONARY_STATE Dictionary;
+
+void
+DtInitialize (
+ uint8_t* HistoryBuffer,
+ uint32_t Size
+ )
+{
+ //
+ // Initialize the buffer and reset the position
+ //
+ Dictionary.Buffer = HistoryBuffer;
+ Dictionary.Offset = 0;
+ Dictionary.BufferSize = Size;
+}
+
+bool
+DtSetLimit (
+ uint32_t Limit
+ )
+{
+ //
+ // Make sure that the passed in dictionary limit fits within the size, and
+ // then set this as the new limit. Save the starting point (current offset)
+ //
+ if ((Dictionary.Offset + Limit) > Dictionary.BufferSize)
+ {
+ return false;
+ }
+ Dictionary.Limit = Dictionary.Offset + Limit;
+ Dictionary.Start = Dictionary.Offset;
+ return true;
+}
+
+bool
+DtIsComplete (
+ uint32_t* BytesProcessed
+ )
+{
+ //
+ // Return bytes processed and if the dictionary has been fully written to
+ //
+ *BytesProcessed = Dictionary.Offset - Dictionary.Start;
+ return (Dictionary.Offset == Dictionary.Limit);
+}
+
+bool
+DtCanWrite (
+ uint32_t* Position
+ )
+{
+ //
+ // Return our position and make sure it's not beyond the uncompressed size
+ //
+ *Position = Dictionary.Offset;
+ return (Dictionary.Offset < Dictionary.Limit);
+}
+
+uint8_t
+DtGetSymbol (
+ uint32_t Distance
+ )
+{
+ //
+ // If the dictionary is still empty, just return 0, otherwise, return the
+ // symbol that is Distance bytes backward.
+ //
+ if (Distance > Dictionary.Offset)
+ {
+ return 0;
+ }
+ return Dictionary.Buffer[Dictionary.Offset - Distance];
+}
+
+void
+DtPutSymbol (
+ uint8_t Symbol
+ )
+{
+ //
+ // Write the symbol and advance our position
+ //
+ Dictionary.Buffer[Dictionary.Offset++] = Symbol;
+}
+
+bool
+DtRepeatSymbol (
+ uint32_t Length,
+ uint32_t Distance
+ )
+{
+ //
+ // Make sure we never get asked to write past the end of the dictionary. We
+ // should also not allow the distance to go beyond the current offset since
+ // DtGetSymbol will return 0 thinking the dictionary is empty.
+ //
+ if (((Length + Dictionary.Offset) > Dictionary.Limit) ||
+ (Distance > Dictionary.Offset))
+ {
+ return false;
+ }
+
+ //
+ // Now rewrite the stream of past symbols forward into the dictionary.
+ //
+ do
+ {
+ DtPutSymbol(DtGetSymbol(Distance));
+ } while (--Length > 0);
+ return true;
+}