databuffer.monkey2 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. Namespace std.memory
  2. Using std.stream
  3. #rem monkeydoc DataBuffer class.
  4. #end
  5. Class DataBuffer Extends std.resource.Resource
  6. #rem monkeydoc Creates a new databuffer.
  7. The new databuffer initally uses little endian byte order. You can change this via the ByteOrder property.
  8. When you have finished with the data buffer, you should call its inherited [[Resource.Discard]] method.
  9. @example
  10. \#Import "<std>"
  11. Using std.memory
  12. Function Main()
  13. Local buf:=New DataBuffer( 10 )
  14. Print buf.Length
  15. For Local i:=0 Until 10
  16. buf.PokeByte( i,i*2 )
  17. Next
  18. For Local i:=0 Until 10
  19. Print buf.PeekByte( i )
  20. Next
  21. End
  22. @end
  23. @param length The length of the databuffer to create, in bytes.
  24. @param byteOrder Initial byte order of the data.
  25. #end
  26. Method New( length:Int,byteOrder:ByteOrder=std.memory.ByteOrder.LittleEndian )
  27. _length=length
  28. _data=Cast<UByte Ptr>( libc.malloc( length ) )
  29. _byteOrder=byteOrder
  30. _swapEndian=False
  31. OnDiscarded+=Lambda()
  32. libc.free( _data )
  33. _data=Null
  34. End
  35. End
  36. #rem monkeydoc A raw pointer to the databuffer's internal memory.
  37. Note: This pointer will change if the databuffer is resized using Resize.
  38. #end
  39. Property Data:UByte Ptr()
  40. Return _data
  41. End
  42. #rem monkeydoc The length of the databuffer in bytes.
  43. #end
  44. Property Length:Int()
  45. Return _length
  46. End
  47. #rem monkeydoc The byte order of the databuffer.
  48. #end
  49. Property ByteOrder:ByteOrder()
  50. Return _byteOrder
  51. Setter( byteOrder:ByteOrder )
  52. _byteOrder=byteOrder
  53. _swapEndian=(_byteOrder=ByteOrder.BigEndian)
  54. End
  55. #rem monkeydoc Resizes the databuffer.
  56. Note: This method reallocates the internal memory buffer and will cause the [[Data]] property to change.
  57. @param length The new length of the databuffer.
  58. #end
  59. Method Resize( length:Int )
  60. Local data:=Cast<UByte Ptr>( libc.malloc( length ) )
  61. libc.memcpy( data,_data,Min( length,_length ) )
  62. libc.free( _data )
  63. _data=data
  64. End
  65. #rem monkeydoc Reads a byte from the databuffer.
  66. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  67. @param offset The offset to read.
  68. @return The byte read from `offset`.
  69. #end
  70. Method PeekByte:Byte( offset:Int )
  71. DebugAssert( offset>=0 And offset<_length )
  72. Return Cast<Byte Ptr>( _data+offset )[0]
  73. End
  74. #rem monkeydoc Reads a ubyte from the databuffer.
  75. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  76. @param offset The offset to read.
  77. @return The ubyte read from `offset`.
  78. #end
  79. Method PeekUByte:UByte( offset:Int )
  80. DebugAssert( offset>=0 And offset<_length )
  81. Return Cast<UByte Ptr>( _data+offset )[0]
  82. End
  83. #rem monkeydoc Reads a 16 bit short from the databuffer.
  84. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  85. @param offset The offset to read.
  86. @return The short read from `offset`.
  87. #end
  88. Method PeekShort:Short( offset:Int )
  89. DebugAssert( offset>=0 And offset<_length-1 )
  90. Local t:=Cast<Short Ptr>( _data+offset )[0]
  91. If _swapEndian Swap2( Varptr t )
  92. Return t
  93. End
  94. #rem monkeydoc Reads a 16 bit ushort from the databuffer.
  95. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  96. @param offset The offset to read.
  97. @return The ushort read from `offset`.
  98. #end
  99. Method PeekUShort:UShort( offset:Int )
  100. DebugAssert( offset>=0 And offset<_length-1 )
  101. Local t:=Cast<UShort Ptr>( _data+offset )[0]
  102. If _swapEndian Swap2( Varptr t )
  103. Return t
  104. End
  105. #rem monkeydoc Reads a 32 bit int from the databuffer.
  106. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  107. @param offset The offset to read.
  108. @return The int read from `offset`.
  109. #end
  110. Method PeekInt:Int( offset:Int )
  111. DebugAssert( offset>=0 And offset<_length-3 )
  112. Local t:=Cast<Int Ptr>( _data+offset )[0]
  113. If _swapEndian Swap4( Varptr t )
  114. Return t
  115. End
  116. #rem monkeydoc Reads a 32 bit uint from the databuffer.
  117. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  118. @param offset The offset to read.
  119. @return The uint read from `offset`.
  120. #end
  121. Method PeekUInt:UInt( offset:Int )
  122. DebugAssert( offset>=0 And offset<_length-3 )
  123. Local t:=Cast<UInt Ptr>( _data+offset )[0]
  124. If _swapEndian Swap4( Varptr t )
  125. Return t
  126. End
  127. #rem monkeydoc Reads a 64 bit long from the databuffer.
  128. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  129. @param offset The offset to read.
  130. @return The long read from `offset`.
  131. #end
  132. Method PeekLong:Long( offset:Int )
  133. DebugAssert( offset>=0 And offset<_length-7 )
  134. Local t:=Cast<Long Ptr>( _data+offset )[0]
  135. If _swapEndian Swap8( Varptr t )
  136. Return t
  137. End
  138. #rem monkeydoc Reads a 64 bit ulong from the databuffer.
  139. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  140. @param offset The offset to read.
  141. @return The ulong read from `offset`.
  142. #end
  143. Method PeekULong:ULong( offset:Int )
  144. DebugAssert( offset>=0 And offset<_length-7 )
  145. Local t:=Cast<ULong Ptr>( _data+offset )[0]
  146. If _swapEndian Swap8( Varptr t )
  147. Return t
  148. End
  149. #rem monkeydoc Reads a 32 bit float from the databuffer.
  150. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  151. @param offset The offset to read.
  152. @return The float read from `offset`.
  153. #end
  154. Method PeekFloat:Float( offset:Int )
  155. DebugAssert( offset>=0 And offset<_length-3 )
  156. Local t:=Cast<Float Ptr>( _data+offset )[0]
  157. If _swapEndian Swap4( Varptr t )
  158. Return t
  159. End
  160. #rem monkeydoc Reads a 64 bit double from the databuffer.
  161. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  162. @param offset The offset to read.
  163. @return The double read from `offset`.
  164. #end
  165. Method PeekDouble:Double( offset:Int )
  166. DebugAssert( offset>=0 And offset<_length-7 )
  167. Local t:=Cast<Double Ptr>( _data+offset )[0]
  168. If _swapEndian Swap8( Varptr t )
  169. Return t
  170. End
  171. #rem monkeydoc Reads a string from the databuffer.
  172. If `count` is omitted, all bytes from `offset` until the end of the data buffer are read.
  173. @param offset Byte offset to read the string.
  174. @param count Number of bytes to read.
  175. #end
  176. Method PeekString:String( offset:Int )
  177. DebugAssert( offset>=0 And offset<=_length )
  178. Return PeekString( offset,_length-offset )
  179. End
  180. Method PeekString:String( offset:Int,count:Int )
  181. DebugAssert( offset>=0 And count>=0 And offset+count<=_length )
  182. Return String.FromCString( _data+offset,count )
  183. End
  184. #rem monkeydoc Writes a byte to the databuffer
  185. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  186. @param offset The offset to write.
  187. #end
  188. Method PokeByte( offset:Int,value:Byte )
  189. DebugAssert( offset>=0 And offset<_length )
  190. Cast<Byte Ptr>( _data+offset )[0]=value
  191. End
  192. #rem monkeydoc Writes an unsigned byte to the databuffer.
  193. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  194. @param offset The offset to write.
  195. #end
  196. Method PokeUByte( offset:Int,value:UByte )
  197. DebugAssert( offset>=0 And offset<_length )
  198. Cast<UByte Ptr>( _data+offset )[0]=value
  199. End
  200. #rem monkeydoc Writes a 16 bit short to the databuffer
  201. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  202. @param offset The offset to write.
  203. #end
  204. Method PokeShort( offset:Int,value:Short )
  205. DebugAssert( offset>=0 And offset<_length-1 )
  206. If _swapEndian Swap2( Varptr value )
  207. Cast<Short Ptr>( _data+offset )[0]=value
  208. End
  209. #rem monkeydoc Writes a 16 bit unsigned short to the databuffer
  210. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  211. @param offset The offset to write.
  212. #end
  213. Method PokeUShort( offset:Int,value:UShort )
  214. DebugAssert( offset>=0 And offset<_length-1 )
  215. If _swapEndian Swap2( Varptr value )
  216. Cast<UShort Ptr>( _data+offset )[0]=value
  217. End
  218. #rem monkeydoc Writes a 32 bit int to the databuffer
  219. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  220. @param offset The offset to write.
  221. #end
  222. Method PokeInt( offset:Int,value:Int )
  223. DebugAssert( offset>=0 And offset<_length-3 )
  224. If _swapEndian Swap4( Varptr value )
  225. Cast<Int Ptr>( _data+offset )[0]=value
  226. End
  227. #rem monkeydoc Writes a 32 bit unsigned int to the databuffer
  228. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  229. @param offset The offset to write.
  230. #end
  231. Method PokeUInt( offset:Int,value:UInt )
  232. DebugAssert( offset>=0 And offset<_length-3 )
  233. If _swapEndian Swap4( Varptr value )
  234. Cast<UInt Ptr>( _data+offset )[0]=value
  235. End
  236. #rem monkeydoc Writes a 64 bit long to the databuffer
  237. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  238. @param offset The offset to write.
  239. #end
  240. Method PokeLong( offset:Int,value:Long )
  241. DebugAssert( offset>=0 And offset<_length-7 )
  242. If _swapEndian Swap8( Varptr value )
  243. Cast<Long Ptr>( _data+offset )[0]=value
  244. End
  245. #rem monkeydoc Writes a 64 bit unsigned long to the databuffer
  246. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  247. @param offset The offset to write.
  248. #end
  249. Method PokeULong( offset:Int,value:ULong )
  250. DebugAssert( offset>=0 And offset<_length-7 )
  251. If _swapEndian Swap8( Varptr value )
  252. Cast<ULong Ptr>( _data+offset )[0]=value
  253. End
  254. #rem monkeydoc Writes a 32 bit float to the databuffer
  255. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  256. @param offset The offset to write.
  257. #end
  258. Method PokeFloat( offset:Int,value:Float )
  259. DebugAssert( offset>=0 And offset<_length-3 )
  260. If _swapEndian Swap4( Varptr value )
  261. Cast<Float Ptr>( _data+offset )[0]=value
  262. End
  263. #rem monkeydoc Writes a 64 bit double to the databuffer
  264. In debug builds, a runtime error will occur if `offset` is outside the range of the databuffer.
  265. @param offset The offset to write.
  266. #end
  267. Method PokeDouble( offset:Int,value:Double )
  268. DebugAssert( offset>=0 And offset<_length-7 )
  269. If _swapEndian Swap8( Varptr value )
  270. Cast<Double Ptr>( _data+offset )[0]=value
  271. End
  272. #rem monkeydoc Write a string to the databuffer.
  273. If there is not enough room in the data buffer, the string data is truncated.
  274. @param offset Byte offset to write the string.
  275. @param value The string to write.
  276. #end
  277. Method PokeString( offset:Int,value:String )
  278. DebugAssert( offset>=0 And offset<=_length )
  279. Local count:=value.Length
  280. If offset+count>_length count=_length-offset
  281. value.ToCString( _data+offset,count )
  282. End
  283. #rem monkeydoc Creates a slice of the databuffer.
  284. #end
  285. Method Slice:DataBuffer( from:Int=0 )
  286. Return Slice( from,_length )
  287. End
  288. Method Slice:DataBuffer( from:Int,term:int )
  289. If from<0
  290. from+=_length
  291. Else If from>_length
  292. from=_length
  293. Endif
  294. If term<0
  295. term+=_length
  296. If term<from term=from
  297. Else If term<from
  298. term=from
  299. Else If term>_length
  300. term=_length
  301. Endif
  302. Local newlen:=term-from
  303. Local data:=New DataBuffer( newlen )
  304. CopyTo( data,from,0,newlen )
  305. Return data
  306. End
  307. #rem monkeydoc Copies databuffer data to another databuffer.
  308. In debug builds, a runtime error while occur if an attempt it made to copy data outside the range of either databuffer.
  309. @param dst The destination databuffer.
  310. @param srcOffset The starting byte offset in this databuffer to copy from.
  311. @param dstOffset The starting byte offest in the destination databuffer to copy to.
  312. @param count The number of bytes to copy.
  313. #end
  314. Method CopyTo( dst:DataBuffer,srcOffset:Int,dstOffset:Int,count:Int )
  315. DebugAssert( srcOffset>=0 And srcOffset+count<=_length And dstOffset>=0 And dstOffset+count<=dst._length )
  316. libc.memmove( dst._data+dstOffset,_data+srcOffset,count )
  317. End
  318. #rem monkeydoc Saves the contents of the databuffer to a file.
  319. @param path The file path.
  320. @return True if successful, false if `path` could not be opened or not all data could be written.
  321. #end
  322. Method Save:Bool( path:String )
  323. Local stream:=Stream.Open( path,"w" )
  324. If Not stream Return False
  325. Local n:=stream.Write( _data,_length )
  326. stream.Close()
  327. Return n=_length
  328. End
  329. #rem monkeydoc Creates a databuffer with the contents of a file.
  330. @param path The file path.
  331. @return A new databuffer containing the contents of `path`, or null if `path` could not be opened.
  332. #end
  333. Function Load:DataBuffer( path:String )
  334. Local stream:=Stream.Open( path,"r" )
  335. If Not stream Return Null
  336. Local data:=stream.ReadAll()
  337. stream.Close()
  338. Return data
  339. End
  340. Private
  341. Field _data:UByte Ptr
  342. Field _length:Int
  343. Field _byteOrder:ByteOrder
  344. Field _swapEndian:Bool
  345. Function Swap2( v:Void Ptr )
  346. Local t:=Cast<UShort Ptr>( v )[0]
  347. Cast<UShort Ptr>( v )[0]=(t Shr 8 & $ff) | (t & $ff) Shl 8
  348. End
  349. Function Swap4( v:Void Ptr )
  350. Local t:=Cast<UInt Ptr>( v )[0]
  351. Cast<UInt Ptr>( v )[0]=(t Shr 24 & $ff) | (t & $ff) Shl 24 | (t Shr 8 & $ff00) | (t & $ff00) Shl 8
  352. End
  353. Function Swap8( v:Void Ptr )
  354. Local t:=Cast<ULong Ptr>( v )[0]
  355. Cast<ULong Ptr>( v )[0]=(t Shr 56 & $ff) | (t & $ff) Shl 56 | (t Shr 40 & $ff00) | (t & $ff00) Shl 40 | (t Shr 24 & $ff0000) | (t & $ff0000) Shl 24 | (t Shr 8 & $ff000000) | (t & $ff000000) Shl 8
  356. End
  357. End