Skip to content
This repository was archived by the owner on Oct 10, 2023. It is now read-only.

Commit 7fdd627

Browse files
committed
Initial commit
0 parents  commit 7fdd627

14 files changed

+472
-0
lines changed

.editorconfig

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = tab
6+
indent_size = 4
7+
insert_final_newline = true
8+
end_of_line = lf
9+
10+
[*.{yml,yaml}]
11+
indent_style = space
12+
indent_size = 2

.github/.templateMarker

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
KOLANICH/python_project_boilerplate.py

.github/dependabot.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "daily"
7+
allow:
8+
- dependency-type: "all"

.github/workflows/CI.yml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: CI
2+
on:
3+
push:
4+
branches: [master]
5+
pull_request:
6+
branches: [master]
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-22.04
11+
steps:
12+
- name: typical python workflow
13+
uses: KOLANICH-GHActions/typical-python-workflow@master
14+
with:
15+
github_token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
__pycache__
2+
*.pyc
3+
*.pyo
4+
/*.egg-info
5+
*.srctrlbm
6+
*.srctrldb
7+
build
8+
dist
9+
.eggs
10+
monkeytype.sqlite3
11+
/.ipynb_checkpoints

.gitlab-ci.yml

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
image: registry.gitlab.com/kolanich-subgroups/docker-images/fixed_python:latest
2+
3+
variables:
4+
DOCKER_DRIVER: overlay2
5+
SAST_ANALYZER_IMAGE_TAG: latest
6+
SAST_DISABLE_DIND: "true"
7+
SAST_CONFIDENCE_LEVEL: 5
8+
CODECLIMATE_VERSION: latest
9+
10+
include:
11+
- template: SAST.gitlab-ci.yml
12+
- template: Code-Quality.gitlab-ci.yml
13+
- template: License-Management.gitlab-ci.yml
14+
15+
build:
16+
tags:
17+
- shared
18+
- linux
19+
stage: build
20+
variables:
21+
GIT_DEPTH: "1"
22+
PYTHONUSERBASE: ${CI_PROJECT_DIR}/python_user_packages
23+
24+
before_script:
25+
- export PATH="$PATH:$PYTHONUSERBASE/bin" # don't move into `variables`
26+
- apt-get update
27+
# todo:
28+
#- apt-get -y install
29+
#- pip3 install --upgrade
30+
#- python3 ./fix_python_modules_paths.py
31+
32+
script:
33+
- python3 -m build -nw bdist_wheel
34+
- mv ./dist/*.whl ./dist/pklib_base-0.CI-py3-none-any.whl
35+
- pip3 install --upgrade ./dist/*.whl
36+
- coverage run --source=pklib_base -m --branch pytest --junitxml=./rspec.xml ./tests/test.py
37+
- coverage report -m
38+
- coverage xml
39+
40+
coverage: /^TOTAL(?:\s+\d+){4}\s+(\d+%).+/
41+
42+
cache:
43+
paths:
44+
- $PYTHONUSERBASE
45+
46+
artifacts:
47+
paths:
48+
- dist
49+
reports:
50+
junit: ./rspec.xml
51+
cobertura: ./coverage.xml

Code_Of_Conduct.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No codes of conduct!

MANIFEST.in

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include UNLICENSE
2+
include *.md
3+
include tests
4+
include .editorconfig

ReadMe.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pklib_base.py [![Unlicensed work](https://raw.githubusercontent.com/unlicense/unlicense.org/master/static/favicon.png)](https://unlicense.org/)
2+
===============
3+
~~[wheel (GitLab)](https://gitlab.com/implode-implode-compression-impls/pklib_base.py/-/jobs/artifacts/master/raw/dist/python_project_boilerplate-0.CI-py3-none-any.whl?job=build)~~
4+
~~[wheel (GHA via `nightly.link`)](https://nightly.link/implode-implode-compression-impls/pklib_base.py/workflows/CI/master/python_project_boilerplate-0.CI-py3-none-any.whl)~~
5+
~~![GitLab Build Status](https://gitlab.com/implode-implode-compression-impls/pklib_base.py/badges/master/pipeline.svg)~~
6+
~~![GitLab Coverage](https://gitlab.com/implode-implode-compression-impls/pklib_base.py/badges/master/coverage.svg)~~
7+
~~[![GitHub Actions](https://github.com/implode-implode-compression-impls/pklib_base.py/workflows/CI/badge.svg)](https://github.com/implode-implode-compression-impls/pklib_base.py/actions/)~~
8+
[![Libraries.io Status](https://img.shields.io/librariesio/github/implode-implode-compression-impls/pklib_base.py.svg)](https://libraries.io/github/implode-implode-compression-impls/pklib_base.py)
9+
[![Code style: antiflash](https://img.shields.io/badge/code%20style-antiflash-FFF.svg)](https://codeberg.org/KOLANICH-tools/antiflash.py)
10+
11+
A library with some common code for `pkimplode.py` and `pkexplode.py`.
12+
13+
Also contains functions to read compression stream header.

UNLICENSE

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author or authors
9+
of this software dedicate any and all copyright interest in the
10+
software to the public domain. We make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. We intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to <https://unlicense.org/>

pklib_base/__init__.py

+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
import ctypes
2+
import platform
3+
import typing
4+
from collections.abc import ByteString
5+
from enum import IntEnum
6+
from functools import partial
7+
from io import IOBase
8+
from struct import Struct
9+
from zlib import crc32 as crc32_zlib
10+
11+
from .enums import CompressionType
12+
13+
# pylint:disable=too-few-public-methods
14+
15+
16+
def crc32(data: ByteString, value: int = 0) -> int:
17+
return (~crc32_zlib(data, value)) & 0xFFFFFFF
18+
19+
20+
def decodeHeader(compressed: ByteString):
21+
compressionType = CompressionType(compressed[0])
22+
dictSizeLog = compressed[1]
23+
return compressionType, logIntoSize(dictSizeLog)
24+
25+
26+
def logIntoSize(log: int) -> int:
27+
return 1 << (log + 6)
28+
29+
30+
def maskIntoSize(mask: int) -> int:
31+
return logIntoSize(mask.bit_length())
32+
33+
34+
def dictSizeIntoLog(dictSize: int) -> int:
35+
mask = 0
36+
if dictSize < 128:
37+
raise ValueError("Dict sizes less than 128 are unsupported!")
38+
39+
return (dictSize).bit_length() - 7
40+
41+
42+
def logIntoMask(dictSizeLog: int) -> int:
43+
return (1 << dictSizeLog) - 1
44+
45+
46+
def dictSizeIntoMask(dictSize: int) -> int:
47+
return logIntoMask(dictSizeIntoLog(dictSize))
48+
49+
50+
class PklibError(IntEnum):
51+
ok = CMP_NO_ERROR = 0
52+
invalidDictSize = CMP_INVALID_DICTSIZE = 1
53+
invalidMode = CMP_INVALID_MODE = 2
54+
badData = CMP_BAD_DATA = 3
55+
abort = CMP_ABORT = 4
56+
57+
58+
class CommonSizeConstants:
59+
__slots__ = ("OUT_BUFF_SIZE", "BUFF_SIZE")
60+
61+
def __init__(self, OUT_BUFF_SIZE: int, BUFF_SIZE: int):
62+
self.OUT_BUFF_SIZE = OUT_BUFF_SIZE
63+
self.BUFF_SIZE = BUFF_SIZE
64+
65+
66+
class CommonSizeConstantsCtypes(ctypes.Structure):
67+
__slots__ = CommonSizeConstants.__slots__ + ("ownSize",)
68+
_fields_ = [
69+
("ownSize", ctypes.c_size_t),
70+
("OUT_BUFF_SIZE", ctypes.c_size_t),
71+
("BUFF_SIZE", ctypes.c_size_t),
72+
]
73+
74+
75+
class LUTSizeConstants:
76+
__slots__ = ("DIST_SIZES", "CH_BITS_ASC_SIZE", "LENS_SIZES")
77+
78+
def __init__(self, DIST_SIZES: int, CH_BITS_ASC_SIZE: int, LENS_SIZES: int):
79+
self.DIST_SIZES = DIST_SIZES
80+
self.CH_BITS_ASC_SIZE = CH_BITS_ASC_SIZE
81+
self.LENS_SIZES = LENS_SIZES
82+
83+
84+
class LUTSizeConstantsCtypes(ctypes.Structure):
85+
__slots__ = LUTSizeConstants.__slots__ + ("ownSize",)
86+
_fields_ = [
87+
("ownSize", ctypes.c_size_t),
88+
("DIST_SIZES", ctypes.c_size_t),
89+
("CH_BITS_ASC_SIZE", ctypes.c_size_t),
90+
("LENS_SIZES", ctypes.c_size_t),
91+
]
92+
93+
94+
specializedSizeConstantsHeader = (("ownSize", ctypes.c_size_t),)
95+
96+
97+
def parseCommonSizeConstants(commonSizes: CommonSizeConstantsCtypes) -> CommonSizeConstants:
98+
if int(commonSizes.ownSize) != ctypes.sizeof(CommonSizeConstantsCtypes):
99+
raise ValueError("CommonSizeConstantsCtypes contents has changed!", commonSizes.ownSize, ctypes.sizeof(CommonSizeConstantsCtypes))
100+
101+
return CommonSizeConstants(int(commonSizes.OUT_BUFF_SIZE), int(commonSizes.BUFF_SIZE))
102+
103+
104+
def _getSizeConstants1(lib, funcName, resCtypesType, resInternalType, parserFunc):
105+
getSpecializedSizeConstantsT = getattr(lib, funcName)
106+
getSpecializedSizeConstantsT.argtypes = []
107+
getSpecializedSizeConstantsT.restype = resCtypesType
108+
sizeConstants = getSpecializedSizeConstantsT()
109+
110+
return parserFunc(sizeConstants)
111+
112+
113+
def getCommonSizeConstants(lib):
114+
return _getSizeConstants1(lib, "getCommonSizeConstants", CommonSizeConstantsCtypes, CommonSizeConstants, parseCommonSizeConstants)
115+
116+
117+
def parseLUTSizeConstants(lutsSizes: LUTSizeConstantsCtypes) -> LUTSizeConstants:
118+
if int(lutsSizes.ownSize) != ctypes.sizeof(LUTSizeConstantsCtypes):
119+
raise ValueError("LUTSizeConstantsCtypes contents has changed!", lutsSizes.ownSize, ctypes.sizeof(LUTSizeConstantsCtypes))
120+
121+
return LUTSizeConstants(int(lutsSizes.DIST_SIZES), int(lutsSizes.CH_BITS_ASC_SIZE), int(lutsSizes.LENS_SIZES))
122+
123+
124+
def getLUTSizeConstants(lib):
125+
return _getSizeConstants1(lib, "getLUTSizeConstants", LUTSizeConstantsCtypes, LUTSizeConstants, parseLUTSizeConstants)
126+
127+
128+
def inputCallbackStream(inputStream: IOBase, buf: ctypes.POINTER(ctypes.c_char_p), chunkSize: ctypes.POINTER(ctypes.c_uint), param: ctypes.POINTER(None)) -> ctypes.c_uint: # pylint:disable=unused-argument
129+
bufT = ctypes.c_byte * chunkSize[0]
130+
bufPtrT = ctypes.POINTER(bufT)
131+
bufArrPtr = ctypes.cast(buf, bufPtrT)
132+
133+
countRead = inputStream.readinto(bufArrPtr[0])
134+
return countRead
135+
136+
137+
def outputCallbackStream(outputStream: IOBase, buf: ctypes.POINTER(ctypes.c_char_p), chunkSize: ctypes.POINTER(ctypes.c_uint), param: ctypes.POINTER(None)) -> None: # pylint:disable=unused-argument
138+
bufT = ctypes.c_byte * chunkSize[0]
139+
bufPtrT = ctypes.POINTER(bufT)
140+
bufArrPtr = ctypes.cast(buf, bufPtrT)
141+
outputStream.write(bufArrPtr[0])
142+
143+
144+
def _genCtypesFuncArgsList(f, skip: int = 0):
145+
return (f.__annotations__.get("return", None),) + tuple(f.__annotations__.get(argName, None) for argName in f.__code__.co_varnames[: f.__code__.co_argcount])[skip:]
146+
147+
148+
ReadFunT = ctypes.CFUNCTYPE(*_genCtypesFuncArgsList(inputCallbackStream, 1))
149+
WriteFunT = ctypes.CFUNCTYPE(*_genCtypesFuncArgsList(outputCallbackStream, 1))
150+
151+
152+
def getStreamCallbacks(inputStream: IOBase, outputStream: IOBase):
153+
icb = ReadFunT(partial(inputCallbackStream, inputStream))
154+
ocb = WriteFunT(partial(outputCallbackStream, outputStream))
155+
return icb, ocb
156+
157+
158+
def getLibraryFileName(nameNoPrefix):
159+
if platform.system() == "Windows":
160+
return "lib" + nameNoPrefix + ".dll"
161+
162+
return "lib" + nameNoPrefix + ".so"
163+
164+
165+
def _initLibrary(func, internalStateStructName, specializedSizeConstantsFields: typing.Tuple[typing.Tuple[str, typing.Any]], getFieldsForInternalStateStructure):
166+
nameNoPrefix = func.__name__
167+
nameNoPrefixFirstCapital = nameNoPrefix[0].upper() + nameNoPrefix[1:]
168+
169+
lutsLib = ctypes.CDLL(getLibraryFileName("pkwareLUT"))
170+
commonLib = lutsLib
171+
172+
lib = ctypes.CDLL(getLibraryFileName(nameNoPrefix))
173+
174+
class SpecializedSizeConstantsT:
175+
__slots__ = tuple(el[0] for el in specializedSizeConstantsFields)
176+
177+
def __init__(self, **kwargs):
178+
for k, defaultV in specializedSizeConstantsFields:
179+
setattr(self, k, kwargs.get(k, defaultV))
180+
181+
SpecializedSizeConstantsT.__name__ = nameNoPrefixFirstCapital + "SizeConstantsT"
182+
183+
class SpecializedSizeConstantsCtypesT(ctypes.Structure):
184+
__slots__ = SpecializedSizeConstantsT.__slots__ + ("ownSize",)
185+
_fields_ = specializedSizeConstantsHeader + tuple((el[0], ctypes.c_size_t) for el in specializedSizeConstantsFields)
186+
187+
SpecializedSizeConstantsCtypesT.__name__ = nameNoPrefixFirstCapital + "SizeConstantsCtypesT"
188+
189+
def _getSizeConstants(lib, nameNoPrefixFirstCapital) -> SpecializedSizeConstantsT:
190+
constantsGetterName = "get" + nameNoPrefixFirstCapital + "SizeConstants"
191+
if hasattr(lib, constantsGetterName):
192+
193+
def parserFunc(sizeConstants):
194+
if int(sizeConstants.ownSize) != ctypes.sizeof(SpecializedSizeConstantsCtypesT):
195+
raise ValueError(SpecializedSizeConstantsCtypesT.__name__ + " contents has changed!", sizeConstants.ownSize, ctypes.sizeof(SpecializedSizeConstantsCtypesT))
196+
197+
kwargs = {}
198+
for k, _ in specializedSizeConstantsFields:
199+
kwargs[k] = int(getattr(sizeConstants, k))
200+
201+
return SpecializedSizeConstantsT(**kwargs)
202+
203+
return _getSizeConstants1(lib, constantsGetterName, SpecializedSizeConstantsCtypesT, SpecializedSizeConstantsT, parserFunc)
204+
else:
205+
sizeConstants = SpecializedSizeConstantsT()
206+
return sizeConstants
207+
208+
def constructInternalStateStruct(name, commonSizes, lutSizes, sizeConstants, getFieldsForInternalStateStructure):
209+
class InternalStateStructT(ctypes.Structure):
210+
_fields_ = getFieldsForInternalStateStructure(commonSizes, lutSizes, sizeConstants)
211+
__slots__ = tuple(el[0] for el in _fields_)
212+
213+
InternalStateStructT.__name__ = name
214+
215+
if sizeConstants.internalStructSize is not None:
216+
if sizeConstants.internalStructSize != ctypes.sizeof(InternalStateStructT):
217+
raise ValueError(InternalStateStructT.__name__ + " contents has changed!", sizeConstants.internalStructSize, ctypes.sizeof(InternalStateStructT))
218+
else:
219+
sizeConstants.internalStructSize = ctypes.sizeof(InternalStateStructT)
220+
221+
return InternalStateStructT
222+
223+
lutSizes = getLUTSizeConstants(lutsLib)
224+
commonSizes = getCommonSizeConstants(commonLib)
225+
226+
sizeConstants = _getSizeConstants(lib, nameNoPrefixFirstCapital)
227+
InternalStateStructT = constructInternalStateStruct(internalStateStructName, commonSizes, lutSizes, sizeConstants, getFieldsForInternalStateStructure)
228+
229+
ctypesFunc = getattr(lib, nameNoPrefix)
230+
231+
ctypesFunc.argtypes = [func.__annotations__[argName] for argName in func.__code__.co_varnames[: func.__code__.co_argcount]]
232+
ctypesFunc.restype = func.__annotations__["return"]
233+
234+
return lib, InternalStateStructT, sizeConstants

pklib_base/enums.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from enum import IntEnum
2+
3+
4+
class CompressionType(IntEnum):
5+
binary = bin = CMP_BINARY = 0
6+
ascii = asc = CMP_ASCII = 1

0 commit comments

Comments
 (0)