PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/src/sys/java/fan/sys/InStream.java

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