PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/sys/dotnet/fan/sys/InStream.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 774 lines | 615 code | 85 blank | 74 comment | 201 complexity | 461382187c4fe6923eefa16045225ba5 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2006, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 16 Jan 07 Andy Frank Creation
  7. //
  8. using System.Text;
  9. using Fanx.Serial;
  10. namespace Fan.Sys
  11. {
  12. /// <summary>
  13. /// InStream interface.
  14. /// </summary>
  15. public class InStream : FanObj
  16. {
  17. //////////////////////////////////////////////////////////////////////////
  18. // Construction
  19. //////////////////////////////////////////////////////////////////////////
  20. public static InStream make(InStream input)
  21. {
  22. InStream self = new InStream();
  23. make_(self, input);
  24. return self;
  25. }
  26. public static void make_(InStream self, InStream input)
  27. {
  28. self.m_in = input;
  29. }
  30. protected InStream()
  31. {
  32. m_charset = Charset.utf8();
  33. m_charsetDecoder = m_charset.newDecoder();
  34. m_charsetEncoder = m_charset.newEncoder();
  35. }
  36. //////////////////////////////////////////////////////////////////////////
  37. // Obj
  38. //////////////////////////////////////////////////////////////////////////
  39. public override Type @typeof() { return Sys.InStreamType; }
  40. //////////////////////////////////////////////////////////////////////////
  41. // C# Stream
  42. //////////////////////////////////////////////////////////////////////////
  43. /// <summary>
  44. /// Read a byte using a Java primitive int. Most
  45. /// reads route to this method for efficient mapping to
  46. /// a java.io.InputStream. If we aren't overriding this
  47. /// method, then route back to read() for the subclass
  48. /// to handle.
  49. /// </summary>
  50. public virtual int r()
  51. {
  52. Long n = read();
  53. if (n == null) return -1;
  54. return n.intValue();
  55. }
  56. /// <summary>
  57. /// Unread a byte using a .NET primitive int. If we aren't
  58. /// overriding this method, then route back to read() for the
  59. /// subclass to handle.
  60. /// </summary>
  61. public virtual InStream unread(int b)
  62. {
  63. return unread((long)b);
  64. }
  65. /// <summary>
  66. /// Read char as primitive int.
  67. /// </summary>
  68. public virtual int rChar()
  69. {
  70. return m_charsetDecoder.decode(this);
  71. }
  72. /// <summary>
  73. /// Unread char as primitive int.
  74. /// </summary>
  75. public virtual InStream unreadChar(int b)
  76. {
  77. return unreadChar((long)b);
  78. }
  79. //////////////////////////////////////////////////////////////////////////
  80. // InStream
  81. //////////////////////////////////////////////////////////////////////////
  82. public virtual Long read()
  83. {
  84. try
  85. {
  86. return m_in.read();
  87. }
  88. catch (System.NullReferenceException e)
  89. {
  90. if (m_in == null)
  91. throw UnsupportedErr.make(@typeof().qname() + " wraps null InStream").val;
  92. else
  93. throw e;
  94. }
  95. }
  96. public virtual Long readBuf(Buf buf, long n)
  97. {
  98. try
  99. {
  100. return m_in.readBuf(buf, n);
  101. }
  102. catch (System.NullReferenceException e)
  103. {
  104. if (m_in == null)
  105. throw UnsupportedErr.make(@typeof().qname() + " wraps null InStream").val;
  106. else
  107. throw e;
  108. }
  109. }
  110. public virtual InStream unread(long n)
  111. {
  112. try
  113. {
  114. m_in.unread(n);
  115. return this;
  116. }
  117. catch (System.NullReferenceException e)
  118. {
  119. if (m_in == null)
  120. throw UnsupportedErr.make(@typeof().qname() + " wraps null InStream").val;
  121. else
  122. throw e;
  123. }
  124. }
  125. public virtual long skip(long n)
  126. {
  127. if (m_in != null) return m_in.skip(n);
  128. long nval = n;
  129. for (int i=0; i<nval; ++i)
  130. if (r() < 0) return i;
  131. return n;
  132. }
  133. public virtual Buf readAllBuf()
  134. {
  135. try
  136. {
  137. long size = FanInt.Chunk.longValue();
  138. Buf buf = Buf.make(size);
  139. while (readBuf(buf, size) != null);
  140. buf.flip();
  141. return buf;
  142. }
  143. finally
  144. {
  145. try { close(); } catch (System.Exception e) { Err.dumpStack(e); }
  146. }
  147. }
  148. public virtual Buf readBufFully(Buf buf, long n)
  149. {
  150. if (buf == null) buf = Buf.make(n);
  151. long total = n;
  152. long got = 0;
  153. while (got < total)
  154. {
  155. Long r = readBuf(buf, total-got);
  156. if (r == null || r.longValue() == 0) throw IOErr.make("Unexpected end of stream").val;
  157. got += r.longValue();
  158. }
  159. buf.flip();
  160. return buf;
  161. }
  162. public virtual Endian endian()
  163. {
  164. return m_bigEndian ? Endian.m_big : Endian.m_little;
  165. }
  166. public void endian(Endian endian)
  167. {
  168. m_bigEndian = endian == Endian.m_big;
  169. }
  170. public virtual Long peek()
  171. {
  172. Long x = read();
  173. if (x != null) unread(x.longValue());
  174. return x;
  175. }
  176. public virtual long readU1()
  177. {
  178. int c = r();
  179. if (c < 0) throw IOErr.make("Unexpected end of stream").val;
  180. return c;
  181. }
  182. public virtual long readS1()
  183. {
  184. int c = r();
  185. if (c < 0) throw IOErr.make("Unexpected end of stream").val;
  186. return (sbyte)c;
  187. }
  188. public virtual long readU2()
  189. {
  190. int c1 = r();
  191. int c2 = r();
  192. if ((c1 | c2) < 0) throw IOErr.make("Unexpected end of stream").val;
  193. if (m_bigEndian)
  194. return c1 << 8 | c2;
  195. else
  196. return c2 << 8 | c1;
  197. }
  198. public virtual long readS2()
  199. {
  200. int c1 = r();
  201. int c2 = r();
  202. if ((c1 | c2) < 0) throw IOErr.make("Unexpected end of stream").val;
  203. if (m_bigEndian)
  204. return (short)(c1 << 8 | c2);
  205. else
  206. return (short)(c2 << 8 | c1);
  207. }
  208. public virtual long readU4()
  209. {
  210. long c1 = r();
  211. long c2 = r();
  212. long c3 = r();
  213. long c4 = r();
  214. if ((c1 | c2 | c3 | c4) < 0) throw IOErr.make("Unexpected end of stream").val;
  215. if (m_bigEndian)
  216. return (c1 << 24) + (c2 << 16) + (c3 << 8) + c4;
  217. else
  218. return (c4 << 24) + (c3 << 16) + (c2 << 8) + c1;
  219. }
  220. public virtual long readS4()
  221. {
  222. int c1 = r();
  223. int c2 = r();
  224. int c3 = r();
  225. int c4 = r();
  226. if ((c1 | c2 | c3 | c4) < 0) throw IOErr.make("Unexpected end of stream").val;
  227. if (m_bigEndian)
  228. return ((c1 << 24) + (c2 << 16) + (c3 << 8) + c4);
  229. else
  230. return ((c4 << 24) + (c3 << 16) + (c2 << 8) + c1);
  231. }
  232. public virtual long readS8()
  233. {
  234. long c1 = r();
  235. long c2 = r();
  236. long c3 = r();
  237. long c4 = r();
  238. long c5 = r();
  239. long c6 = r();
  240. long c7 = r();
  241. long c8 = r();
  242. if ((c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8) < 0) throw IOErr.make("Unexpected end of stream").val;
  243. if (m_bigEndian)
  244. return ((c1 << 56) + (c2 << 48) + (c3 << 40) + (c4 << 32) +
  245. (c5 << 24) + (c6 << 16) + (c7 << 8) + c8);
  246. else
  247. return ((c8 << 56) + (c7 << 48) + (c6 << 40) + (c5 << 32) +
  248. (c4 << 24) + (c3 << 16) + (c2 << 8) + c1);
  249. }
  250. public virtual double readF4()
  251. {
  252. return System.BitConverter.ToSingle(System.BitConverter.GetBytes(readS4()), 0);
  253. }
  254. public virtual double readF8()
  255. {
  256. return System.BitConverter.Int64BitsToDouble(readS8());
  257. }
  258. public virtual BigDecimal readDecimal()
  259. {
  260. return FanDecimal.fromStr(readUtfString(), true);
  261. }
  262. public virtual bool readBool()
  263. {
  264. int n = r();
  265. if (n < 0) throw IOErr.make("Unexpected end of stream").val;
  266. return n == 0 ? false : true;
  267. }
  268. public virtual string readUtf() { return readUtfString(); }
  269. private string readUtfString()
  270. {
  271. // read two-byte Length
  272. int len1 = r();
  273. int len2 = r();
  274. if ((len1 | len2) < 0) throw IOErr.make("Unexpected end of stream").val;
  275. int utflen = len1 << 8 | len2;
  276. char[] buf = new char[utflen]; // char buffer we read into
  277. int bnum = 0, cnum = 0; // byte count, char count
  278. // read the chars
  279. int c, c2, c3;
  280. while (bnum < utflen)
  281. {
  282. c = r(); bnum++;
  283. if (c < 0) throw IOErr.make("Unexpected end of stream").val;
  284. switch (c >> 4) {
  285. case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
  286. /* 0xxxxxxx*/
  287. buf[cnum++]=(char)c;
  288. break;
  289. case 12: case 13:
  290. /* 110x xxxx 10xx xxxx*/
  291. if (bnum >= utflen) throw IOErr.make("UTF encoding error").val;
  292. c2 = r(); bnum++;
  293. if (c2 < 0) throw IOErr.make("Unexpected end of stream").val;
  294. if ((c2 & 0xC0) != 0x80) throw IOErr.make("UTF encoding error").val;
  295. buf[cnum++]=(char)(((c & 0x1F) << 6) | (c2 & 0x3F));
  296. break;
  297. case 14:
  298. /* 1110 xxxx 10xx xxxx 10xx xxxx */
  299. if (bnum+1 >= utflen) throw IOErr.make("UTF encoding error").val;
  300. c2 = r(); bnum++;
  301. c3 = r(); bnum++;
  302. if ((c2|c3) < 0) throw IOErr.make("Unexpected end of stream").val;
  303. if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) throw IOErr.make("UTF encoding error").val;
  304. buf[cnum++]=(char)(((c & 0x0F) << 12) | ((c2 & 0x3F) << 6) | ((c3 & 0x3F) << 0));
  305. break;
  306. default:
  307. /* 10xx xxxx, 1111 xxxx */
  308. throw IOErr.make("UTF encoding error").val;
  309. }
  310. }
  311. // allocate as string
  312. return new string(buf, 0, cnum);
  313. }
  314. public virtual Charset charset()
  315. {
  316. return m_charset;
  317. }
  318. public virtual void charset(Charset charset)
  319. {
  320. m_charsetDecoder = charset.newDecoder();
  321. m_charsetEncoder = charset.newEncoder();
  322. m_charset = charset;
  323. }
  324. public virtual Long readChar()
  325. {
  326. int ch = m_charsetDecoder.decode(this);
  327. return ch < 0 ? null : Long.valueOf(ch);
  328. }
  329. public virtual InStream unreadChar(long c)
  330. {
  331. m_charsetEncoder.encode((char)c, this);
  332. return this;
  333. }
  334. public virtual Long peekChar()
  335. {
  336. Long x = readChar();
  337. if (x != null) unreadChar(x.longValue());
  338. return x;
  339. }
  340. public virtual string readChars(long n)
  341. {
  342. if (n < 0) throw ArgErr.make("readChars n < 0: " + n).val;
  343. if (n == 0) return "";
  344. StringBuilder buf = new StringBuilder(256);
  345. for (int i=(int)n; i>0; --i)
  346. {
  347. int ch = rChar();
  348. if (ch < 0) throw IOErr.make("Unexpected end of stream").val;
  349. buf.Append((char)ch);
  350. }
  351. return buf.ToString();
  352. }
  353. public virtual string readLine() { return readLine(FanInt.Chunk); }
  354. public virtual string readLine(Long max)
  355. {
  356. // max limit
  357. int maxChars = System.Int32.MaxValue;
  358. if (max != null)
  359. {
  360. long maxLong = max.longValue();
  361. if (maxLong == 0L) return "";
  362. if (maxLong < 0) throw ArgErr.make("Invalid max: " + max).val;
  363. if (maxLong < System.Int32.MaxValue)
  364. maxChars = (int)maxLong;
  365. }
  366. // read first char, if at end of file bail
  367. int c = rChar();
  368. if (c < 0) return null;
  369. // loop reading chars until we hit newline
  370. // combo or end of stream
  371. StringBuilder buf = new StringBuilder(256);
  372. while (true)
  373. {
  374. // check for \n, \r\n, or \r
  375. if (c == '\n') break;
  376. if (c == '\r')
  377. {
  378. c = rChar();
  379. if (c >= 0 && c != '\n') unreadChar(c);
  380. break;
  381. }
  382. // Append to working buffer
  383. buf.Append((char)c);
  384. if (buf.Length >= maxChars) break;
  385. // read next char
  386. c = rChar();
  387. if (c < 0) break;
  388. }
  389. return buf.ToString();
  390. }
  391. public virtual string readStrToken() { return readStrToken(FanInt.Chunk, null); }
  392. public virtual string readStrToken(Long max) { return readStrToken(max, null); }
  393. public virtual string readStrToken(Long max, Func f)
  394. {
  395. // max limit
  396. int maxChars = (max != null) ? max.intValue() : System.Int32.MaxValue;
  397. if (maxChars <= 0) return string.Empty;
  398. // read first char, if at end of file bail
  399. int c = rChar();
  400. if (c < 0) return null;
  401. // loop reading chars until our closure returns false
  402. StringBuilder buf = new StringBuilder();
  403. while (true)
  404. {
  405. // check for \n, \r\n, or \r
  406. bool terminate;
  407. if (f == null)
  408. terminate = FanInt.isSpace(c);
  409. else
  410. terminate = ((Boolean)f.call(c)).booleanValue();
  411. if (terminate)
  412. {
  413. unreadChar(c);
  414. break;
  415. }
  416. // Append to working buffer
  417. buf.Append((char)c);
  418. if (buf.Length >= maxChars) break;
  419. // read next char
  420. c = rChar();
  421. if (c < 0) break;
  422. }
  423. return buf.ToString();
  424. }
  425. public virtual List readAllLines()
  426. {
  427. try
  428. {
  429. List list = new List(Sys.StrType);
  430. string line;
  431. while ((line = readLine()) != null)
  432. list.add(line);
  433. return list;
  434. }
  435. finally
  436. {
  437. try { close(); } catch (System.Exception e) { Err.dumpStack(e); }
  438. }
  439. }
  440. public virtual void eachLine(Func f)
  441. {
  442. try
  443. {
  444. string line;
  445. while ((line = readLine()) != null)
  446. f.call(line);
  447. }
  448. finally
  449. {
  450. try { close(); } catch (System.Exception e) { Err.dumpStack(e); }
  451. }
  452. }
  453. public virtual string readAllStr() { return readAllStr(true); }
  454. public virtual string readAllStr(bool normalizeNewlines)
  455. {
  456. try
  457. {
  458. char[] buf = new char[4096];
  459. int n = 0;
  460. bool normalize = normalizeNewlines;
  461. // read characters
  462. int last = -1;
  463. while (true)
  464. {
  465. int c = rChar();
  466. if (c < 0) break;
  467. // grow buffer if needed
  468. if (n >= buf.Length)
  469. {
  470. char[] temp = new char[buf.Length*2];
  471. System.Array.Copy(buf, 0, temp, 0, n);
  472. buf = temp;
  473. }
  474. // normalize newlines and add to buffer
  475. if (normalize)
  476. {
  477. if (c == '\r') buf[n++] = '\n';
  478. else if (last == '\r' && c == '\n') {}
  479. else buf[n++] = (char)c;
  480. last = c;
  481. }
  482. else
  483. {
  484. buf[n++] = (char)c;
  485. }
  486. }
  487. return new string(buf, 0, n);
  488. }
  489. finally
  490. {
  491. try { close(); } catch (System.Exception e) { Err.dumpStack(e); }
  492. }
  493. }
  494. public virtual object readObj() { return readObj(null); }
  495. public virtual object readObj(Map options)
  496. {
  497. return new ObjDecoder(this, options).readObj();
  498. }
  499. public virtual Map readProps() { return readProps(false); }
  500. public Map readPropsListVals() { return readProps(true); }
  501. private Map readProps(bool listVals) // listVals is Str:Str[]
  502. {
  503. Charset origCharset = charset();
  504. charset(Charset.utf8());
  505. try
  506. {
  507. Map props = new Map(Sys.StrType, listVals ? Sys.StrType.toListOf() : Sys.StrType);
  508. StringBuilder name = new StringBuilder();
  509. StringBuilder val = null;
  510. int inBlockComment = 0;
  511. bool inEndOfLineComment = false;
  512. int c = ' ', last = ' ';
  513. int lineNum = 1;
  514. while (true)
  515. {
  516. last = c;
  517. c = rChar();
  518. if (c < 0) break;
  519. // end of line
  520. if (c == '\n' || c == '\r')
  521. {
  522. inEndOfLineComment = false;
  523. if (last == '\r' && c == '\n') continue;
  524. string n = FanStr.makeTrim(name);
  525. if (val != null)
  526. {
  527. addProp(props, n, FanStr.makeTrim(val), listVals);
  528. name = new StringBuilder();
  529. val = null;
  530. }
  531. else if (n.Length > 0)
  532. throw IOErr.make("Invalid name/value pair [Line " + lineNum + "]").val;
  533. lineNum++;
  534. continue;
  535. }
  536. // if in comment
  537. if (inEndOfLineComment) continue;
  538. // block comment
  539. if (inBlockComment > 0)
  540. {
  541. if (last == '/' && c == '*') inBlockComment++;
  542. if (last == '*' && c == '/') inBlockComment--;
  543. continue;
  544. }
  545. // equal
  546. if (c == '=' && val == null)
  547. {
  548. val = new StringBuilder();
  549. continue;
  550. }
  551. // comment
  552. if (c == '/' && FanInt.isSpace(last))
  553. {
  554. int peek = rChar();
  555. if (peek < 0) break;
  556. if (peek == '/') { inEndOfLineComment = true; continue; }
  557. if (peek == '*') { inBlockComment++; continue; }
  558. unreadChar(peek);
  559. }
  560. // escape or line continuation
  561. if (c == '\\')
  562. {
  563. int peek = rChar();
  564. if (peek < 0) break;
  565. else if (peek == 'n') c = '\n';
  566. else if (peek == 'r') c = '\r';
  567. else if (peek == 't') c = '\t';
  568. else if (peek == '\\') c = '\\';
  569. else if (peek == '\r' || peek == '\n')
  570. {
  571. // line continuation
  572. lineNum++;
  573. if (peek == '\r')
  574. {
  575. peek = rChar();
  576. if (peek != '\n') unreadChar(peek);
  577. }
  578. while (true)
  579. {
  580. peek = rChar();
  581. if (peek == ' ' || peek == '\t') continue;
  582. unreadChar(peek);
  583. break;
  584. }
  585. continue;
  586. }
  587. else if (peek == 'u')
  588. {
  589. int n3 = hex(rChar());
  590. int n2 = hex(rChar());
  591. int n1 = hex(rChar());
  592. int n0 = hex(rChar());
  593. if (n3 < 0 || n2 < 0 || n1 < 0 || n0 < 0) throw IOErr.make("Invalid hex value for \\uxxxx [Line " + lineNum + "]").val;
  594. c = ((n3 << 12) | (n2 << 8) | (n1 << 4) | n0);
  595. }
  596. else throw IOErr.make("Invalid escape sequence [Line " + lineNum + "]").val;
  597. }
  598. // normal character
  599. if (val == null)
  600. name.Append((char)c);
  601. else
  602. val.Append((char)c);
  603. }
  604. string nm = FanStr.makeTrim(name);
  605. if (val != null)
  606. addProp(props, nm, FanStr.makeTrim(val), listVals);
  607. else if (nm.Length > 0)
  608. throw IOErr.make("Invalid name/value pair [Line " + lineNum + "]").val;
  609. return props;
  610. }
  611. finally
  612. {
  613. try { close(); } catch (System.Exception e) { Err.dumpStack(e); }
  614. charset(origCharset);
  615. }
  616. }
  617. static void addProp(Map props, string n, string v, bool listVals)
  618. {
  619. if (listVals)
  620. {
  621. List list =(List)props.get(n);
  622. if (list == null) props.add(n, list = new List(Sys.StrType));
  623. list.add(v);
  624. }
  625. else
  626. {
  627. props.add(n, v);
  628. }
  629. }
  630. static int hex(int c)
  631. {
  632. if ('0' <= c && c <= '9') return c - '0';
  633. if ('a' <= c && c <= 'f') return c - 'a' + 10;
  634. if ('A' <= c && c <= 'F') return c - 'A' + 10;
  635. return -1;
  636. }
  637. public virtual long pipe(OutStream output) { return pipe(output, null, true); }
  638. public virtual long pipe(OutStream output, Long n) { return pipe(output, n, true); }
  639. public virtual long pipe(OutStream output, Long toPipe, bool cls)
  640. {
  641. try
  642. {
  643. long bufSize = FanInt.Chunk.longValue();
  644. Buf buf = Buf.make(bufSize);
  645. long total = 0;
  646. if (toPipe == null)
  647. {
  648. while (true)
  649. {
  650. Long n = readBuf(buf.clear(), bufSize);
  651. if (n == null) break;
  652. output.writeBuf(buf.flip(), buf.remaining());
  653. total += n.longValue();
  654. }
  655. }
  656. else
  657. {
  658. long toPipeVal = toPipe.longValue();
  659. while (total < toPipeVal)
  660. {
  661. if (toPipeVal - total < bufSize) bufSize = toPipeVal - total;
  662. Long n = readBuf(buf.clear(), bufSize);
  663. if (n == null) throw IOErr.make("Unexpected end of stream").val;
  664. output.writeBuf(buf.flip(), buf.remaining());
  665. total += n.longValue();
  666. }
  667. }
  668. return total;
  669. }
  670. finally
  671. {
  672. if (cls) close();
  673. }
  674. }
  675. public virtual bool close()
  676. {
  677. if (m_in != null) return m_in.close();
  678. return true;
  679. }
  680. //////////////////////////////////////////////////////////////////////////
  681. // Fields
  682. //////////////////////////////////////////////////////////////////////////
  683. internal InStream m_in;
  684. internal bool m_bigEndian = true;
  685. internal Charset m_charset;
  686. internal Charset.Decoder m_charsetDecoder;
  687. internal Charset.Encoder m_charsetEncoder;
  688. }
  689. }