aboutsummaryrefslogtreecommitdiff
path: root/src/blocks/lzssblock.nim
blob: b23cee2662b79d5f24b747916e1582840033d9f0 (plain)
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)