1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
# gzip-like LZSS compressor
# Copyright (C) 2018 Pacien TRAN-GIRARD
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import lists
import ../bitio/integers, ../bitio/bitreader, ../bitio/bitwriter
import ../lzss/lzsschain, ../lzss/lzssencoder
import ../huffman/huffmantree, ../huffman/huffmantreebuilder, ../huffman/huffmanencoder, ../huffman/huffmandecoder
import ../lzsshuffman/lzsshuffmanstats, ../lzsshuffman/lzsshuffmandecoder, ../lzsshuffman/lzsshuffmanencoder
const maxDataByteLength = 32_000
type LzssBlock* = object
lzssChain: LzssChain
proc readSerialised*(bitReader: BitReader): LzssBlock =
let symbolHuffmanTree = huffmantree.deserialise(bitReader, uint16)
let positionHuffmanTree = huffmantree.deserialise(bitReader, uint16)
let symbolDecoder = symbolHuffmanTree.decoder()
let positionDecoder = positionHuffmanTree.decoder()
LzssBlock(lzssChain: readChain(bitReader, symbolDecoder, positionDecoder, maxDataByteLength))
proc writeSerialisedTo*(lzssBlock: LzssBlock, bitWriter: BitWriter) =
let (symbolStats, positionStats) = aggregateStats(lzssBlock.lzssChain)
let symbolHuffmanTree = buildHuffmanTree(symbolStats)
let positionHuffmanTree = buildHuffmanTree(positionStats)
let symbolEncoder = symbolHuffmanTree.encoder(uint16)
let positionEncoder = positionHuffmanTree.encoder(uint16)
symbolHuffmanTree.serialise(bitWriter)
positionHuffmanTree.serialise(bitWriter)
lzssBlock.lzssChain.writeChain(symbolEncoder, positionEncoder, bitWriter)
proc readRaw*(bitReader: BitReader): LzssBlock =
let byteBuf = bitReader.readSeq(maxDataByteLength, uint8)
LzssBlock(lzssChain: lzssEncode(byteBuf.data))
proc writeRawTo*(lzssBlock: LzssBlock, bitWriter: BitWriter) =
let byteSeq = lzssBlock.lzssChain.decode()
bitWriter.writeSeq(byteSeq.len * wordBitLength, byteSeq)
|