PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rlib/rzlib.py

https://bitbucket.org/pypy/pypy/
Python | 422 lines | 362 code | 39 blank | 21 comment | 17 complexity | 9023d8d38c0810641f96dfdc79845a67 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from __future__ import with_statement
  2. import sys
  3. from rpython.rlib import rgc
  4. from rpython.rlib.rstring import StringBuilder
  5. from rpython.rtyper.annlowlevel import llstr
  6. from rpython.rtyper.lltypesystem import rffi, lltype
  7. from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
  8. from rpython.rtyper.tool import rffi_platform
  9. from rpython.translator.platform import platform as compiler, CompilationError
  10. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  11. if compiler.name == "msvc":
  12. libname = 'zlib' # use the static lib, not zlib1 which is dll import lib
  13. testonly_libraries = ['zlib1']
  14. else:
  15. libname = 'z'
  16. testonly_libraries = []
  17. eci = ExternalCompilationInfo(
  18. libraries=[libname],
  19. includes=['zlib.h'],
  20. testonly_libraries = testonly_libraries
  21. )
  22. eci = rffi_platform.configure_external_library(
  23. libname, eci,
  24. [dict(prefix='zlib-'),
  25. ])
  26. constantnames = '''
  27. Z_OK Z_STREAM_ERROR Z_BUF_ERROR Z_MEM_ERROR Z_STREAM_END Z_DATA_ERROR
  28. Z_DEFLATED Z_DEFAULT_STRATEGY Z_DEFAULT_COMPRESSION
  29. Z_NO_FLUSH Z_FINISH Z_SYNC_FLUSH Z_FULL_FLUSH
  30. MAX_WBITS MAX_MEM_LEVEL
  31. Z_BEST_SPEED Z_BEST_COMPRESSION Z_DEFAULT_COMPRESSION
  32. Z_FILTERED Z_HUFFMAN_ONLY Z_DEFAULT_STRATEGY Z_NEED_DICT
  33. '''.split()
  34. class SimpleCConfig:
  35. """
  36. Definitions for basic types defined by zlib.
  37. """
  38. _compilation_info_ = eci
  39. # XXX If Z_PREFIX was defined for the libz build, then these types are
  40. # named z_uInt, z_uLong, and z_Bytef instead.
  41. uInt = rffi_platform.SimpleType('uInt', rffi.UINT)
  42. uLong = rffi_platform.SimpleType('uLong', rffi.ULONG)
  43. Bytef = rffi_platform.SimpleType('Bytef', rffi.UCHAR)
  44. voidpf = rffi_platform.SimpleType('voidpf', rffi.VOIDP)
  45. ZLIB_VERSION = rffi_platform.DefinedConstantString('ZLIB_VERSION')
  46. for _name in constantnames:
  47. setattr(SimpleCConfig, _name, rffi_platform.ConstantInteger(_name))
  48. config = rffi_platform.configure(SimpleCConfig)
  49. voidpf = config['voidpf']
  50. uInt = config['uInt']
  51. uLong = config['uLong']
  52. Bytef = config['Bytef']
  53. Bytefp = lltype.Ptr(lltype.Array(Bytef, hints={'nolength': True}))
  54. ZLIB_VERSION = config['ZLIB_VERSION']
  55. for _name in constantnames:
  56. globals()[_name] = config[_name]
  57. # The following parameter is copied from zutil.h, version 0.95,
  58. # according to CPython's zlibmodule.c
  59. DEFLATED = Z_DEFLATED
  60. if MAX_MEM_LEVEL >= 8:
  61. DEF_MEM_LEVEL = 8
  62. else:
  63. DEF_MEM_LEVEL = MAX_MEM_LEVEL
  64. OUTPUT_BUFFER_SIZE = 32*1024
  65. class ComplexCConfig:
  66. """
  67. Definitions of structure types defined by zlib and based on SimpleCConfig
  68. definitions.
  69. """
  70. _compilation_info_ = eci
  71. z_stream = rffi_platform.Struct(
  72. 'z_stream',
  73. [('next_in', Bytefp),
  74. ('avail_in', uInt),
  75. ('total_in', uLong),
  76. ('next_out', Bytefp),
  77. ('avail_out', uInt),
  78. ('total_out', uLong),
  79. ('msg', rffi.CCHARP),
  80. ('zalloc', lltype.Ptr(
  81. lltype.FuncType([voidpf, uInt, uInt], voidpf))),
  82. ('zfree', lltype.Ptr(
  83. lltype.FuncType([voidpf, voidpf], lltype.Void))),
  84. ('opaque', voidpf),
  85. ('data_type', rffi.INT),
  86. ('adler', uLong),
  87. ('reserved', uLong)
  88. ])
  89. config = rffi_platform.configure(ComplexCConfig)
  90. z_stream = config['z_stream']
  91. z_stream_p = lltype.Ptr(z_stream)
  92. def zlib_external(*a, **kw):
  93. kw['compilation_info'] = eci
  94. return rffi.llexternal(*a, **kw)
  95. _crc32 = zlib_external('crc32', [uLong, Bytefp, uInt], uLong)
  96. _adler32 = zlib_external('adler32', [uLong, Bytefp, uInt], uLong)
  97. # XXX I want to call deflateInit2, not deflateInit2_
  98. _deflateInit2_ = zlib_external(
  99. 'deflateInit2_',
  100. [z_stream_p, # stream
  101. rffi.INT, # level
  102. rffi.INT, # method
  103. rffi.INT, # window bits
  104. rffi.INT, # mem level
  105. rffi.INT, # strategy
  106. rffi.CCHARP, # version
  107. rffi.INT], # stream size
  108. rffi.INT)
  109. _deflate = zlib_external('deflate', [z_stream_p, rffi.INT], rffi.INT)
  110. _deflateEnd = zlib_external('deflateEnd', [z_stream_p], rffi.INT,
  111. releasegil=False)
  112. def _deflateInit2(stream, level, method, wbits, memlevel, strategy):
  113. size = rffi.sizeof(z_stream)
  114. result = _deflateInit2_(
  115. stream, level, method, wbits, memlevel, strategy, ZLIB_VERSION, size)
  116. return result
  117. # XXX I also want to call inflateInit2 instead of inflateInit2_
  118. _inflateInit2_ = zlib_external(
  119. 'inflateInit2_',
  120. [z_stream_p, # stream
  121. rffi.INT, # window bits
  122. rffi.CCHARP, # version
  123. rffi.INT], # stream size
  124. rffi.INT)
  125. _inflate = zlib_external('inflate', [z_stream_p, rffi.INT], rffi.INT)
  126. _inflateEnd = zlib_external('inflateEnd', [z_stream_p], rffi.INT,
  127. releasegil=False)
  128. def _inflateInit2(stream, wbits):
  129. size = rffi.sizeof(z_stream)
  130. result = _inflateInit2_(stream, wbits, ZLIB_VERSION, size)
  131. return result
  132. _deflateSetDictionary = zlib_external('deflateSetDictionary', [z_stream_p, Bytefp, uInt], rffi.INT)
  133. _inflateSetDictionary = zlib_external('inflateSetDictionary', [z_stream_p, Bytefp, uInt], rffi.INT)
  134. _zlibVersion = zlib_external('zlibVersion', [], rffi.CCHARP)
  135. # ____________________________________________________________
  136. CRC32_DEFAULT_START = 0
  137. def crc32(string, start=CRC32_DEFAULT_START):
  138. """
  139. Compute the CRC32 checksum of the string, possibly with the given
  140. start value, and return it as a unsigned 32 bit integer.
  141. """
  142. with rffi.scoped_nonmovingbuffer(string) as bytes:
  143. checksum = _crc32(start, rffi.cast(Bytefp, bytes), len(string))
  144. return checksum
  145. ADLER32_DEFAULT_START = 1
  146. def deflateSetDictionary(stream, string):
  147. with rffi.scoped_nonmovingbuffer(string) as buf:
  148. err = _deflateSetDictionary(stream, rffi.cast(Bytefp, buf), len(string))
  149. if err == Z_STREAM_ERROR:
  150. raise RZlibError("Parameter is invalid or the stream state is inconsistent")
  151. def inflateSetDictionary(stream, string):
  152. with rffi.scoped_nonmovingbuffer(string) as buf:
  153. err = _inflateSetDictionary(stream, rffi.cast(Bytefp, buf), len(string))
  154. if err == Z_STREAM_ERROR:
  155. raise RZlibError("Parameter is invalid or the stream state is inconsistent")
  156. elif err == Z_DATA_ERROR:
  157. raise RZlibError("The given dictionary doesn't match the expected one")
  158. def adler32(string, start=ADLER32_DEFAULT_START):
  159. """
  160. Compute the Adler-32 checksum of the string, possibly with the given
  161. start value, and return it as a unsigned 32 bit integer.
  162. """
  163. with rffi.scoped_nonmovingbuffer(string) as bytes:
  164. checksum = _adler32(start, rffi.cast(Bytefp, bytes), len(string))
  165. return checksum
  166. def zlibVersion():
  167. """Return the runtime version of zlib library"""
  168. return rffi.charp2str(_zlibVersion())
  169. # ____________________________________________________________
  170. class RZlibError(Exception):
  171. """Exception raised by failing operations in rpython.rlib.rzlib."""
  172. def __init__(self, msg):
  173. self.msg = msg
  174. def __str__(self):
  175. return self.msg
  176. def fromstream(stream, err, while_doing):
  177. """Return a RZlibError with a message formatted from a zlib error
  178. code and stream.
  179. """
  180. if stream.c_msg:
  181. reason = rffi.charp2str(stream.c_msg)
  182. elif err == Z_MEM_ERROR:
  183. reason = "out of memory"
  184. elif err == Z_BUF_ERROR:
  185. reason = "incomplete or truncated stream"
  186. elif err == Z_STREAM_ERROR:
  187. reason = "inconsistent stream state"
  188. elif err == Z_DATA_ERROR:
  189. reason = "invalid input data"
  190. else:
  191. reason = ""
  192. if reason:
  193. delim = ": "
  194. else:
  195. delim = ""
  196. msg = "Error %d %s%s%s" % (err, while_doing, delim, reason)
  197. return RZlibError(msg)
  198. fromstream = staticmethod(fromstream)
  199. null_stream = lltype.nullptr(z_stream)
  200. def deflateInit(level=Z_DEFAULT_COMPRESSION, method=Z_DEFLATED,
  201. wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL,
  202. strategy=Z_DEFAULT_STRATEGY):
  203. """
  204. Allocate and return an opaque 'stream' object that can be used to
  205. compress data.
  206. """
  207. stream = lltype.malloc(z_stream, flavor='raw', zero=True)
  208. rgc.add_memory_pressure(rffi.sizeof(z_stream))
  209. err = _deflateInit2(stream, level, method, wbits, memLevel, strategy)
  210. if err == Z_OK:
  211. return stream
  212. else:
  213. try:
  214. if err == Z_STREAM_ERROR:
  215. raise ValueError("Invalid initialization option")
  216. else:
  217. raise RZlibError.fromstream(stream, err,
  218. "while creating compression object")
  219. finally:
  220. lltype.free(stream, flavor='raw')
  221. def deflateEnd(stream):
  222. """
  223. Free the resources associated with the deflate stream.
  224. """
  225. _deflateEnd(stream)
  226. lltype.free(stream, flavor='raw')
  227. def inflateInit(wbits=MAX_WBITS):
  228. """
  229. Allocate and return an opaque 'stream' object that can be used to
  230. decompress data.
  231. """
  232. stream = lltype.malloc(z_stream, flavor='raw', zero=True)
  233. rgc.add_memory_pressure(rffi.sizeof(z_stream))
  234. err = _inflateInit2(stream, wbits)
  235. if err == Z_OK:
  236. return stream
  237. else:
  238. try:
  239. if err == Z_STREAM_ERROR:
  240. raise ValueError("Invalid initialization option")
  241. else:
  242. raise RZlibError.fromstream(stream, err,
  243. "while creating decompression object")
  244. finally:
  245. lltype.free(stream, flavor='raw')
  246. def inflateEnd(stream):
  247. """
  248. Free the resources associated with the inflate stream.
  249. Note that this may raise RZlibError.
  250. """
  251. _inflateEnd(stream)
  252. lltype.free(stream, flavor='raw')
  253. def compress(stream, data, flush=Z_NO_FLUSH):
  254. """
  255. Feed more data into a deflate stream. Returns a string containing
  256. (a part of) the compressed data. If flush != Z_NO_FLUSH, this also
  257. flushes the output data; see zlib.h or the documentation of the
  258. zlib module for the possible values of 'flush'.
  259. """
  260. # Warning, reentrant calls to the zlib with a given stream can cause it
  261. # to crash. The caller of rpython.rlib.rzlib should use locks if needed.
  262. data, _, avail_in = _operate(stream, data, flush, sys.maxint, _deflate,
  263. "while compressing")
  264. assert not avail_in, "not all input consumed by deflate"
  265. return data
  266. def decompress(stream, data, flush=Z_SYNC_FLUSH, max_length=sys.maxint):
  267. """
  268. Feed more data into an inflate stream. Returns a tuple (string,
  269. finished, unused_data_length). The string contains (a part of) the
  270. decompressed data. If flush != Z_NO_FLUSH, this also flushes the
  271. output data; see zlib.h or the documentation of the zlib module for
  272. the possible values of 'flush'.
  273. The 'string' is never longer than 'max_length'. The
  274. 'unused_data_length' is the number of unprocessed input characters,
  275. either because they are after the end of the compressed stream or
  276. because processing it would cause the 'max_length' to be exceeded.
  277. """
  278. # Warning, reentrant calls to the zlib with a given stream can cause it
  279. # to crash. The caller of rpython.rlib.rzlib should use locks if needed.
  280. # _operate() does not support the Z_FINISH method of decompressing.
  281. # We can use Z_SYNC_FLUSH instead and manually check that we got to
  282. # the end of the data.
  283. if flush == Z_FINISH:
  284. flush = Z_SYNC_FLUSH
  285. should_finish = True
  286. else:
  287. should_finish = False
  288. while_doing = "while decompressing data"
  289. data, err, avail_in = _operate(stream, data, flush, max_length, _inflate,
  290. while_doing)
  291. if should_finish:
  292. # detect incomplete input
  293. rffi.setintfield(stream, 'c_avail_in', 0)
  294. err = _inflate(stream, Z_FINISH)
  295. if err < 0:
  296. raise RZlibError.fromstream(stream, err, while_doing)
  297. finished = (err == Z_STREAM_END)
  298. return data, finished, avail_in
  299. def _operate(stream, data, flush, max_length, cfunc, while_doing):
  300. """Common code for compress() and decompress().
  301. """
  302. # Prepare the input buffer for the stream
  303. assert data is not None # XXX seems to be sane assumption, however not for sure
  304. with rffi.scoped_nonmovingbuffer(data) as inbuf:
  305. stream.c_next_in = rffi.cast(Bytefp, inbuf)
  306. rffi.setintfield(stream, 'c_avail_in', len(data))
  307. # Prepare the output buffer
  308. with lltype.scoped_alloc(rffi.CCHARP.TO, OUTPUT_BUFFER_SIZE) as outbuf:
  309. # Strategy: we call deflate() to get as much output data as fits in
  310. # the buffer, then accumulate all output into a StringBuffer
  311. # 'result'.
  312. result = StringBuilder()
  313. while True:
  314. stream.c_next_out = rffi.cast(Bytefp, outbuf)
  315. bufsize = OUTPUT_BUFFER_SIZE
  316. if max_length < bufsize:
  317. if max_length <= 0:
  318. err = Z_OK
  319. break
  320. bufsize = max_length
  321. max_length -= bufsize
  322. rffi.setintfield(stream, 'c_avail_out', bufsize)
  323. err = cfunc(stream, flush)
  324. if err == Z_OK or err == Z_STREAM_END:
  325. # accumulate data into 'result'
  326. avail_out = rffi.cast(lltype.Signed, stream.c_avail_out)
  327. result.append_charpsize(outbuf, bufsize - avail_out)
  328. # if the output buffer is full, there might be more data
  329. # so we need to try again. Otherwise, we're done.
  330. if avail_out > 0:
  331. break
  332. # We're also done if we got a Z_STREAM_END (which should
  333. # only occur when flush == Z_FINISH).
  334. if err == Z_STREAM_END:
  335. break
  336. else:
  337. continue
  338. elif err == Z_BUF_ERROR:
  339. avail_out = rffi.cast(lltype.Signed, stream.c_avail_out)
  340. # When compressing, we will only get Z_BUF_ERROR if
  341. # the output buffer was full but there wasn't more
  342. # output when we tried again, so it is not an error
  343. # condition.
  344. if avail_out == bufsize:
  345. break
  346. # fallback case: report this error
  347. raise RZlibError.fromstream(stream, err, while_doing)
  348. # When decompressing, if the compressed stream of data was truncated,
  349. # then the zlib simply returns Z_OK and waits for more. If it is
  350. # complete it returns Z_STREAM_END.
  351. return (result.build(),
  352. err,
  353. rffi.cast(lltype.Signed, stream.c_avail_in))