diff --git a/lzo.py b/lzo.py index a69ec3a..81a34f1 100755 --- a/lzo.py +++ b/lzo.py @@ -1,9 +1,11 @@ import struct import io -import __builtin__ +import builtins from _lzo import * +from enum import IntFlag + __all__ = ["LzoFile", "open"] MAGIC = b"\x89\x4C\x5A\x4F\x00\x0D\x0A\x1A\x0A" @@ -18,25 +20,41 @@ LZO_LIB_VERSION = 0x0940 -BLOCK_SIZE = (128*1024L) -MAX_BLOCK_SIZE = (64*1024l*1024L) - - -F_ADLER32_D = 0x00000001L -F_ADLER32_C = 0x00000002L -F_STDIN = 0x00000004L -F_STDOUT = 0x00000008L -F_NAME_DEFAULT = 0x00000010L -F_DOSISH = 0x00000020L -F_H_EXTRA_FIELD = 0x00000040L -F_H_GMTDIFF = 0x00000080L -F_CRC32_D = 0x00000100L -F_CRC32_C = 0x00000200L -F_MULTIPART = 0x00000400L -F_H_FILTER = 0x00000800L -F_H_CRC32 = 0x00001000L -F_H_PATH = 0x00002000L -F_MASK = 0x00003FFFL +BLOCK_SIZE = (128*1024) +MAX_BLOCK_SIZE = (64*1024*1024) + +class Flags(IntFlag): + adler32_d = 0x00000001 + adler32_c = 0x00000002 + stdin = 0x00000004 + stdout = 0x00000008 + name_default = 0x00000010 + dosish = 0x00000020 + header_extra_field = 0x00000040 + header_gmt_diff = 0x00000080 + crc32_d = 0x00000100 + crc32_c = 0x00000200 + multipart = 0x00000400 + header_filter = 0x00000800 + header_crc32 = 0x00001000 + header_path = 0x00002000 + mask = 0x00003FFF + +F_ADLER32_D = Flags.adler32_d +F_ADLER32_C = Flags.adler32_c +F_STDIN = Flags.stdin +F_STDOUT = Flags.stdout +F_NAME_DEFAULT = Flags.name_default +F_DOSISH = Flags.dosish +F_H_EXTRA_FIELD = Flags.header_extra_field +F_H_GMTDIFF = Flags.header_gmt_diff +F_CRC32_D = Flags.crc32_d +F_CRC32_C = Flags.crc32_c +F_MULTIPART = Flags.multipart +F_H_FILTER = Flags.header_filter +F_H_CRC32 = Flags.header_crc32 +F_H_PATH = Flags.header_path +F_MASK = Flags.mask def open(filename, mode): return LzoFile(filename = filename, mode = mode) @@ -53,7 +71,7 @@ def __init__(self, filename=None, mode=None, The compresslevel and mtime attribute is not supported so far The new class instance is based on fileobj, which can be a regular - file, a StringIO object, or any other object which simulates a file. + file, a BytesIO object, or any other object which simulates a file. It defaults to None, in which case filename is opened to provide a file object. @@ -74,7 +92,7 @@ def __init__(self, filename=None, mode=None, mode = 'rb' if fileobj is None: - fileobj = __builtin__.open(filename, mode) + fileobj = builtins.open(filename, mode) self.need_close = True else: self.need_close = False @@ -93,7 +111,7 @@ def __init__(self, filename=None, mode=None, self.mode = WRITE else: - raise IOError, "Mode " + mode + " not supported" + raise IOError("Mode " + mode + " not supported") self.fileobj = fileobj self.offset = 0 @@ -123,11 +141,17 @@ def __init__(self, filename=None, mode=None, self.mtime_low = 0 self.mtime_high = 0 - self.name = filename + self.name = filename.encode("utf-8") self._write_magic() self._write_header() + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + self.close() + def _clear_buf(self): self._buf = [] self._buf_len = 0 @@ -172,7 +196,7 @@ def _read_magic(self): if magic == MAGIC: return True else: - raise IOError, 'Wrong lzo signature' + raise IOError('Wrong lzo signature') def _read_header(self): self.adler32 = ADLER32_INIT_VALUE @@ -184,9 +208,9 @@ def _read_header(self): if self.version > 0x0940: self.ver_need_ext = self._read16_c() if self.ver_need_ext > LZOP_VERSION: - raise IOError, 'Need liblzo version higher than %s' %(hex(self.ver_need_ext)) + raise IOError('Need liblzo version higher than %s' %(hex(self.ver_need_ext))) elif self.ver_need_ext < 0x0900: - raise IOError, '3' + raise IOError('3') self.method = self._read8_c() assert(self.method in [1,2,3]) @@ -197,7 +221,7 @@ def _read_header(self): self.flags = self._read32_c() if self.flags & F_H_CRC32: - raise error, 'CRC32 not implemented in minilzo' + raise error('CRC32 not implemented in minilzo') if self.flags & F_H_FILTER: self.ffilter = self._read32() @@ -230,7 +254,7 @@ def _read_block(self): return None if dst_len > MAX_BLOCK_SIZE: - raise error, 'uncompressed larger than max block size' + raise error('uncompressed larger than max block size') src_len = self._read32() @@ -542,14 +566,14 @@ def main(): else: de_name = filename + '.uncompressed' - with __builtin__.open(de_name, 'wb') as de: + with builtins.open(de_name, 'wb') as de: de.write(f.read()) else: - with __builtin__.open(args.path, 'rb') as f: + with builtins.open(args.path, 'rb') as f: with LzoFile(filename = args.path + ".lzo", mode = 'wb') as com: com.write(f.read()) if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/lzomodule.c b/lzomodule.c index 78cf43c..0e0188b 100755 --- a/lzomodule.c +++ b/lzomodule.c @@ -59,12 +59,6 @@ compress_block(PyObject *dummy, PyObject *args) out_len = in_len + in_len / 64 + 16 + 3; - result = PyBytes_FromStringAndSize(NULL, out_len); - - if (result == NULL){ - return PyErr_NoMemory(); - } - if (method == M_LZO1X_1) wrk_len = LZO1X_1_MEM_COMPRESS; #ifdef USE_LIBLZO @@ -78,7 +72,7 @@ compress_block(PyObject *dummy, PyObject *args) assert(wrk_len <= WRK_LEN); wrkmem = (lzo_voidp) PyMem_Malloc(wrk_len); - out = (lzo_bytep) PyString_AsString(result); + out = (lzo_bytep) PyMem_Malloc(out_len); if (method == M_LZO1X_1){ err = lzo1x_1_compress(in, (lzo_uint) in_len, out, (lzo_uint*) &new_len, wrkmem); @@ -96,12 +90,18 @@ compress_block(PyObject *dummy, PyObject *args) #endif else{ PyMem_Free(wrkmem); - Py_DECREF(result); + PyMem_Free(out); PyErr_SetString(LzoError, "Compression method not supported"); return NULL; } + result = PyBytes_FromStringAndSize(out, new_len); + if (result == NULL){ + return PyErr_NoMemory(); + } + PyMem_Free(wrkmem); + PyMem_Free(out); if (err != LZO_E_OK || new_len > out_len) { /* this should NEVER happen */ @@ -110,13 +110,6 @@ compress_block(PyObject *dummy, PyObject *args) return NULL; } - if (new_len != out_len) - _PyString_Resize(&result, new_len); - /* - If the reallocation fails, the result is set to NULL, and memory exception is set - So should raise right exception to python environment without additional check - */ - return result; } @@ -229,39 +222,34 @@ static /* const */ char module_documentation[]= ; +static PyModuleDef moduleSpec = { + PyModuleDef_HEAD_INIT, + /*.m_name=*/"_lzo", + /*.m_doc=*/module_documentation, + /*.m_size=*/-1, + /*.m_methods=*/methods, + /*.m_reload=*/NULL, + /*.m_traverse=*/NULL, + /*.m_clear=*/NULL, + /*.m_free=*/NULL, +}; #ifdef _MSC_VER _declspec(dllexport) #endif -void init_lzo(void) -{ - PyObject *m, *d, *v; +PyMODINIT_FUNC PyInit__lzo() { if (lzo_init() != LZO_E_OK) { - return; + return NULL; } - - m = Py_InitModule4("_lzo", methods, module_documentation, - NULL, PYTHON_API_VERSION); - d = PyModule_GetDict(m); - - LzoError = PyErr_NewException("_lzo.error", NULL, NULL); - PyDict_SetItemString(d, "error", LzoError); - - v = PyString_FromString(""); - PyDict_SetItemString(d, "__author__", v); - Py_DECREF(v); - - v = PyInt_FromLong(LZO_VERSION); - PyDict_SetItemString(d, "LZO_VERSION", v); - Py_DECREF(v); - v = PyString_FromString(LZO_VERSION_STRING); - PyDict_SetItemString(d, "LZO_VERSION_STRING", v); - Py_DECREF(v); - v = PyString_FromString(LZO_VERSION_DATE); - PyDict_SetItemString(d, "LZO_VERSION_DATE", v); - Py_DECREF(v); -} + PyObject *m = PyModule_Create(&moduleSpec); + PyObject_SetAttrString(m, "__author__", PyUnicode_FromString("")); + PyObject_SetAttrString(m, "LZO_VERSION", PyLong_FromLong(LZO_VERSION)); + PyObject_SetAttrString(m, "LZO_VERSION_STRING", PyUnicode_FromString(LZO_VERSION_STRING)); + PyObject_SetAttrString(m, "LZO_VERSION_DATE", PyUnicode_FromString(LZO_VERSION_DATE)); + PyObject_SetAttrString(m, "error", (PyObject*) PyErr_NewException("_lzo.error", NULL, NULL)); + return m; + } /*