bytebuffer.bmx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. ' Copyright (c) 2024 Bruce A Henderson
  2. '
  3. ' This software is provided 'as-is', without any express or implied
  4. ' warranty. In no event will the authors be held liable for any damages
  5. ' arising from the use of this software.
  6. '
  7. ' Permission is granted to anyone to use this software for any purpose,
  8. ' including commercial applications, and to alter it and redistribute it
  9. ' freely, subject to the following restrictions:
  10. '
  11. ' 1. The origin of this software must not be misrepresented; you must not
  12. ' claim that you wrote the original software. If you use this software
  13. ' in a product, an acknowledgment in the product documentation would be
  14. ' appreciated but is not required.
  15. ' 2. Altered source versions must be plainly marked as such, and must not be
  16. ' misrepresented as being the original software.
  17. ' 3. This notice may not be removed or altered from any source distribution.
  18. '
  19. SuperStrict
  20. Rem
  21. bbdoc: Byte Buffer
  22. End Rem
  23. Module BRL.ByteBuffer
  24. ModuleInfo "Version: 1.02"
  25. ModuleInfo "License: zlib/libpng"
  26. ModuleInfo "Copyright: 2024 Bruce A Henderson"
  27. ModuleInfo "History: 1.02"
  28. ModuleInfo "History: Added Slice() and Compact() methods"
  29. ModuleInfo "History: 1.01"
  30. ModuleInfo "History: Added GetBytes() and PutBytes()"
  31. ModuleInfo "History: 1.00 Initial Release"
  32. Import "glue.c"
  33. Rem
  34. bbdoc: The byte order.
  35. End Rem
  36. Enum EByteOrder
  37. BigEndian
  38. LittleEndian
  39. End Enum
  40. Rem
  41. bbdoc: A buffer is a list of elements of a specific type.
  42. End Rem
  43. Type TBuffer Abstract
  44. Protected
  45. Field ReadOnly _size:Int
  46. Field _limit:Int
  47. Field _mark:Int = -1
  48. Field _position:Int
  49. Method New(size:Int)
  50. _size = size
  51. _limit = size
  52. End Method
  53. Method New(mark:Int, position:Int, limit:Int, capacity:Int)
  54. _mark = mark
  55. _position = position
  56. _limit = limit
  57. _size = capacity
  58. End Method
  59. Public
  60. Rem
  61. bbdoc: Clears the buffer.
  62. about: Does not change the the content of the buffer, other than to set the position to zero, the mark is cleared, and the limit is set to buffer size.
  63. End Rem
  64. Method Clear:TBuffer()
  65. _position = 0
  66. _limit = _size
  67. _mark = -1
  68. Return Self
  69. End Method
  70. Rem
  71. bbdoc: Flips the buffer.
  72. about: The limit is set to the current position, position set to zero, and the mark is cleared.
  73. End Rem
  74. Method Flip:TBuffer()
  75. _limit = _position
  76. _position = 0
  77. _mark = -1
  78. Return Self
  79. End Method
  80. Rem
  81. bbdoc: Return the buffer limit.
  82. End Rem
  83. Method Limit:Int()
  84. Return _limit
  85. End Method
  86. Rem
  87. bbdoc: Sets the buffer limit.
  88. End Rem
  89. Method Limit:TBuffer(newLimit:Int)
  90. If newLimit < 0 Or newLimit > _size Then
  91. Throw "Bad limit"
  92. End If
  93. _limit = newLimit
  94. If _position > newLimit Then
  95. _position = newLimit
  96. End If
  97. If _mark <> -1 And _mark > newLimit Then
  98. _mark = -1
  99. End If
  100. Return Self
  101. End Method
  102. Rem
  103. bbdoc: Marks the current position that can be returned to later with a call to #Reset.
  104. End Rem
  105. Method Mark:TBuffer()
  106. _mark = _position
  107. Return Self
  108. End Method
  109. Rem
  110. bbdoc: Returns the current position of the buffer.
  111. End Rem
  112. Method Position:Int()
  113. Return _position
  114. End Method
  115. Rem
  116. bbdoc: Sets the position of the buffer.
  117. End Rem
  118. Method Position:TBuffer(newPos:Int)
  119. DoSetPosition(newPos)
  120. Return Self
  121. End Method
  122. Protected
  123. Method DoSetPosition(newPos:Int)
  124. If newPos < 0 Or newPos > _limit Then
  125. Throw "Bad position"
  126. End If
  127. _position = newPos
  128. If _mark <> -1 And _mark > _position Then
  129. _mark = -1
  130. End If
  131. End Method
  132. Public
  133. Rem
  134. bbdoc: Returns whether there are any bytes remaining in the buffer.
  135. End Rem
  136. Method HasRemaining:Int()
  137. Return _position < _limit
  138. End Method
  139. Rem
  140. bbdoc: Returns the number of bytes remaining in the buffer.
  141. End Rem
  142. Method Remaining:Int()
  143. Return _limit - _position
  144. End Method
  145. Rem
  146. bbdoc: Resets the current position to that of the last mark.
  147. about: If mark is not set, this method will throw.
  148. End Rem
  149. Method Reset:TBuffer()
  150. If _mark = -1 Then
  151. Throw "Mark not set"
  152. End If
  153. _position = _mark
  154. Return Self
  155. End Method
  156. Rem
  157. bbdoc: Rewinds the the position back to the start of the buffer.
  158. End Rem
  159. Method Rewind:TBuffer()
  160. _position = 0
  161. _mark = -1
  162. Return Self
  163. End Method
  164. End Type
  165. Rem
  166. bbdoc: A #TBuffer for bytes.
  167. End Rem
  168. Type TByteBuffer Extends TBuffer
  169. Field _order:EByteOrder = EByteOrder.BigEndian
  170. Rem
  171. bbdoc: Allocates a new #TByteBuffer of the specific @size number of bytes.
  172. End Rem
  173. Function Allocate:TByteBuffer(size:Int)
  174. Assert size >= 0 Else "Size < 0 : " + size
  175. Return New TByteArrayBuffer(New Byte[size])
  176. End Function
  177. Rem
  178. bbdoc: Creates a new #TByteBuffer by wrapping the provided #Byte array.
  179. End Rem
  180. Function Wrap:TByteBuffer(data:Byte[])
  181. Return New TByteArrayBuffer(data)
  182. End Function
  183. Rem
  184. bbdoc: Creates a new #TByteBuffer by wrapping the provided Byte Ptr.
  185. about: Note that the Byte Ptr is expected to remain valid throughout the use of the #TByteBuffer.
  186. Freeing the associated memory early may result in undefined behaviour.
  187. End Rem
  188. Function Wrap:TByteBuffer(data:Byte Ptr, size:Int)
  189. Return New TBytePtrBuffer(data, size)
  190. End Function
  191. Rem
  192. bbdoc: Gets the byte order used by the #TByteBuffer when doing #Byte conversions.
  193. End Rem
  194. Method Order:EByteOrder()
  195. Return _order
  196. End Method
  197. Rem
  198. bbdoc: Sets the byte order to use by the #TByteBuffer when doing #Byte conversions.
  199. End Rem
  200. Method Order:TByteBuffer(byteOrder:EByteOrder)
  201. _order = byteOrder
  202. Return Self
  203. End Method
  204. Rem
  205. bbdoc: Returns the #Byte at the current position, and increments the position by 1.
  206. End Rem
  207. Method Get:Byte() Abstract
  208. Rem
  209. bbdoc: Returns the #Short at the current position, and increments the position by 2.
  210. End Rem
  211. Method GetShort:Short() Abstract
  212. Rem
  213. bbdoc: Returns the #Int at the current position, and increments the position by 4.
  214. End Rem
  215. Method GetInt:Int() Abstract
  216. Rem
  217. bbdoc: Returns the #UInt at the current position, and increments the position by 4.
  218. End Rem
  219. Method GetUInt:UInt() Abstract
  220. Rem
  221. bbdoc: Returns the #Long at the current position, and increments the position by 8.
  222. End Rem
  223. Method GetLong:Long() Abstract
  224. Rem
  225. bbdoc: Returns the #ULong at the current position, and increments the position by 8.
  226. End Rem
  227. Method GetULong:ULong() Abstract
  228. Rem
  229. bbdoc: Returns the #Size_T at the current position, and increments the position by 8 (64-bit) or 4 (32-bit).
  230. End Rem
  231. Method GetSizeT:Size_T() Abstract
  232. Rem
  233. bbdoc: Returns the #Float at the current position, and increments the position by 4.
  234. End Rem
  235. Method GetFloat:Float() Abstract
  236. Rem
  237. bbdoc: Returns the #Double at the current position, and increments the position by 8.
  238. End Rem
  239. Method GetDouble:Double() Abstract
  240. Rem
  241. bbdoc: Copies @length bytes into @dst at the curent position, and increments the position by @length.
  242. End Rem
  243. Method GetBytes(dst:Byte Ptr, length:UInt) Abstract
  244. Rem
  245. bbdoc: Writes the specified #Byte to the current position and increments the position by 1.
  246. End Rem
  247. Method Put:TByteBuffer(value:Byte) Abstract
  248. Rem
  249. bbdoc: Writes the specified #Short to the current position and increments the position by 2.
  250. End Rem
  251. Method PutShort:TByteBuffer(value:Short) Abstract
  252. Rem
  253. bbdoc: Writes the specified #Int to the current position and increments the position by 4.
  254. End Rem
  255. Method PutInt:TByteBuffer(value:Int) Abstract
  256. Rem
  257. bbdoc: Writes the specified #UInt to the current position and increments the position by 4.
  258. End Rem
  259. Method PutUInt:TByteBuffer(value:UInt) Abstract
  260. Rem
  261. bbdoc: Writes the specified #Long to the current position and increments the position by 8.
  262. End Rem
  263. Method PutLong:TByteBuffer(value:Long) Abstract
  264. Rem
  265. bbdoc: Writes the specified #ULong to the current position and increments the position by 8.
  266. End Rem
  267. Method PutULong:TByteBuffer(value:ULong) Abstract
  268. Rem
  269. bbdoc: Writes the specified #Size_T to the current position and increments the position by 8 (64-bit) or 4 (32-bit).
  270. End Rem
  271. Method PutSizeT:TByteBuffer(value:Size_T) Abstract
  272. Rem
  273. bbdoc: Writes the specified #Float to the current position and increments the position by 4.
  274. End Rem
  275. Method PutFloat:TByteBuffer(value:Float) Abstract
  276. Rem
  277. bbdoc: Writes the specified #Double to the current position and increments the position by 8.
  278. End Rem
  279. Method PutDouble:TByteBuffer(value:Double) Abstract
  280. Rem
  281. bbdoc: Writes the specified number of bytes to the current position.
  282. End Rem
  283. Method PutBytes:TByteBuffer(bytes:Byte Ptr, length:UInt) Abstract
  284. Rem
  285. bbdoc: Returns a sliced #TByteBuffer that shares its content with this one.
  286. about: The new buffer's position, limit, and mark are independent of this buffer.
  287. End Rem
  288. Method Slice:TByteBuffer() Abstract
  289. Rem
  290. bbdoc: Returns a sliced #TByteBuffer that shares its content with this one.
  291. about: The new buffer's position, limit, and mark are independent of this buffer.
  292. End Rem
  293. Method Slice:TByteBuffer(length:Int) Abstract
  294. Rem
  295. bbdoc: Creates a duplicate #TByteBuffer that shares its content with this one.
  296. End Rem
  297. Method Duplicate:TByteBuffer() Abstract
  298. Rem
  299. bbdoc: Compacts this #TByteBuffer.
  300. End Rem
  301. Method Compact:TByteBuffer() Abstract
  302. Method BytePtr:Byte Ptr() Abstract
  303. Method Offset:Int() Abstract
  304. End Type
  305. Rem
  306. bbdoc: A #TBuffer whose data comes from a Byte Ptr.
  307. End Rem
  308. Type TBytePtrBuffer Extends TByteBuffer
  309. Field _readOnly:Int
  310. Field _data:Byte Ptr
  311. Field _offset:Int
  312. Method New(data:Byte Ptr, size:Int, offset:Int = 0, isReadOnly:Int = False)
  313. Super.New(size)
  314. Self._data = data
  315. Self._offset = offset
  316. Self._readOnly = isReadOnly
  317. End Method
  318. Method Get:Byte() Override
  319. If _position = _limit Then
  320. Throw New TBufferUnderflowException
  321. End If
  322. Local result:Byte = _data[_position]
  323. _position :+ 1
  324. Return result
  325. End Method
  326. Method GetShort:Short() Override
  327. Local newPosition:Int = _position + 2
  328. If newPosition > _limit Then
  329. Throw New TBufferUnderflowException
  330. End If
  331. Local result:Short
  332. Local pos:Int = _position + _offset
  333. If _order = EByteOrder.BigEndian Then
  334. result = (_data[pos] Shl 8) | (_data[pos + 1] & $ff)
  335. Else
  336. result = (_data[pos + 1] Shl 8) | (_data[pos] & $ff)
  337. End If
  338. _position = newPosition
  339. Return result
  340. End Method
  341. Method GetFloat:Float() Override
  342. Return bmx_bytebuffer_intbitstofloat(GetInt())
  343. End Method
  344. Method GetDouble:Double() Override
  345. Return bmx_bytebuffer_longbitstodouble(GetLong())
  346. End Method
  347. Method GetInt:Int() Override
  348. Local newPosition:Int = _position + 4
  349. If newPosition > _limit Then
  350. Throw New TBufferUnderflowException
  351. End If
  352. Local result:Int
  353. Local pos:Int = _position + _offset
  354. If _order = EByteOrder.BigEndian Then
  355. result = ((_data[pos] & $ff) Shl 24) | ((_data[pos + 1] & $ff) Shl 16) | ((_data[pos + 2] & $ff) Shl 8) | (_data[pos + 3] & $ff)
  356. Else
  357. result = (_data[pos] & $ff) | ((_data[pos + 1] & $ff) Shl 8) | ((_data[pos + 2] & $ff) Shl 16) | ((_data[pos + 3] & $ff) Shl 24)
  358. End If
  359. _position = newPosition
  360. Return result
  361. End Method
  362. Method GetUInt:UInt() Override
  363. Local newPosition:Int = _position + 4
  364. If newPosition > _limit Then
  365. Throw New TBufferUnderflowException
  366. End If
  367. Local result:UInt
  368. Local pos:Int = _position + _offset
  369. If _order = EByteOrder.BigEndian Then
  370. result = ((_data[pos] & $ff:UInt) Shl 24) | ((_data[pos + 1] & $ff:UInt) Shl 16) | ((_data[pos + 2] & $ff:UInt) Shl 8) | (_data[pos + 3] & $ff:UInt)
  371. Else
  372. result = (_data[pos] & $ff:UInt) | ((_data[pos + 1] & $ff:UInt) Shl 8) | ((_data[pos + 2] & $ff:UInt) Shl 16) | ((_data[pos + 3] & $ff:UInt) Shl 24)
  373. End If
  374. _position = newPosition
  375. Return result
  376. End Method
  377. Method GetLong:Long() Override
  378. Local newPosition:Int = _position + 8
  379. If newPosition > _limit Then
  380. Throw New TBufferUnderflowException
  381. End If
  382. Local result:Long
  383. Local pos:Int = _position + _offset
  384. If _order = EByteOrder.BigEndian Then
  385. Local high:Int = ((_data[pos] & $ff) Shl 24) | ((_data[pos + 1] & $ff) Shl 16) | ((_data[pos + 2] & $ff) Shl 8) | (_data[pos + 3] & $ff)
  386. Local low:Int = ((_data[pos + 4] & $ff) Shl 24) | ((_data[pos + 5] & $ff) Shl 16) | ((_data[pos + 6] & $ff) Shl 8) | (_data[pos + 7] & $ff)
  387. result = (Long(high) Shl 32) | (Long(low) & $ffffffff:Long)
  388. Else
  389. Local low:Int = (_data[pos] & $ff) | ((_data[pos + 1] & $ff) Shl 8) | ((_data[pos + 2] & $ff) Shl 16) | ((_data[pos + 3] & $ff) Shl 24)
  390. Local high:Int = (_data[pos + 4] & $ff) | ((_data[pos + 5] & $ff) Shl 8) | ((_data[pos + 6] & $ff) Shl 16) | ((_data[pos + 7] & $ff) Shl 24)
  391. result = (Long(high) Shl 32) | (Long(low) & $ffffffff:Long)
  392. End If
  393. _position = newPosition
  394. Return result
  395. End Method
  396. Method GetULong:ULong() Override
  397. Local newPosition:Int = _position + 8
  398. If newPosition > _limit Then
  399. Throw New TBufferUnderflowException
  400. End If
  401. Local result:ULong
  402. Local pos:Int = _position + _offset
  403. If _order = EByteOrder.BigEndian Then
  404. Local high:UInt = ((_data[pos] & $ff:UInt) Shl 24) | ((_data[pos + 1] & $ff:UInt) Shl 16) | ((_data[pos + 2] & $ff:UInt) Shl 8) | (_data[pos + 3] & $ff:UInt)
  405. Local low:UInt = ((_data[pos + 4] & $ff:UInt) Shl 24) | ((_data[pos + 5] & $ff:UInt) Shl 16) | ((_data[pos + 6] & $ff) Shl 8) | (_data[pos + 7] & $ff)
  406. result = (ULong(high) Shl 32) | (Long(low) & $ffffffff:ULong)
  407. Else
  408. Local low:UInt = (_data[pos] & $ff:UInt) | ((_data[pos + 1] & $ff:UInt) Shl 8) | ((_data[pos + 2] & $ff:UInt) Shl 16) | ((_data[pos + 3] & $ff:UInt) Shl 24)
  409. Local high:UInt = (_data[pos + 4] & $ff:UInt) | ((_data[pos + 5] & $ff:UInt) Shl 8) | ((_data[pos + 6] & $ff:UInt) Shl 16) | ((_data[pos + 7] & $ff:UInt) Shl 24)
  410. result = (ULong(high) Shl 32) | (ULong(low) & $ffffffff:ULong)
  411. End If
  412. _position = newPosition
  413. Return result
  414. End Method
  415. Method GetSizeT:Size_T() Override
  416. ?ptr64
  417. Return Size_T(GetULong())
  418. ?Not ptr64
  419. Return Size_T(GetUInt())
  420. ?
  421. End Method
  422. Method GetBytes(dst:Byte Ptr, length:UInt)
  423. Local newPosition:Int = _position + length
  424. If newPosition > _limit Then
  425. Throw New TBufferUnderflowException
  426. End If
  427. Local pos:Int = _position + _offset
  428. MemCopy(dst, _data + pos, Size_T(length))
  429. _position = newPosition
  430. End Method
  431. Method Put:TByteBuffer(value:Byte) Override
  432. If _readOnly Then
  433. Throw New TReadOnlyBufferException
  434. End If
  435. If _position = _limit Then
  436. Throw New TBufferOverflowException
  437. End If
  438. _data[_position] = value
  439. _position :+ 1
  440. Return Self
  441. End Method
  442. Method PutShort:TByteBuffer(value:Short) Override
  443. If _readOnly Then
  444. Throw New TReadOnlyBufferException
  445. End If
  446. Local newPosition:Int = _position + 2
  447. If newPosition > _limit Then
  448. Throw New TBufferOverflowException
  449. End If
  450. Local pos:Int = _offset + _position
  451. If _order = EByteOrder.BigEndian Then
  452. _data[pos] = Byte((value Shr 8) & $ff)
  453. _data[pos + 1] = Byte(value & $ff)
  454. Else
  455. _data[pos] = Byte(value & $ff)
  456. _data[pos + 1] = Byte((value Shr 8) & $ff)
  457. End If
  458. _position = newPosition
  459. Return Self
  460. End Method
  461. Method PutInt:TByteBuffer(value:Int) Override
  462. If _readOnly Then
  463. Throw New TReadOnlyBufferException
  464. End If
  465. Local newPosition:Int = _position + 4
  466. If newPosition > _limit Then
  467. Throw New TBufferOverflowException
  468. End If
  469. Local pos:Int = _offset + _position
  470. If _order = EByteOrder.BigEndian Then
  471. _data[pos] = Byte((value Shr 24) & $ff)
  472. _data[pos + 1] = Byte((value Shr 16) & $ff)
  473. _data[pos + 2] = Byte((value Shr 8) & $ff)
  474. _data[pos + 3] = Byte(value & $ff)
  475. Else
  476. _data[pos] = Byte(value & $ff)
  477. _data[pos + 1] = Byte((value Shr 8) & $ff)
  478. _data[pos + 2] = Byte((value Shr 16) & $ff)
  479. _data[pos + 3] = Byte((value Shr 24) & $ff)
  480. End If
  481. _position = newPosition
  482. Return Self
  483. End Method
  484. Method PutUInt:TByteBuffer(value:UInt) Override
  485. If _readOnly Then
  486. Throw New TReadOnlyBufferException
  487. End If
  488. Local newPosition:Int = _position + 4
  489. If newPosition > _limit Then
  490. Throw New TBufferOverflowException
  491. End If
  492. Local pos:Int = _offset + _position
  493. If _order = EByteOrder.BigEndian Then
  494. _data[pos] = Byte((value Shr 24) & $ff)
  495. _data[pos + 1] = Byte((value Shr 16) & $ff)
  496. _data[pos + 2] = Byte((value Shr 8) & $ff)
  497. _data[pos + 3] = Byte(value & $ff)
  498. Else
  499. _data[pos] = Byte(value & $ff)
  500. _data[pos + 1] = Byte((value Shr 8) & $ff)
  501. _data[pos + 2] = Byte((value Shr 16) & $ff)
  502. _data[pos + 3] = Byte((value Shr 24) & $ff)
  503. End If
  504. _position = newPosition
  505. Return Self
  506. End Method
  507. Method PutLong:TByteBuffer(value:Long) Override
  508. If _readOnly Then
  509. Throw New TReadOnlyBufferException
  510. End If
  511. Local newPosition:Int = _position + 8
  512. If newPosition > _limit Then
  513. Throw New TBufferOverflowException
  514. End If
  515. Local pos:Int = _offset + _position
  516. If _order = EByteOrder.BigEndian Then
  517. Local i:Int = Int(value Shr 32)
  518. _data[pos] = Byte((i Shr 24) & $ff)
  519. _data[pos + 1] = Byte((i Shr 16) & $ff)
  520. _data[pos + 2] = Byte((i Shr 8) & $ff)
  521. _data[pos + 3] = Byte(i & $ff)
  522. i = Int(value)
  523. _data[pos + 4] = Byte((i Shr 24) & $ff)
  524. _data[pos + 5] = Byte((i Shr 16) & $ff)
  525. _data[pos + 6] = Byte((i Shr 8) & $ff)
  526. _data[pos + 7] = Byte(i & $ff)
  527. Else
  528. Local i:Int = Int(value)
  529. _data[pos] = Byte(i & $ff)
  530. _data[pos + 1] = Byte((i Shr 8) & $ff)
  531. _data[pos + 2] = Byte((i Shr 16) & $ff)
  532. _data[pos + 3] = Byte((i Shr 24) & $ff)
  533. i = Int(value Shr 32)
  534. _data[pos + 4] = Byte(i & $ff)
  535. _data[pos + 5] = Byte((i Shr 8) & $ff)
  536. _data[pos + 6] = Byte((i Shr 16) & $ff)
  537. _data[pos + 7] = Byte((i Shr 24) & $ff)
  538. End If
  539. _position = newPosition
  540. Return Self
  541. End Method
  542. Method PutULong:TByteBuffer(value:ULong) Override
  543. If _readOnly Then
  544. Throw New TReadOnlyBufferException
  545. End If
  546. Local newPosition:Int = _position + 8
  547. If newPosition > _limit Then
  548. Throw New TBufferOverflowException
  549. End If
  550. Local pos:Int = _offset + _position
  551. If _order = EByteOrder.BigEndian Then
  552. Local i:UInt = UInt(value Shr 32)
  553. _data[pos] = Byte((i Shr 24) & $ff)
  554. _data[pos + 1] = Byte((i Shr 16) & $ff)
  555. _data[pos + 2] = Byte((i Shr 8) & $ff)
  556. _data[pos + 3] = Byte(i & $ff)
  557. i = UInt(value)
  558. _data[pos + 4] = Byte((i Shr 24) & $ff)
  559. _data[pos + 5] = Byte((i Shr 16) & $ff)
  560. _data[pos + 6] = Byte((i Shr 8) & $ff)
  561. _data[pos + 7] = Byte(i & $ff)
  562. Else
  563. Local i:UInt = UInt(value)
  564. _data[pos] = Byte(i & $ff)
  565. _data[pos + 1] = Byte((i Shr 8) & $ff)
  566. _data[pos + 2] = Byte((i Shr 16) & $ff)
  567. _data[pos + 3] = Byte((i Shr 24) & $ff)
  568. i = UInt(value Shr 32)
  569. _data[pos + 4] = Byte(i & $ff)
  570. _data[pos + 5] = Byte((i Shr 8) & $ff)
  571. _data[pos + 6] = Byte((i Shr 16) & $ff)
  572. _data[pos + 7] = Byte((i Shr 24) & $ff)
  573. End If
  574. _position = newPosition
  575. Return Self
  576. End Method
  577. Method PutSizeT:TByteBuffer(value:Size_T) Override
  578. ?ptr64
  579. Return PutULong(ULong(value))
  580. ?Not ptr64
  581. Return PutUInt(UInt(value))
  582. ?
  583. End Method
  584. Method PutFloat:TByteBuffer(value:Float) Override
  585. Return PutInt(bmx_bytebuffer_floattointbits(value))
  586. End Method
  587. Method PutDouble:TByteBuffer(value:Double) Override
  588. Return PutLong(bmx_bytebuffer_doubletolongbits(value))
  589. End Method
  590. Method PutBytes:TByteBuffer(bytes:Byte Ptr, length:UInt) Override
  591. If _readOnly Then
  592. Throw New TReadOnlyBufferException
  593. End If
  594. Local newPosition:Int = _position + length
  595. If newPosition > _limit Then
  596. Throw New TBufferOverflowException
  597. End If
  598. Local pos:Int = _offset + _position
  599. MemCopy(_data + pos, bytes, Size_T(length))
  600. _position = newPosition
  601. Return Self
  602. End Method
  603. Method Slice:TByteBuffer() Override
  604. Return New TBytePtrBuffer(_data, remaining(), _offset + _position, _readOnly)
  605. End Method
  606. Method Slice:TByteBuffer(length:Int) Override
  607. If length > remaining() Then
  608. Throw New TBufferOverflowException
  609. End If
  610. Return New TBytePtrBuffer(_data, length, _offset + _position, _readOnly)
  611. End Method
  612. Method Duplicate:TByteBuffer() Override
  613. Return Copy(Self, _mark, _readOnly)
  614. End Method
  615. Method Compact:TByteBuffer() Override
  616. Local remaining:Int
  617. If _position <= _limit Then
  618. remaining = _limit - _position
  619. End If
  620. MemCopy(_data + _offset, _data + _offset + _position, Size_T(remaining))
  621. Position(remaining)
  622. Limit(_size)
  623. _mark = -1
  624. Return Self
  625. End Method
  626. Method BytePtr:Byte Ptr()
  627. If _readOnly Then
  628. Throw New TReadOnlyBufferException()
  629. End If
  630. Return _data
  631. End Method
  632. Method Offset:Int()
  633. Return _offset
  634. End Method
  635. Private
  636. Function Copy:TBytePtrBuffer(buffer:TBytePtrBuffer, mark:Int, isReadOnly:Int)
  637. Local bufCopy:TBytePtrBuffer = New TBytePtrBuffer(buffer._data, buffer._size, buffer._offset, isReadOnly)
  638. bufCopy._limit = buffer._limit
  639. bufCopy._position = buffer.Position()
  640. bufCopy._mark = mark
  641. Return bufCopy
  642. End Function
  643. End Type
  644. Rem
  645. bbdoc: A #TBuffer whose data comes from a #Byte array.
  646. End Rem
  647. Type TByteArrayBuffer Extends TBytePtrBuffer
  648. Field _array:Byte[]
  649. Method New(data:Byte[])
  650. Super.New(data, data.length)
  651. Self._array = data
  652. End Method
  653. Private
  654. Method New(data:Byte[], size:Int, offset:Int, isReadOnly:Int)
  655. Super.New(data, size)
  656. Self._array = data
  657. Self._offset = offset
  658. Self._readOnly = isReadOnly
  659. If offset + size > data.length Then
  660. Throw New TArrayBoundsException
  661. End If
  662. End Method
  663. Function Copy:TByteArrayBuffer(buffer:TByteArrayBuffer, mark:Int, isReadOnly:Int)
  664. Local bufCopy:TByteArrayBuffer = New TByteArrayBuffer(buffer._array, buffer._size, buffer._offset, isReadOnly)
  665. bufCopy._limit = buffer._limit
  666. bufCopy._position = buffer.Position()
  667. bufCopy._mark = mark
  668. Return bufCopy
  669. End Function
  670. Public
  671. Method Slice:TByteBuffer() Override
  672. Return New TByteArrayBuffer(_array, remaining(), _offset + _position, _readOnly)
  673. End Method
  674. Method Slice:TByteBuffer(length:Int) Override
  675. If length > remaining() Then
  676. Throw New TBufferOverflowException
  677. End If
  678. Return New TByteArrayBuffer(_array, length, _offset + _position, _readOnly)
  679. End Method
  680. Method Duplicate:TByteBuffer() Override
  681. Return Copy(Self, _mark, _readOnly)
  682. End Method
  683. Method BytePtr:Byte Ptr()
  684. If _readOnly Then
  685. Throw New TReadOnlyBufferException()
  686. End If
  687. Return _array
  688. End Method
  689. End Type
  690. Type TBufferUnderflowException Extends TBlitzException
  691. End Type
  692. Type TBufferOverflowException Extends TBlitzException
  693. End Type
  694. Type TReadOnlyBufferException Extends TBlitzException
  695. End Type
  696. Private
  697. Extern
  698. Function bmx_bytebuffer_intbitstofloat:Float(value:Int)
  699. Function bmx_bytebuffer_floattointbits:Int(value:Float)
  700. Function bmx_bytebuffer_longbitstodouble:Double(value:Long)
  701. Function bmx_bytebuffer_doubletolongbits:Long(value:Double)
  702. End Extern