/runtime/stdlib/zlib.py

https://github.com/cheery/lever · Python · 203 lines · 169 code · 25 blank · 9 comment · 43 complexity · 993d6c0ee14d3ad4c2363f01336656e7 MD5 · raw file

  1. from space import *
  2. from rpython.rlib import rzlib
  3. from rpython.rtyper.lltypesystem import rffi, lltype
  4. module = Module(u'zlib', {}, frozen=True)
  5. def builtin(fn):
  6. name = fn.__name__.rstrip('_').decode('utf-8')
  7. module.setattr_force(name, Builtin(fn, name))
  8. return fn
  9. @builtin
  10. @signature(Uint8Data, Integer, optional=1)
  11. def crc32(array, start):
  12. start = rzlib.CRC32_DEFAULT_START if start is None else start.value
  13. string = array.to_str()
  14. checksum = rzlib.crc32(string, rffi.r_uint(start))
  15. return Integer(rffi.r_long(checksum))
  16. @builtin
  17. @signature(Uint8Data, Integer, optional=1)
  18. def adler32(array, start):
  19. start = rzlib.ADLER32_DEFAULT_START if start is None else start.value
  20. string = array.to_str()
  21. checksum = rzlib.adler32(string, rffi.r_uint(start))
  22. return Integer(rffi.r_long(checksum))
  23. class Compress(Object):
  24. def __init__(self, stream):
  25. self.stream = stream
  26. def __del__(self):
  27. if self.stream:
  28. rzlib.deflateEnd(self.stream)
  29. self.stream = rzlib.null_stream
  30. # TODO: add options handler here.
  31. @Compress.instantiator2(signature())
  32. def Compress_init():
  33. try:
  34. level = rzlib.Z_DEFAULT_COMPRESSION
  35. method = rzlib.Z_DEFLATED
  36. wbits = rzlib.MAX_WBITS
  37. memLevel = rzlib.DEF_MEM_LEVEL
  38. strategy = rzlib.Z_DEFAULT_STRATEGY
  39. stream = rzlib.deflateInit(level, method, wbits, memLevel, strategy)
  40. return Compress(stream)
  41. except rzlib.RZlibError as e:
  42. raise zlib_error(e.msg)
  43. @Compress.method(u"compress_beta", signature(Compress, Object, Object))
  44. def Compress_compress_beta(self, inp, out):
  45. stream = self.stream
  46. i_data = cast(inp.getattr(u"data"), Uint8Data, u"inp.data")
  47. i_start = cast(inp.getattr(u"start"), Integer, u"inp.start").value
  48. i_stop = cast(inp.getattr(u"stop"), Integer, u"inp.stop").value
  49. if not (0 <= i_start <= i_stop <= i_data.length):
  50. raise unwind(LTypeError(u"inp.start/stop invalid"))
  51. o_data = cast(out.getattr(u"data"), Uint8Data, u"out.data")
  52. o_start = cast(out.getattr(u"start"), Integer, u"out.start").value
  53. o_stop = cast(out.getattr(u"stop"), Integer, u"out.stop").value
  54. if not (0 <= o_start <= o_stop <= o_data.length):
  55. raise unwind(LTypeError(u"out.start/stop invalid"))
  56. stream.c_next_in = rffi.ptradd(i_data.uint8data, i_start)
  57. stream.c_avail_in = rffi.r_uint(i_stop - i_start)
  58. stream.c_next_out = rffi.ptradd(o_data.uint8data, o_stop)
  59. stream.c_avail_out = rffi.r_uint(o_data.length - o_stop)
  60. if i_start == i_stop:
  61. err = rzlib._deflate(stream, rzlib.Z_FINISH)
  62. else:
  63. err = rzlib._deflate(stream, 0)
  64. if err == rzlib.Z_NEED_DICT:
  65. raise unwind(LError(u"Z_NEED_DICT"))
  66. if err == rzlib.Z_BUF_ERROR:
  67. raise unwind(LError(u"Z_BUF_ERROR"))
  68. if err == rzlib.Z_OK or err == rzlib.Z_STREAM_END:
  69. inp.setattr(u"start", Integer(i_stop - rffi.r_long(stream.c_avail_in)))
  70. out.setattr(u"stop", Integer(rffi.r_long(stream.c_avail_out) + o_stop))
  71. return null
  72. @Compress.method(u"compress", signature(Compress, Uint8Data))
  73. def Compress_compress(self, array):
  74. data = array.to_str()
  75. try:
  76. # lock
  77. result = rzlib.compress(self.stream, data)
  78. # unlock
  79. except rzlib.RZlibError as e:
  80. raise zlib_error(e.msg)
  81. return to_uint8array(result)
  82. @Compress.method(u"finish", signature(Compress, Integer, optional=1))
  83. def Compress_finish(self, mode):
  84. mode = rzlib.Z_FINISH if mode is None else mode.value
  85. try:
  86. # lock
  87. result = rzlib.compress(self.stream, '', rzlib.Z_FINISH)
  88. if mode == rzlib.Z_FINISH:
  89. rzlib.deflateEnd(self.stream)
  90. self.stream = rzlib.null_stream
  91. # unlock
  92. except rzlib.RZlibError as e:
  93. raise zlib_error(e.msg)
  94. return to_uint8array(result)
  95. class Decompress(Object):
  96. def __init__(self, stream):
  97. self.stream = stream
  98. def __del__(self):
  99. if self.stream:
  100. rzlib.inflateEnd(self.stream)
  101. self.stream = rzlib.null_stream
  102. @Decompress.instantiator2(signature(Integer, optional=1))
  103. def Decompress_init(wbits):
  104. wbits = rzlib.MAX_WBITS if wbits is None else wbits.value
  105. try:
  106. stream = rzlib.inflateInit(wbits)
  107. return Decompress(stream)
  108. except rzlib.RZlibError as e:
  109. raise zlib_error(e.msg)
  110. @Decompress.method(u"decompress_beta", signature(Decompress, Object, Object))
  111. def Decompress_decompress_beta(self, inp, out):
  112. stream = self.stream
  113. i_data = cast(inp.getattr(u"data"), Uint8Data, u"inp.data")
  114. i_start = cast(inp.getattr(u"start"), Integer, u"inp.start").value
  115. i_stop = cast(inp.getattr(u"stop"), Integer, u"inp.stop").value
  116. if not (0 <= i_start <= i_stop <= i_data.length):
  117. raise unwind(LTypeError(u"inp.start/stop invalid"))
  118. o_data = cast(out.getattr(u"data"), Uint8Data, u"out.data")
  119. o_start = cast(out.getattr(u"start"), Integer, u"out.start").value
  120. o_stop = cast(out.getattr(u"stop"), Integer, u"out.stop").value
  121. if not (0 <= o_start <= o_stop <= o_data.length):
  122. raise unwind(LTypeError(u"out.start/stop invalid"))
  123. stream.c_next_in = rffi.ptradd(i_data.uint8data, i_start)
  124. stream.c_avail_in = rffi.r_uint(i_stop - i_start)
  125. stream.c_next_out = rffi.ptradd(o_data.uint8data, o_stop)
  126. stream.c_avail_out = rffi.r_uint(o_data.length - o_stop)
  127. if i_start == i_stop:
  128. err = rzlib._inflate(stream, rzlib.Z_FINISH)
  129. else:
  130. err = rzlib._inflate(stream, 0)
  131. if err == rzlib.Z_NEED_DICT:
  132. raise unwind(LError(u"Z_NEED_DICT"))
  133. if err == rzlib.Z_BUF_ERROR:
  134. raise unwind(LError(u"Z_BUF_ERROR"))
  135. if err == rzlib.Z_OK or err == rzlib.Z_STREAM_END:
  136. inp.setattr(u"start", Integer(i_stop - rffi.r_long(stream.c_avail_in)))
  137. out.setattr(u"stop", Integer(rffi.r_long(stream.c_avail_out) + o_stop))
  138. return null
  139. @Decompress.method(u"decompress", signature(Decompress, Uint8Data))
  140. def Decompress_decompress(self, array):
  141. data = array.to_str()
  142. try:
  143. # lock
  144. result = rzlib.decompress(self.stream, data)
  145. # finally unlock
  146. except rzlib.RZlibError as e:
  147. raise zlib_error(e.msg)
  148. string, finished, unused_len = result
  149. assert unused_len == 0
  150. return to_uint8array(string)
  151. @Decompress.method(u"finish", signature(Decompress))
  152. def Decompress_finish(self):
  153. try:
  154. # lock
  155. result = rzlib.decompress(self.stream, '', rzlib.Z_FINISH)
  156. # finally unlock
  157. except rzlib.RZlibError as e:
  158. raise zlib_error(e.msg)
  159. string, finished, unused_len = result
  160. assert unused_len == 0
  161. return to_uint8array(string)
  162. def zlib_error(msg):
  163. return unwind(LError(msg.decode('utf-8')))
  164. module.setattr_force(u"Decompress", Decompress.interface)
  165. module.setattr_force(u"Compress", Compress.interface)
  166. for _name in u"""
  167. MAX_WBITS DEFLATED DEF_MEM_LEVEL
  168. Z_BEST_SPEED Z_BEST_COMPRESSION Z_DEFAULT_COMPRESSION
  169. Z_FILTERED Z_HUFFMAN_ONLY Z_DEFAULT_STRATEGY
  170. Z_FINISH Z_NO_FLUSH Z_SYNC_FLUSH Z_FULL_FLUSH
  171. ZLIB_VERSION""".split():
  172. value = getattr(rzlib, _name)
  173. if isinstance(value, int):
  174. module.setattr_force(_name, Integer(value))
  175. elif isinstance(value, str):
  176. module.setattr_force(_name, String(value.decode('utf-8')))
  177. else:
  178. assert False, "add fillup method"