comparison semicongine/thirdparty/zippy/zippy.nim @ 1123:657bb0b2af45

add: thirdparty libraries into repo
author sam <sam@basx.dev>
date Sat, 27 Apr 2024 22:04:30 +0700
parents
children
comparison
equal deleted inserted replaced
1121:21690a5aa280 1123:657bb0b2af45
1 import zippy/adler32, zippy/common, zippy/crc, zippy/deflate,
2 zippy/gzip, zippy/inflate, zippy/internal
3
4 when (NimMajor, NimMinor, NimPatch) >= (1, 6, 0):
5 import std/sysrand
6 else:
7 import std/random, std/times
8
9 export common
10
11 proc compress*(
12 src: pointer,
13 len: int,
14 level = DefaultCompression,
15 dataFormat = dfGzip
16 ): string {.raises: [ZippyError].} =
17 ## Compresses src and returns the compressed data.
18 let src = cast[ptr UncheckedArray[uint8]](src)
19
20 case dataFormat:
21 of dfGzip:
22 result.setLen(10)
23 result[0] = 31.char
24 result[1] = 139.char
25 result[2] = 8.char
26 result[3] = (1.uint8 shl 3).char # Set the fname flag
27
28 block: # https://github.com/guzba/zippy/issues/61
29 let htbLen =
30 when (NimMajor, NimMinor, NimPatch) >= (1, 6, 0):
31 var urand: array[1, uint8]
32 if not urandom(urand):
33 raise newException(ZippyError, "Failed to generate random number")
34 (urand[0] mod 26).int
35 else:
36 let now = getTime()
37 var rand = initRand(now.toUnix * 1_000_000_000 + now.nanosecond)
38 (rand.next() mod 26).int # mod the uint first to ensure a positive int
39 # Add up to 26 characters as the gzip header file name
40 for i in 0 ..< htbLen:
41 result.add (97 + i).char
42 result.add '\0'
43
44 deflate(result, src, len, level)
45
46 let
47 checksum = crc32(src, len)
48 isize = len
49
50 result.add(((checksum shr 0) and 255).char)
51 result.add(((checksum shr 8) and 255).char)
52 result.add(((checksum shr 16) and 255).char)
53 result.add(((checksum shr 24) and 255).char)
54
55 result.add(((isize shr 0) and 255).char)
56 result.add(((isize shr 8) and 255).char)
57 result.add(((isize shr 16) and 255).char)
58 result.add(((isize shr 24) and 255).char)
59
60 of dfZlib:
61 const
62 cm = 8.uint8
63 cinfo = 7.uint8
64 cmf = (cinfo shl 4) or cm
65 fcheck = (31.uint32 - (cmf.uint32 * 256) mod 31).uint8
66
67 result.setLen(2)
68 result[0] = cmf.char
69 result[1] = fcheck.char
70
71 deflate(result, src, len, level)
72
73 let checksum = adler32(src, len)
74
75 result.add(((checksum shr 24) and 255).char)
76 result.add(((checksum shr 16) and 255).char)
77 result.add(((checksum shr 8) and 255).char)
78 result.add(((checksum shr 0) and 255).char)
79
80 of dfDeflate:
81 deflate(result, src, len, level)
82
83 else:
84 raise newException(ZippyError, "Invalid data format " & $dfDetect)
85
86 proc compress*(
87 src: string,
88 level = DefaultCompression,
89 dataFormat = dfGzip
90 ): string {.raises: [ZippyError].} =
91 compress(src.cstring, src.len, level, dataFormat)
92
93 proc compress*(
94 src: seq[uint8],
95 level = DefaultCompression,
96 dataFormat = dfGzip
97 ): seq[uint8] {.raises: [ZippyError].} =
98 cast[seq[uint8]](compress(cast[string](src).cstring, src.len, level, dataFormat))
99
100 proc uncompress*(
101 src: pointer,
102 len: int,
103 dataFormat = dfDetect
104 ): string {.raises: [ZippyError].} =
105 ## Uncompresses src and returns the uncompressed data.
106 let src = cast[ptr UncheckedArray[uint8]](src)
107
108 case dataFormat:
109 of dfDetect:
110 if (
111 len > 18 and
112 src[0].uint8 == 31 and src[1].uint8 == 139 and src[2].uint8 == 8 and
113 (src[3].uint8 and 0b11100000) == 0
114 ):
115 return uncompress(src, len, dfGzip)
116
117 if (
118 len > 6 and
119 (src[0].uint8 and 0b00001111) == 8 and
120 (src[0].uint8 shr 4) <= 7 and
121 ((src[0].uint16 * 256) + src[1].uint8) mod 31 == 0
122 ):
123 return uncompress(src, len, dfZlib)
124
125 raise newException(ZippyError, "Unable to detect compressed data format")
126
127 of dfGzip:
128 uncompressGzip(result, src, len)
129
130 of dfZlib:
131 if len < 6:
132 failUncompress()
133
134 let
135 cmf = src[0].uint8
136 flg = src[1].uint8
137 cm = cmf and 0b00001111
138 cinfo = cmf shr 4
139
140 if cm != 8: # DEFLATE
141 raise newException(ZippyError, "Unsupported compression method")
142
143 if cinfo > 7.uint8:
144 raise newException(ZippyError, "Invalid compression info")
145
146 if ((cmf.uint16 * 256) + flg.uint16) mod 31 != 0:
147 raise newException(ZippyError, "Invalid header")
148
149 if (flg and 0b00100000) != 0: # FDICT
150 raise newException(ZippyError, "Preset dictionary is not yet supported")
151
152 inflate(result, src, len, 2)
153
154 let checksum = (
155 src[len - 4].uint32 shl 24 or
156 src[len - 3].uint32 shl 16 or
157 src[len - 2].uint32 shl 8 or
158 src[len - 1].uint32
159 )
160
161 if checksum != adler32(result):
162 raise newException(ZippyError, "Checksum verification failed")
163
164 of dfDeflate:
165 inflate(result, src, len, 0)
166
167 proc uncompress*(
168 src: string,
169 dataFormat = dfDetect
170 ): string {.raises: [ZippyError].} =
171 uncompress(src.cstring, src.len, dataFormat)
172
173 proc uncompress*(
174 src: seq[uint8],
175 dataFormat = dfDetect
176 ): seq[uint8] {.raises: [ZippyError].} =
177 cast[seq[uint8]](uncompress(cast[string](src).cstring, src.len, dataFormat))