stream.monkey2 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. Namespace std.stream
  2. Using libc
  3. Using std.memory
  4. Using std.collections
  5. #rem monkeydoc Stream class.
  6. #end
  7. Class Stream Extends std.resource.Resource
  8. #rem monkeydoc True if no more data can be read from the stream.
  9. #end
  10. Property Eof:Bool() Abstract
  11. #rem monkeydoc Current stream position.
  12. In the case of non-seekable streams, `Position` will always be -1.
  13. #end
  14. Property Position:Int() Abstract
  15. #rem monkeydoc Current stream length.
  16. In the case of non-seekable streams, `Length` is the number of bytes that can be read from the stream without 'blocking'.
  17. #end
  18. Property Length:Int() Abstract
  19. #rem monkeydoc Closes the stream.
  20. #end
  21. Method Close:Void()
  22. If Not _open Return
  23. _open-=1
  24. If _open Return
  25. If _sharedPath _shared.Remove( _sharedPath )
  26. OnClose()
  27. End
  28. #rem monkeydoc Seeks to a position in the stream.
  29. In debug builds, a runtime error will occur if the stream is not seekable or `position` is out of range.
  30. @param position The position to seek to.
  31. #end
  32. Method Seek( position:Int ) Abstract
  33. #rem monkeydoc Reads data from the stream into memory.
  34. Reads `count` bytes of data from the stream into either a raw memory pointer or a databuffer.
  35. Returns the number of bytes actually read.
  36. @param buf A pointer to the memory to read the data into.
  37. @param data The databuffer to read the data into.
  38. @param count The number of bytes to read from the stream.
  39. @return The number of bytes actually read.
  40. #end
  41. Method Read:Int( buf:Void Ptr,count:Int ) Abstract
  42. Method Read:Int( data:DataBuffer,offset:Int,count:Int )
  43. DebugAssert( offset>=0 And count>=0 And offset+count<=data.Length )
  44. Return Read( data.Data+offset,count )
  45. End
  46. #rem monkeydoc Writes data to the stream from memory.
  47. Writes `count` bytes of data to the stream from either a raw memory pointer or a databuffer.
  48. Returns the number of bytes actually written
  49. @param buf A pointer to the memory to write the data from.
  50. @param data The databuffer to write the data from.
  51. @param count The number of bytes to write to the stream.
  52. @return The number of bytes actually written.
  53. #end
  54. Method Write:Int( buf:Void Ptr,count:Int ) Abstract
  55. Method Write:Int( data:DataBuffer,offset:Int,count:Int )
  56. DebugAssert( offset>=0 And count>=0 And offset+count<=data.Length )
  57. Return Write( data.Data+offset,count )
  58. End
  59. #rem monkeydoc The byte order of the stream.
  60. The default byte order is ByteOrder.LittleEndian.
  61. #end
  62. Property ByteOrder:ByteOrder()
  63. Return _swap ? ByteOrder.BigEndian Else ByteOrder.LittleEndian
  64. Setter( byteOrder:ByteOrder )
  65. _swap=(byteOrder=ByteOrder.BigEndian)
  66. End
  67. #rem monkeydoc Reads as many bytes as possible from a stream into memory.
  68. Continously reads data from a stream until either `count` bytes are read or the end of stream is reached.
  69. Returns the number of bytes read or the data read.
  70. @param buf memory to read bytes into.
  71. @param data data buffer to read bytes into.
  72. @param count number of bytes to read.
  73. #end
  74. Method ReadAll:Int( buf:Void Ptr,count:Int )
  75. Local pos:=0
  76. While pos<count
  77. Local n:=Read( Cast<UByte Ptr>( buf )+pos,count-pos )
  78. If n<=0 Exit
  79. pos+=n
  80. Wend
  81. Return pos
  82. End
  83. Method ReadAll:Int( data:DataBuffer,offset:Int,count:Int )
  84. Return ReadAll( data.Data+offset,count )
  85. End
  86. Method ReadAll:DataBuffer( count:Int )
  87. Local data:=New DataBuffer( count )
  88. Local n:=ReadAll( data,0,count )
  89. If n=count Return data
  90. Local tmp:=data.Slice( 0,n )
  91. data.Discard()
  92. Return tmp
  93. End
  94. Method ReadAll:DataBuffer()
  95. If Length>=0 Return ReadAll( Length-Position )
  96. Local bufs:=New Stack<DataBuffer>
  97. Local buf:=New DataBuffer( 4096 ),pos:=0
  98. Repeat
  99. pos=ReadAll( buf,0,4096 )
  100. If pos<4096 Exit
  101. bufs.Push( buf )
  102. buf=New DataBuffer( 4096 )
  103. Forever
  104. Local len:=bufs.Length * 4096 + pos
  105. Local data:=New DataBuffer( len )
  106. pos=0
  107. For Local buf:=Eachin bufs
  108. buf.CopyTo( data,0,pos,4096 )
  109. buf.Discard()
  110. pos+=4096
  111. Next
  112. buf.CopyTo( data,0,pos,len-pos )
  113. buf.Discard()
  114. Return data
  115. End
  116. #rem monkeydoc Reads data from the stream and throws it away.
  117. @param count The number of bytes to skip.
  118. @return The number of bytes actually skipped.
  119. #end
  120. Method Skip:Int( count:Int )
  121. If count<=0 Return 0
  122. Local tmp:=libc.malloc( 4096 ),n:=0
  123. While n<count
  124. Local t:=Read( tmp,Min( count-n,4096 ) )
  125. If t<=0 Exit
  126. n+=t
  127. Wend
  128. libc.free( tmp )
  129. Return n
  130. End
  131. Property SharedPath:String()
  132. If Not _sharedPath
  133. Global sharedId:=0
  134. sharedId+=1
  135. Local path:="@"+sharedId
  136. _sharedPath="stream::"+path
  137. _shared[path]=Self
  138. Endif
  139. Return _sharedPath
  140. End
  141. #rem monkeydoc Reopens the stream.
  142. #end
  143. Method Reopen:Stream()
  144. _open+=1
  145. Return Self
  146. End
  147. #rem monkeydoc Reads a byte from the stream.
  148. @return The byte read.
  149. #end
  150. Method ReadByte:Byte()
  151. Local n:Byte
  152. Read( Varptr n,1 )
  153. Return n
  154. End
  155. #rem monkeydoc Reads an unsigned byte from the stream.
  156. @return The ubyte read.
  157. #end
  158. Method ReadUByte:UByte()
  159. Local n:UByte
  160. Read( Varptr n,1 )
  161. Return n
  162. End
  163. #rem monkeydoc Reads a 16 bit short from the stream.
  164. @return The short read.
  165. #end
  166. Method ReadShort:Short()
  167. Local n:Short
  168. If Read( Varptr n,2 )<>2 n=0
  169. If _swap Swap2( Varptr n )
  170. Return n
  171. End
  172. #rem monkeydoc Reads a 16 bit unsigned short from the stream.
  173. @return The ushort read.
  174. #end
  175. Method ReadUShort:UShort()
  176. Local n:UShort
  177. If Read( Varptr n,2 )<>2 n=0
  178. If _swap Swap2( Varptr n )
  179. Return n
  180. End
  181. #rem monkeydoc Reads a 32 bit int from the stream.
  182. @return The int read.
  183. #end
  184. Method ReadInt:Int()
  185. Local n:Int
  186. If Read( Varptr n,4 )<>4 n=0
  187. If _swap Swap4( Varptr n )
  188. Return n
  189. End
  190. #rem monkeydoc Reads a 32 bit unsigned int from the stream.
  191. @return The uint read.
  192. #end
  193. Method ReadUInt:UInt()
  194. Local n:UInt
  195. If Read( Varptr n,4 )<>4 n=0
  196. If _swap Swap4( Varptr n )
  197. Return n
  198. End
  199. #rem monkeydoc Reads a 32 bit long from the stream.
  200. @return The long read.
  201. #end
  202. Method ReadLong:Long()
  203. Local n:Long
  204. If Read( Varptr n,8 )<>8 n=0
  205. If _swap Swap8( Varptr n )
  206. Return n
  207. End
  208. #rem monkeydoc Reads a 32 bit unsigned long from the stream.
  209. @return The ulong read.
  210. #end
  211. Method ReadULong:ULong()
  212. Local n:ULong
  213. If Read( Varptr n,8 )<>8 n=0
  214. If _swap Swap8( Varptr n )
  215. Return n
  216. End
  217. #rem monkeydoc Reads a 32 bit float from the stream.
  218. @return The float read.
  219. #end
  220. Method ReadFloat:Float()
  221. Local n:Float
  222. If Read( Varptr n,4 )<>4 n=0
  223. If _swap Swap4( Varptr n )
  224. Return n
  225. End
  226. #rem monkeydoc Reads a 64 bit double from the stream.
  227. @return The double read.
  228. #end
  229. Method ReadDouble:Double()
  230. Local n:Double
  231. If Read( Varptr n,8 )<>8 n=0
  232. If _swap Swap8( Varptr n )
  233. Return n
  234. End
  235. #rem monkeydoc Reads the entire stream into a string.
  236. #end
  237. Method ReadString:String()
  238. Local data:=ReadAll()
  239. Local str:=data.PeekString( 0 )
  240. data.Discard()
  241. Return str
  242. End
  243. #rem monkeydoc Reads a size prefixed string from the stream.
  244. Reads an int from the stream, then a string from that many bytes.
  245. @return the string read.
  246. #end
  247. Method ReadSizedString:String()
  248. Local n:=ReadInt()
  249. Local data:=ReadAll( n )
  250. Local str:=data.PeekString( 0 )
  251. data.Discard()
  252. Return str
  253. End
  254. #rem monkeydoc Reads a null terminated cstring from the stream.
  255. @return the string read.
  256. #end
  257. Method ReadCString:String()
  258. Local buf:=New Stack<Byte>
  259. While Not Eof
  260. Local chr:=ReadByte()
  261. If Not chr Exit
  262. buf.Push( chr )
  263. Wend
  264. Return String.FromCString( buf.Data.Data,buf.Length )
  265. End
  266. #rem monkeydoc Reads a line of text from the stream.
  267. Bytes are read from the stream until a newline character (ascii code 10) or null character (ascii code 0) is read, or end of file is detected.
  268. The bytes read are returned in the form of a string, excluding any terminating newline or null character.
  269. Carriage return characters (ascii code 13) are silently ignored.
  270. #end
  271. Method ReadLine:String()
  272. Local buf:=New Stack<Byte>
  273. While Not Eof
  274. Local chr:=ReadByte()
  275. If Not chr Or chr=10 exit
  276. If chr=13 Continue
  277. buf.Push( chr )
  278. Wend
  279. Return String.FromCString( buf.Data.Data,buf.Length )
  280. End
  281. #rem monkeydoc Writes a byte to the stream.
  282. @param data The byte to write.
  283. #end
  284. Method WriteByte( data:Byte )
  285. Write( Varptr data,1 )
  286. End
  287. #rem monkeydoc Write an unsigned byte to the stream.
  288. @param data The ubyte to write.
  289. #end
  290. Method WriteUByte( data:UByte )
  291. Write( Varptr data,1 )
  292. End
  293. #rem monkeydoc Writes a 16 bit short to the stream.
  294. @param data The short to write.
  295. #end
  296. Method WriteShort( data:Short )
  297. If _swap Swap2( Varptr data )
  298. Write( Varptr data,2 )
  299. End
  300. #rem monkeydoc Writes a 16 bit unsigned short to the stream.
  301. @param data The ushort to write.
  302. #end
  303. Method WriteUShort( data:UShort )
  304. If _swap Swap2( Varptr data )
  305. Write( Varptr data,2 )
  306. End
  307. #rem monkeydoc Writes a 32 bit int to the stream.
  308. @param data The int to write.
  309. #end
  310. Method WriteInt( data:Int )
  311. If _swap Swap4( Varptr data )
  312. Write( Varptr data,4 )
  313. End
  314. #rem monkeydoc Writes a 32 bit unsigned int to the stream.
  315. @param data The uint to write.
  316. #end
  317. Method WriteUInt( data:UInt )
  318. If _swap Swap4( Varptr data )
  319. Write( Varptr data,4 )
  320. End
  321. #rem monkeydoc Writes a 64 bit long to the stream.
  322. @param data The long to write.
  323. #end
  324. Method WriteLong( data:Long )
  325. If _swap Swap8( Varptr data )
  326. Write( Varptr data,8 )
  327. End
  328. #rem monkeydoc Writes a 64 bit unsigned long to the stream.
  329. @param data The ulong to write.
  330. #end
  331. Method WriteULong( data:ULong )
  332. If _swap Swap8( Varptr data )
  333. Write( Varptr data,8 )
  334. End
  335. #rem monkeydoc Writes a 32 bit float to the stream,
  336. @param data The float to write.
  337. #end
  338. Method WriteFloat:Void( data:Float )
  339. If _swap Swap4( Varptr data )
  340. Write( Varptr data,4 )
  341. End
  342. #rem monkeydoc Writes a 64 bit double to the stream.
  343. @param data The double to write.
  344. #end
  345. Method WriteDouble( data:Double )
  346. If _swap Swap8( Varptr data )
  347. Write( Varptr data,8 )
  348. End
  349. #rem monkeydoc Writes a string to the stream (NOT null terminated).
  350. @param str The string to write.
  351. #end
  352. Method WriteString( str:String )
  353. Local buf:=New DataBuffer( str.CStringLength )
  354. buf.PokeString( 0,str )
  355. Write( buf,0,buf.Length )
  356. buf.Discard()
  357. End
  358. #rem monkeydoc Writes a size prefixed string to the stream.
  359. Writes an int containing the size of the string to the stream, followed the string itself.
  360. #end
  361. Method WriteSizedString( str:String )
  362. WriteInt( str.CStringLength )
  363. WriteString( str )
  364. End
  365. #rem monkeydoc Writes a null terminated cstring to the stream.
  366. @param str The string to write.
  367. #end
  368. Method WriteCString( str:String )
  369. WriteString( str )
  370. WriteByte( 0 )
  371. End
  372. #rem monkeydoc Writes a line of text to the stream.
  373. Writes the characters in `str` followed by the line terminating sequence "~r~n".
  374. #end
  375. Method WriteLine( str:String )
  376. WriteString( str )
  377. WriteString( "~r~n" )
  378. End
  379. #rem monkeydoc Opens a stream
  380. `mode` should be "r" for read, "w" for write or "rw" for read/write.
  381. If the stream could not be opened, null will be returned.
  382. When opening a file using "r" or "rw", the file must already exist or the function will fail and null will be returned.
  383. When opening a file using "w", any existing file at the same path will be overwritten.
  384. Stream paths may include the following prefixes:
  385. | Stream path prefix | Supported targets | Description
  386. |:----------------------|:------------------|:-----------
  387. | `asset::` | All | Open a stream for reading an app asset.
  388. | `internal::` | Mobile | Open a stream for reading/writing internal app storage.
  389. | `external::` | Android | Open a stream for reading/writing external app storage.
  390. | `home::` | Desktop | Open a stream for reading/writing a file in the user's home directory.
  391. | `desktop::` | Desktop | Open a stream for reading/writing a file in the user's desktop directory.
  392. @param mode The mode to open the stream in: "r", "w" or "rw"
  393. #end
  394. Function Open:Stream( path:String,mode:String )
  395. Local i:=path.Find( "::" )
  396. If i=-1 Return FileStream.Open( path,mode )
  397. Local proto:=path.Slice( 0,i )
  398. Local ipath:=path.Slice( i+2 )
  399. If proto="stream" Return _shared[ipath].Reopen()
  400. Return OpenFuncs[proto]( proto,ipath,mode )
  401. End
  402. #rem monkeydoc Stream open function type
  403. #end
  404. Alias OpenFunc:Stream( proto:String,path:String,mode:String )
  405. #rem monkeydoc Stream open functions map
  406. #end
  407. Const OpenFuncs:=New StringMap<OpenFunc>
  408. Protected
  409. Method New()
  410. _swap=false
  411. _open=1
  412. End
  413. Method OnClose() Virtual
  414. Discard()
  415. End
  416. Private
  417. Field _swap:Bool
  418. Field _open:Int
  419. Field _sharedPath:String
  420. Global _shared:=New StringMap<Stream>
  421. Function Swap2( v:Void Ptr )
  422. Local t:=Cast<UShort Ptr>( v )[0]
  423. Cast<UShort Ptr>( v )[0]=(t Shr 8 & $ff) | (t & $ff) Shl 8
  424. End
  425. Function Swap4( v:Void Ptr )
  426. Local t:=Cast<UInt Ptr>( v )[0]
  427. Cast<UInt Ptr>( v )[0]=(t Shr 24 & $ff) | (t & $ff) Shl 24 | (t Shr 8 & $ff00) | (t & $ff00) Shl 8
  428. End
  429. Function Swap8( v:Void Ptr )
  430. Local t:=Cast<ULong Ptr>( v )[0]
  431. 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
  432. End
  433. End