lzmastream.bmx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. SuperStrict
  2. Rem
  3. bbdoc: Streams/Lzma Streams
  4. End Rem
  5. Module Otus.LzmaStream
  6. ModuleInfo "Version: 1.02"
  7. ModuleInfo "Author: Jan Varho"
  8. ModuleInfo "License: Public domain"
  9. ModuleInfo "History: 1.02"
  10. ModuleInfo "History: Updated for NG."
  11. ModuleInfo "History: 1.01"
  12. ModuleInfo "History: Added Discard method"
  13. ModuleInfo "History: Added 4 bytes to header"
  14. ModuleInfo "History: Fixed memory access error"
  15. Import BRL.BankStream
  16. Import BRL.Stream
  17. Import Otus.LZMA
  18. Rem
  19. bbdoc: LZMA stream wrapper type
  20. about:
  21. #TLzmaStream wraps a raw stream and allows access to uncompressed data.
  22. When writing, the data is compressed and the compressed daa written to the wrapped stream.
  23. If compression expands the data, uncompressed data is written instead.
  24. Changes in the raw stream don't automatically appear in a TLzmaStream
  25. - #ReadSync updates to the current raw stream, but any changes are lost.
  26. Similarly, changes written to a TLzmaStream are only written to the raw stream
  27. on a Flush/FlushStream call or when the stream is closed.
  28. Note: You may lose data if you fail to close/flush the stream before program ends.
  29. Do not rely on the automatic Delete->Close call!
  30. End Rem
  31. Type TLzmaStream Extends TStreamWrapper
  32. Field _basestream:TStream
  33. Field _level:Int = 5
  34. Field _closed:Int
  35. Rem
  36. bbdoc: Closes the stream, writing any changes
  37. End Rem
  38. Method Close()
  39. If _closed Return
  40. Flush()
  41. If _basestream Then _basestream.Close()
  42. If _stream Then _stream.Close()
  43. _closed = True
  44. End Method
  45. Rem
  46. bbdoc: Closes the stream, discarding any changes
  47. End Rem
  48. Method Discard()
  49. If _closed Return
  50. _basestream = Null
  51. If _stream Then _stream.Close()
  52. _closed = True
  53. End Method
  54. Rem
  55. bbdoc: Updates to current raw stream data
  56. End Rem
  57. Method ReadSync()
  58. 'Empty stream?
  59. If _basestream.Size()=0
  60. _stream = CreateBankStream(Null)
  61. Return
  62. End If
  63. 'Verify header
  64. _basestream.Seek(0)
  65. If _basestream.ReadInt() <> $4c5a4d41 'LZMA
  66. Return
  67. End If
  68. _basestream.Seek(0)
  69. 'Copy stream contents to a bank
  70. ?bmxng
  71. Local b:TBank = TBank.Create(Size_T(_basestream.Size()))
  72. ?Not bmxng
  73. Local b:TBank = TBank.Create(_basestream.Size())
  74. ?
  75. CopyStream _basestream, CreateBankStream(b)
  76. 'Set up bank for raw access
  77. Local buf:Byte Ptr = b.Lock()
  78. 'Is this uncompressed data?
  79. ?bmxng
  80. Local size:Size_T = b.Size()-8
  81. Local usize:Long = Int Ptr(buf)[1] + 1
  82. ?Not bmxng
  83. Local size:Int = b.Size()-8
  84. Local usize:Int = Int Ptr(buf)[1] + 1
  85. ?
  86. If usize<=1
  87. If -usize <> size Return
  88. ?bmxng
  89. Local u:TBank = TBank.Create(Size_T(-usize))
  90. Local ubuf:Byte Ptr = u.Lock()
  91. MemCopy ubuf, buf+8, Size_T(-usize)
  92. ?Not bmxng
  93. Local u:TBank = TBank.Create(-usize)
  94. Local ubuf:Byte Ptr = u.Lock()
  95. MemCopy ubuf, buf+8, -usize
  96. ?
  97. u.Unlock()
  98. _stream = CreateBankStream(u)
  99. Return
  100. End If
  101. 'Create a bank for uncompressed data
  102. ?bmxng
  103. Local u:TBank = TBank.Create(Size_T(usize))
  104. Local ubuf:Byte Ptr = u.Lock()
  105. Local us:Size_T = Size_T(usize)
  106. LzmaUncompress ubuf, us, buf+8, size
  107. usize = us
  108. ?Not bmxng
  109. Local u:TBank = TBank.Create(usize)
  110. Local ubuf:Byte Ptr = u.Lock()
  111. LzmaUncompress ubuf, usize, buf+8, size
  112. ?
  113. 'Not valid LZMA?
  114. If usize <> u.Size()-1 Then Return
  115. u.Unlock()
  116. ?bmxng
  117. u.Resize(Size_T(usize))
  118. ?Not bmxng
  119. u.Resize(usize)
  120. ?
  121. _stream = CreateBankStream(u)
  122. End Method
  123. Rem
  124. bbdoc: Flushes current data to the raw stream
  125. End Rem
  126. Method Flush()
  127. 'Set up bank for raw access
  128. Local b:TBank = TBankStream(_stream)._bank
  129. ?bmxng
  130. Local bsize:Size_T = b.Size()
  131. ?Not bmxng
  132. Local bsize:Int = b.Size()
  133. ?
  134. Local buf:Byte Ptr = b.Lock()
  135. 'Create bank for compressed data
  136. ?bmxng
  137. Local csize:Size_T = bsize + 1024
  138. ?Not bmxng
  139. Local csize:Int = bsize + 1024
  140. ?
  141. Local c:TBank = TBank.Create(csize)
  142. Local cbuf:Byte Ptr = c.Lock()
  143. LzmaCompress2 cbuf, csize, buf, bsize, _level
  144. _basestream.Seek 0
  145. 'Does it fit?
  146. If csize<b.Size()
  147. _basestream.WriteInt $4c5a4d41 'LZMA
  148. _basestream.WriteInt Int(b.Size())
  149. _basestream.WriteBytes cbuf, csize
  150. Else
  151. 'Write uncompressed
  152. _basestream.WriteInt $4c5a4d41 'LZMA
  153. _basestream.WriteInt Int(-b.Size())
  154. _basestream.WriteBytes buf, b.Size()
  155. End If
  156. b.Unlock()
  157. End Method
  158. Function Create:TLzmaStream( stream:TStream )
  159. 'Stream must be seekable
  160. If stream=Null Or stream.Seek(0)=-1 Then Return Null
  161. Local l:TLzmaStream = New TLzmaStream
  162. l._basestream = stream
  163. l.ReadSync()
  164. If Not l._stream Then Return Null
  165. Return l
  166. End Function
  167. End Type
  168. Rem
  169. bbdoc: Opens #url as TLzmaStream
  170. about:
  171. An alternative to using OpenStream("lzma::-blah").
  172. End Rem
  173. Function CreateLzmaStream:TLzmaStream( url:Object )
  174. Return TLzmaStream.Create( OpenStream(url) )
  175. End Function
  176. New TLzmaStreamFactory
  177. Type TLzmaStreamFactory Extends TStreamFactory
  178. Method CreateStream:TStream( url:Object,proto$,path$,readable%,writeable% )
  179. If proto<>"lzma" Then Return Null
  180. Local stream:TStream = OpenStream(path, readable, writeable)
  181. Assert stream<>Null
  182. Return TLzmaStream.Create( stream )
  183. End Method
  184. End Type