Mercurial > games > semicongine
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)) |