databuffer.monkey2 14 KB

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