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)) |
