PageRenderTime 70ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/phobos/std/stream.d

#
D | 2952 lines | 2101 code | 265 blank | 586 comment | 569 complexity | 3f032893269d92d289d7864cd32a2157 MD5 | raw file
Possible License(s): AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. // Written in the D programming language
  2. /**
  3. * Macros:
  4. * WIKI = Phobos/StdStream
  5. */
  6. /*
  7. * Copyright (c) 2001-2005
  8. * Pavel "EvilOne" Minayev
  9. * with buffering and endian support added by Ben Hinkle
  10. * with buffered readLine performance improvements by Dave Fladebo
  11. * with opApply inspired by (and mostly copied from) Regan Heath
  12. * with bug fixes and MemoryStream/SliceStream enhancements by Derick Eddington
  13. *
  14. * Permission to use, copy, modify, distribute and sell this software
  15. * and its documentation for any purpose is hereby granted without fee,
  16. * provided that the above copyright notice appear in all copies and
  17. * that both that copyright notice and this permission notice appear
  18. * in supporting documentation. Author makes no representations about
  19. * the suitability of this software for any purpose. It is provided
  20. * "as is" without express or implied warranty.
  21. */
  22. module std.stream;
  23. import std.conv;
  24. /* Class structure:
  25. * InputStream interface for reading
  26. * OutputStream interface for writing
  27. * Stream abstract base of stream implementations
  28. * File an OS file stream
  29. * FilterStream a base-class for wrappers around another stream
  30. * BufferedStream a buffered stream wrapping another stream
  31. * BufferedFile a buffered File
  32. * EndianStream a wrapper stream for swapping byte order and BOMs
  33. * SliceStream a portion of another stream
  34. * MemoryStream a stream entirely stored in main memory
  35. * TArrayStream a stream wrapping an array-like buffer
  36. */
  37. /// A base class for stream exceptions.
  38. class StreamException: Exception {
  39. /// Construct a StreamException with given error message.
  40. this(string msg) { super(msg); }
  41. }
  42. /// Thrown when unable to read data from Stream.
  43. class ReadException: StreamException {
  44. /// Construct a ReadException with given error message.
  45. this(string msg) { super(msg); }
  46. }
  47. /// Thrown when unable to write data to Stream.
  48. class WriteException: StreamException {
  49. /// Construct a WriteException with given error message.
  50. this(string msg) { super(msg); }
  51. }
  52. /// Thrown when unable to move Stream pointer.
  53. class SeekException: StreamException {
  54. /// Construct a SeekException with given error message.
  55. this(string msg) { super(msg); }
  56. }
  57. // seek whence...
  58. enum SeekPos {
  59. Set,
  60. Current,
  61. End
  62. }
  63. private {
  64. import std.format;
  65. import std.system; // for Endian enumeration
  66. import std.intrinsic; // for bswap
  67. import std.utf;
  68. import std.stdarg;
  69. }
  70. version (Windows) {
  71. private import std.file;
  72. }
  73. /// InputStream is the interface for readable streams.
  74. interface InputStream {
  75. /***
  76. * Read exactly size bytes into the buffer.
  77. *
  78. * Throws a ReadException if it is not correct.
  79. */
  80. void readExact(void* buffer, size_t size);
  81. /***
  82. * Read a block of data big enough to fill the given array buffer.
  83. *
  84. * Returns: the actual number of bytes read. Unfilled bytes are not modified.
  85. */
  86. size_t read(ubyte[] buffer);
  87. /***
  88. * Read a basic type or counted string.
  89. *
  90. * Throw a ReadException if it could not be read.
  91. * Outside of byte, ubyte, and char, the format is
  92. * implementation-specific and should not be used except as opposite actions
  93. * to write.
  94. */
  95. void read(out byte x);
  96. void read(out ubyte x); /// ditto
  97. void read(out short x); /// ditto
  98. void read(out ushort x); /// ditto
  99. void read(out int x); /// ditto
  100. void read(out uint x); /// ditto
  101. void read(out long x); /// ditto
  102. void read(out ulong x); /// ditto
  103. void read(out float x); /// ditto
  104. void read(out double x); /// ditto
  105. void read(out real x); /// ditto
  106. void read(out ifloat x); /// ditto
  107. void read(out idouble x); /// ditto
  108. void read(out ireal x); /// ditto
  109. void read(out cfloat x); /// ditto
  110. void read(out cdouble x); /// ditto
  111. void read(out creal x); /// ditto
  112. void read(out char x); /// ditto
  113. void read(out wchar x); /// ditto
  114. void read(out dchar x); /// ditto
  115. // reads a string, written earlier by write()
  116. void read(out char[] s); /// ditto
  117. // reads a Unicode string, written earlier by write()
  118. void read(out wchar[] s); /// ditto
  119. /***
  120. * Read a line that is terminated with some combination of carriage return and
  121. * line feed or end-of-file.
  122. *
  123. * The terminators are not included. The wchar version
  124. * is identical. The optional buffer parameter is filled (reallocating
  125. * it if necessary) and a slice of the result is returned.
  126. */
  127. char[] readLine();
  128. char[] readLine(char[] result); /// ditto
  129. wchar[] readLineW(); /// ditto
  130. wchar[] readLineW(wchar[] result); /// ditto
  131. /***
  132. * Overload foreach statements to read the stream line by line and call the
  133. * supplied delegate with each line or with each line with line number.
  134. *
  135. * The string passed in line may be reused between calls to the delegate.
  136. * Line numbering starts at 1.
  137. * Breaking out of the foreach will leave the stream
  138. * position at the beginning of the next line to be read.
  139. * For example, to echo a file line-by-line with line numbers run:
  140. * ------------------------------------
  141. * Stream file = new BufferedFile("sample.txt");
  142. * foreach(ulong n, string line; file) {
  143. * stdout.writefln("line %d: %s",n,line);
  144. * }
  145. * file.close();
  146. * ------------------------------------
  147. */
  148. // iterate through the stream line-by-line
  149. int opApply(int delegate(inout char[] line) dg);
  150. int opApply(int delegate(inout ulong n, inout char[] line) dg); /// ditto
  151. int opApply(int delegate(inout wchar[] line) dg); /// ditto
  152. int opApply(int delegate(inout ulong n, inout wchar[] line) dg); /// ditto
  153. /// Read a string of the given length,
  154. /// throwing ReadException if there was a problem.
  155. char[] readString(size_t length);
  156. /***
  157. * Read a string of the given length, throwing ReadException if there was a
  158. * problem.
  159. *
  160. * The file format is implementation-specific and should not be used
  161. * except as opposite actions to <b>write</b>.
  162. */
  163. wchar[] readStringW(size_t length);
  164. /***
  165. * Read and return the next character in the stream.
  166. *
  167. * This is the only method that will handle ungetc properly.
  168. * getcw's format is implementation-specific.
  169. * If EOF is reached then getc returns char.init and getcw returns wchar.init.
  170. */
  171. char getc();
  172. wchar getcw(); /// ditto
  173. /***
  174. * Push a character back onto the stream.
  175. *
  176. * They will be returned in first-in last-out order from getc/getcw.
  177. * Only has effect on further calls to getc() and getcw().
  178. */
  179. char ungetc(char c);
  180. wchar ungetcw(wchar c); /// ditto
  181. /***
  182. * Scan a string from the input using a similar form to C's scanf
  183. * and <a href="std_format.html">std.format</a>.
  184. *
  185. * An argument of type string is interpreted as a format string.
  186. * All other arguments must be pointer types.
  187. * If a format string is not present a default will be supplied computed from
  188. * the base type of the pointer type. An argument of type string* is filled
  189. * (possibly with appending characters) and a slice of the result is assigned
  190. * back into the argument. For example the following readf statements
  191. * are equivalent:
  192. * --------------------------
  193. * int x;
  194. * double y;
  195. * string s;
  196. * file.readf(&x, " hello ", &y, &s);
  197. * file.readf("%d hello %f %s", &x, &y, &s);
  198. * file.readf("%d hello %f", &x, &y, "%s", &s);
  199. * --------------------------
  200. */
  201. int vreadf(TypeInfo[] arguments, void* args);
  202. int readf(...); /// ditto
  203. /// Retrieve the number of bytes available for immediate reading.
  204. size_t available();
  205. /***
  206. * Return whether the current file position is the same as the end of the
  207. * file.
  208. *
  209. * This does not require actually reading past the end, as with stdio. For
  210. * non-seekable streams this might only return true after attempting to read
  211. * past the end.
  212. */
  213. bool eof();
  214. bool isOpen(); /// Return true if the stream is currently open.
  215. }
  216. /// Interface for writable streams.
  217. interface OutputStream {
  218. /***
  219. * Write exactly size bytes from buffer, or throw a WriteException if that
  220. * could not be done.
  221. */
  222. void writeExact(const void* buffer, size_t size);
  223. /***
  224. * Write as much of the buffer as possible,
  225. * returning the number of bytes written.
  226. */
  227. size_t write(const(ubyte)[] buffer);
  228. /***
  229. * Write a basic type.
  230. *
  231. * Outside of byte, ubyte, and char, the format is implementation-specific
  232. * and should only be used in conjunction with read.
  233. * Throw WriteException on error.
  234. */
  235. void write(byte x);
  236. void write(ubyte x); /// ditto
  237. void write(short x); /// ditto
  238. void write(ushort x); /// ditto
  239. void write(int x); /// ditto
  240. void write(uint x); /// ditto
  241. void write(long x); /// ditto
  242. void write(ulong x); /// ditto
  243. void write(float x); /// ditto
  244. void write(double x); /// ditto
  245. void write(real x); /// ditto
  246. void write(ifloat x); /// ditto
  247. void write(idouble x); /// ditto
  248. void write(ireal x); /// ditto
  249. void write(cfloat x); /// ditto
  250. void write(cdouble x); /// ditto
  251. void write(creal x); /// ditto
  252. void write(char x); /// ditto
  253. void write(wchar x); /// ditto
  254. void write(dchar x); /// ditto
  255. /***
  256. * Writes a string, together with its length.
  257. *
  258. * The format is implementation-specific
  259. * and should only be used in conjunction with read.
  260. * Throw WriteException on error.
  261. */
  262. void write(char[] s);
  263. void write(const(wchar)[] s); /// ditto
  264. /***
  265. * Write a line of text,
  266. * appending the line with an operating-system-specific line ending.
  267. *
  268. * Throws WriteException on error.
  269. */
  270. void writeLine(const(char)[] s);
  271. /***
  272. * Write a line of text,
  273. * appending the line with an operating-system-specific line ending.
  274. *
  275. * The format is implementation-specific.
  276. * Throws WriteException on error.
  277. */
  278. void writeLineW(const(wchar)[] s);
  279. /***
  280. * Write a string of text.
  281. *
  282. * Throws WriteException if it could not be fully written.
  283. */
  284. void writeString(const(char)[] s);
  285. /***
  286. * Write a string of text.
  287. *
  288. * The format is implementation-specific.
  289. * Throws WriteException if it could not be fully written.
  290. */
  291. void writeStringW(const(wchar)[] s);
  292. /***
  293. * Print a formatted string into the stream using printf-style syntax,
  294. * returning the number of bytes written.
  295. */
  296. size_t vprintf(char[] format, va_list args);
  297. size_t printf(char[] format, ...); /// ditto
  298. /***
  299. * Print a formatted string into the stream using writef-style syntax.
  300. * References: <a href="std_format.html">std.format</a>.
  301. * Returns: self to chain with other stream commands like flush.
  302. */
  303. OutputStream writef(...);
  304. OutputStream writefln(...); /// ditto
  305. OutputStream writefx(TypeInfo[] arguments, void* argptr, int newline = false); /// ditto
  306. void flush(); /// Flush pending output if appropriate.
  307. void close(); /// Close the stream, flushing output if appropriate.
  308. bool isOpen(); /// Return true if the stream is currently open.
  309. }
  310. /***
  311. * Stream is the base abstract class from which the other stream classes derive.
  312. *
  313. * Stream's byte order is the format native to the computer.
  314. *
  315. * Reading:
  316. * These methods require that the readable flag be set.
  317. * Problems with reading result in a ReadException being thrown.
  318. * Stream implements the InputStream interface in addition to the
  319. * readBlock method.
  320. *
  321. * Writing:
  322. * These methods require that the writeable flag be set. Problems with writing
  323. * result in a WriteException being thrown. Stream implements the OutputStream
  324. * interface in addition to the following methods:
  325. * writeBlock
  326. * copyFrom
  327. * copyFrom
  328. *
  329. * Seeking:
  330. * These methods require that the seekable flag be set.
  331. * Problems with seeking result in a SeekException being thrown.
  332. * seek, seekSet, seekCur, seekEnd, position, size, toString, toHash
  333. */
  334. // not really abstract, but its instances will do nothing useful
  335. class Stream : InputStream, OutputStream {
  336. private import std.string, crc32, std.c.stdlib, std.c.stdio;
  337. // stream abilities
  338. bool readable = false; /// Indicates whether this stream can be read from.
  339. bool writeable = false; /// Indicates whether this stream can be written to.
  340. bool seekable = false; /// Indicates whether this stream can be seeked within.
  341. protected bool isopen = true; /// Indicates whether this stream is open.
  342. protected bool readEOF = false; /** Indicates whether this stream is at eof
  343. * after the last read attempt.
  344. */
  345. protected bool prevCr = false; /** For a non-seekable stream indicates that
  346. * the last readLine or readLineW ended on a
  347. * '\r' character.
  348. */
  349. this() {}
  350. /***
  351. * Read up to size bytes into the buffer and return the number of bytes
  352. * actually read. A return value of 0 indicates end-of-file.
  353. */
  354. abstract size_t readBlock(void* buffer, size_t size);
  355. // reads block of data of specified size,
  356. // throws ReadException on error
  357. void readExact(void* buffer, size_t size) {
  358. for(;;) {
  359. if (!size) return;
  360. size_t readsize = readBlock(buffer, size); // return 0 on eof
  361. if (readsize == 0) break;
  362. buffer += readsize;
  363. size -= readsize;
  364. }
  365. if (size != 0)
  366. throw new ReadException("not enough data in stream");
  367. }
  368. // reads block of data big enough to fill the given
  369. // array, returns actual number of bytes read
  370. size_t read(ubyte[] buffer) {
  371. return readBlock(buffer.ptr, buffer.length);
  372. }
  373. // read a single value of desired type,
  374. // throw ReadException on error
  375. void read(out byte x) { readExact(&x, x.sizeof); }
  376. void read(out ubyte x) { readExact(&x, x.sizeof); }
  377. void read(out short x) { readExact(&x, x.sizeof); }
  378. void read(out ushort x) { readExact(&x, x.sizeof); }
  379. void read(out int x) { readExact(&x, x.sizeof); }
  380. void read(out uint x) { readExact(&x, x.sizeof); }
  381. void read(out long x) { readExact(&x, x.sizeof); }
  382. void read(out ulong x) { readExact(&x, x.sizeof); }
  383. void read(out float x) { readExact(&x, x.sizeof); }
  384. void read(out double x) { readExact(&x, x.sizeof); }
  385. void read(out real x) { readExact(&x, x.sizeof); }
  386. void read(out ifloat x) { readExact(&x, x.sizeof); }
  387. void read(out idouble x) { readExact(&x, x.sizeof); }
  388. void read(out ireal x) { readExact(&x, x.sizeof); }
  389. void read(out cfloat x) { readExact(&x, x.sizeof); }
  390. void read(out cdouble x) { readExact(&x, x.sizeof); }
  391. void read(out creal x) { readExact(&x, x.sizeof); }
  392. void read(out char x) { readExact(&x, x.sizeof); }
  393. void read(out wchar x) { readExact(&x, x.sizeof); }
  394. void read(out dchar x) { readExact(&x, x.sizeof); }
  395. // reads a string, written earlier by write()
  396. void read(out char[] s) {
  397. size_t len;
  398. read(len);
  399. s = readString(len);
  400. }
  401. // reads a Unicode string, written earlier by write()
  402. void read(out wchar[] s) {
  403. size_t len;
  404. read(len);
  405. s = readStringW(len);
  406. }
  407. // reads a line, terminated by either CR, LF, CR/LF, or EOF
  408. char[] readLine() {
  409. return readLine(null);
  410. }
  411. // reads a line, terminated by either CR, LF, CR/LF, or EOF
  412. // reusing the memory in buffer if result will fit and otherwise
  413. // allocates a new string
  414. char[] readLine(char[] result) {
  415. size_t strlen = 0;
  416. char ch = getc();
  417. while (readable) {
  418. switch (ch) {
  419. case '\r':
  420. if (seekable) {
  421. ch = getc();
  422. if (ch != '\n')
  423. ungetc(ch);
  424. } else {
  425. prevCr = true;
  426. }
  427. case '\n':
  428. case char.init:
  429. result.length = strlen;
  430. return result;
  431. default:
  432. if (strlen < result.length) {
  433. result[strlen] = ch;
  434. } else {
  435. result ~= ch;
  436. }
  437. strlen++;
  438. }
  439. ch = getc();
  440. }
  441. result.length = strlen;
  442. return result;
  443. }
  444. // reads a Unicode line, terminated by either CR, LF, CR/LF,
  445. // or EOF; pretty much the same as the above, working with
  446. // wchars rather than chars
  447. wchar[] readLineW() {
  448. return readLineW(null);
  449. }
  450. // reads a Unicode line, terminated by either CR, LF, CR/LF,
  451. // or EOF;
  452. // fills supplied buffer if line fits and otherwise allocates a new string.
  453. wchar[] readLineW(wchar[] result) {
  454. size_t strlen = 0;
  455. wchar c = getcw();
  456. while (readable) {
  457. switch (c) {
  458. case '\r':
  459. if (seekable) {
  460. c = getcw();
  461. if (c != '\n')
  462. ungetcw(c);
  463. } else {
  464. prevCr = true;
  465. }
  466. case '\n':
  467. case wchar.init:
  468. result.length = strlen;
  469. return result;
  470. default:
  471. if (strlen < result.length) {
  472. result[strlen] = c;
  473. } else {
  474. result ~= c;
  475. }
  476. strlen++;
  477. }
  478. c = getcw();
  479. }
  480. result.length = strlen;
  481. return result;
  482. }
  483. // iterate through the stream line-by-line - due to Regan Heath
  484. int opApply(int delegate(inout char[] line) dg) {
  485. int res = 0;
  486. char[128] buf;
  487. while (!eof()) {
  488. char[] line = readLine(buf);
  489. res = dg(line);
  490. if (res) break;
  491. }
  492. return res;
  493. }
  494. // iterate through the stream line-by-line with line count and string
  495. int opApply(int delegate(inout ulong n, inout char[] line) dg) {
  496. int res = 0;
  497. ulong n = 1;
  498. char[128] buf;
  499. while (!eof()) {
  500. auto line = readLine(buf);
  501. res = dg(n,line);
  502. if (res) break;
  503. n++;
  504. }
  505. return res;
  506. }
  507. // iterate through the stream line-by-line with wchar[]
  508. int opApply(int delegate(inout wchar[] line) dg) {
  509. int res = 0;
  510. wchar[128] buf;
  511. while (!eof()) {
  512. auto line = readLineW(buf);
  513. res = dg(line);
  514. if (res) break;
  515. }
  516. return res;
  517. }
  518. // iterate through the stream line-by-line with line count and wchar[]
  519. int opApply(int delegate(inout ulong n, inout wchar[] line) dg) {
  520. int res = 0;
  521. ulong n = 1;
  522. wchar[128] buf;
  523. while (!eof()) {
  524. auto line = readLineW(buf);
  525. res = dg(n,line);
  526. if (res) break;
  527. n++;
  528. }
  529. return res;
  530. }
  531. // reads a string of given length, throws
  532. // ReadException on error
  533. char[] readString(size_t length) {
  534. char[] result = new char[length];
  535. readExact(result.ptr, length);
  536. return result;
  537. }
  538. // reads a Unicode string of given length, throws
  539. // ReadException on error
  540. wchar[] readStringW(size_t length) {
  541. auto result = new wchar[length];
  542. readExact(result.ptr, result.length * wchar.sizeof);
  543. return result;
  544. }
  545. // unget buffer
  546. private wchar[] unget;
  547. final bool ungetAvailable() { return unget.length > 1; }
  548. // reads and returns next character from the stream,
  549. // handles characters pushed back by ungetc()
  550. // returns char.init on eof.
  551. char getc() {
  552. char c;
  553. if (prevCr) {
  554. prevCr = false;
  555. c = getc();
  556. if (c != '\n')
  557. return c;
  558. }
  559. if (unget.length > 1) {
  560. c = cast(char)unget[unget.length - 1];
  561. unget.length = unget.length - 1;
  562. } else {
  563. readBlock(&c,1);
  564. }
  565. return c;
  566. }
  567. // reads and returns next Unicode character from the
  568. // stream, handles characters pushed back by ungetc()
  569. // returns wchar.init on eof.
  570. wchar getcw() {
  571. wchar c;
  572. if (prevCr) {
  573. prevCr = false;
  574. c = getcw();
  575. if (c != '\n')
  576. return c;
  577. }
  578. if (unget.length > 1) {
  579. c = unget[unget.length - 1];
  580. unget.length = unget.length - 1;
  581. } else {
  582. void* buf = &c;
  583. size_t n = readBlock(buf,2);
  584. if (n == 1 && readBlock(buf+1,1) == 0)
  585. throw new ReadException("not enough data in stream");
  586. }
  587. return c;
  588. }
  589. // pushes back character c into the stream; only has
  590. // effect on further calls to getc() and getcw()
  591. char ungetc(char c) {
  592. if (c == c.init) return c;
  593. // first byte is a dummy so that we never set length to 0
  594. if (unget.length == 0)
  595. unget.length = 1;
  596. unget ~= c;
  597. return c;
  598. }
  599. // pushes back Unicode character c into the stream; only
  600. // has effect on further calls to getc() and getcw()
  601. wchar ungetcw(wchar c) {
  602. if (c == c.init) return c;
  603. // first byte is a dummy so that we never set length to 0
  604. if (unget.length == 0)
  605. unget.length = 1;
  606. unget ~= c;
  607. return c;
  608. }
  609. int vreadf(TypeInfo[] arguments, void* args) {
  610. string fmt;
  611. int j = 0;
  612. int count = 0, i = 0;
  613. char c = getc();
  614. while ((j < arguments.length || i < fmt.length) && !eof()) {
  615. if (fmt.length == 0 || i == fmt.length) {
  616. i = 0;
  617. if (arguments[j] is typeid(char[])) {
  618. fmt = va_arg!(string)(args);
  619. j++;
  620. continue;
  621. } else if (arguments[j] is typeid(int*) ||
  622. arguments[j] is typeid(byte*) ||
  623. arguments[j] is typeid(short*) ||
  624. arguments[j] is typeid(long*)) {
  625. fmt = "%d";
  626. } else if (arguments[j] is typeid(uint*) ||
  627. arguments[j] is typeid(ubyte*) ||
  628. arguments[j] is typeid(ushort*) ||
  629. arguments[j] is typeid(ulong*)) {
  630. fmt = "%d";
  631. } else if (arguments[j] is typeid(float*) ||
  632. arguments[j] is typeid(double*) ||
  633. arguments[j] is typeid(real*)) {
  634. fmt = "%f";
  635. } else if (arguments[j] is typeid(char[]*) ||
  636. arguments[j] is typeid(wchar[]*) ||
  637. arguments[j] is typeid(dchar[]*)) {
  638. fmt = "%s";
  639. } else if (arguments[j] is typeid(char*)) {
  640. fmt = "%c";
  641. }
  642. }
  643. if (fmt[i] == '%') { // a field
  644. i++;
  645. bool suppress = false;
  646. if (fmt[i] == '*') { // suppress assignment
  647. suppress = true;
  648. i++;
  649. }
  650. // read field width
  651. int width = 0;
  652. while (isdigit(fmt[i])) {
  653. width = width * 10 + (fmt[i] - '0');
  654. i++;
  655. }
  656. if (width == 0)
  657. width = -1;
  658. // skip any modifier if present
  659. if (fmt[i] == 'h' || fmt[i] == 'l' || fmt[i] == 'L')
  660. i++;
  661. // check the typechar and act accordingly
  662. switch (fmt[i]) {
  663. case 'd': // decimal/hexadecimal/octal integer
  664. case 'D':
  665. case 'u':
  666. case 'U':
  667. case 'o':
  668. case 'O':
  669. case 'x':
  670. case 'X':
  671. case 'i':
  672. case 'I':
  673. {
  674. while (iswhite(c)) {
  675. c = getc();
  676. count++;
  677. }
  678. bool neg = false;
  679. if (c == '-') {
  680. neg = true;
  681. c = getc();
  682. count++;
  683. } else if (c == '+') {
  684. c = getc();
  685. count++;
  686. }
  687. char ifmt = cast(char)(fmt[i] | 0x20);
  688. if (ifmt == 'i') { // undetermined base
  689. if (c == '0') { // octal or hex
  690. c = getc();
  691. count++;
  692. if (c == 'x' || c == 'X') { // hex
  693. ifmt = 'x';
  694. c = getc();
  695. count++;
  696. } else { // octal
  697. ifmt = 'o';
  698. }
  699. }
  700. else // decimal
  701. ifmt = 'd';
  702. }
  703. long n = 0;
  704. switch (ifmt)
  705. {
  706. case 'd': // decimal
  707. case 'u': {
  708. while (isdigit(c) && width) {
  709. n = n * 10 + (c - '0');
  710. width--;
  711. c = getc();
  712. count++;
  713. }
  714. } break;
  715. case 'o': { // octal
  716. while (isoctdigit(c) && width) {
  717. n = n * 010 + (c - '0');
  718. width--;
  719. c = getc();
  720. count++;
  721. }
  722. } break;
  723. case 'x': { // hexadecimal
  724. while (ishexdigit(c) && width) {
  725. n *= 0x10;
  726. if (isdigit(c))
  727. n += c - '0';
  728. else
  729. n += 0xA + (c | 0x20) - 'a';
  730. width--;
  731. c = getc();
  732. count++;
  733. }
  734. } break;
  735. default:
  736. assert(0);
  737. }
  738. if (neg)
  739. n = -n;
  740. if (arguments[j] is typeid(int*)) {
  741. int* p = va_arg!(int*)(args);
  742. *p = cast(int)n;
  743. } else if (arguments[j] is typeid(short*)) {
  744. short* p = va_arg!(short*)(args);
  745. *p = cast(short)n;
  746. } else if (arguments[j] is typeid(byte*)) {
  747. byte* p = va_arg!(byte*)(args);
  748. *p = cast(byte)n;
  749. } else if (arguments[j] is typeid(long*)) {
  750. long* p = va_arg!(long*)(args);
  751. *p = n;
  752. } else if (arguments[j] is typeid(uint*)) {
  753. uint* p = va_arg!(uint*)(args);
  754. *p = cast(uint)n;
  755. } else if (arguments[j] is typeid(ushort*)) {
  756. ushort* p = va_arg!(ushort*)(args);
  757. *p = cast(ushort)n;
  758. } else if (arguments[j] is typeid(ubyte*)) {
  759. ubyte* p = va_arg!(ubyte*)(args);
  760. *p = cast(ubyte)n;
  761. } else if (arguments[j] is typeid(ulong*)) {
  762. ulong* p = va_arg!(ulong*)(args);
  763. *p = cast(ulong)n;
  764. }
  765. j++;
  766. i++;
  767. } break;
  768. case 'f': // float
  769. case 'F':
  770. case 'e':
  771. case 'E':
  772. case 'g':
  773. case 'G':
  774. {
  775. while (iswhite(c)) {
  776. c = getc();
  777. count++;
  778. }
  779. bool neg = false;
  780. if (c == '-') {
  781. neg = true;
  782. c = getc();
  783. count++;
  784. } else if (c == '+') {
  785. c = getc();
  786. count++;
  787. }
  788. real n = 0;
  789. while (isdigit(c) && width) {
  790. n = n * 10 + (c - '0');
  791. width--;
  792. c = getc();
  793. count++;
  794. }
  795. if (width && c == '.') {
  796. width--;
  797. c = getc();
  798. count++;
  799. double frac = 1;
  800. while (isdigit(c) && width) {
  801. n = n * 10 + (c - '0');
  802. frac *= 10;
  803. width--;
  804. c = getc();
  805. count++;
  806. }
  807. n /= frac;
  808. }
  809. if (width && (c == 'e' || c == 'E')) {
  810. width--;
  811. c = getc();
  812. count++;
  813. if (width) {
  814. bool expneg = false;
  815. if (c == '-') {
  816. expneg = true;
  817. width--;
  818. c = getc();
  819. count++;
  820. } else if (c == '+') {
  821. width--;
  822. c = getc();
  823. count++;
  824. }
  825. real exp = 0;
  826. while (isdigit(c) && width) {
  827. exp = exp * 10 + (c - '0');
  828. width--;
  829. c = getc();
  830. count++;
  831. }
  832. if (expneg) {
  833. while (exp--)
  834. n /= 10;
  835. } else {
  836. while (exp--)
  837. n *= 10;
  838. }
  839. }
  840. }
  841. if (neg)
  842. n = -n;
  843. if (arguments[j] is typeid(float*)) {
  844. float* p = va_arg!(float*)(args);
  845. *p = n;
  846. } else if (arguments[j] is typeid(double*)) {
  847. double* p = va_arg!(double*)(args);
  848. *p = n;
  849. } else if (arguments[j] is typeid(real*)) {
  850. real* p = va_arg!(real*)(args);
  851. *p = n;
  852. }
  853. j++;
  854. i++;
  855. } break;
  856. case 's': { // string
  857. while (iswhite(c)) {
  858. c = getc();
  859. count++;
  860. }
  861. char[] s;
  862. char[]* p;
  863. size_t strlen;
  864. if (arguments[j] is typeid(char[]*)) {
  865. p = va_arg!(char[]*)(args);
  866. s = *p;
  867. }
  868. while (!iswhite(c) && c != char.init) {
  869. if (strlen < s.length) {
  870. s[strlen] = c;
  871. } else {
  872. s ~= c;
  873. }
  874. strlen++;
  875. c = getc();
  876. count++;
  877. }
  878. s = s[0 .. strlen];
  879. if (arguments[j] is typeid(char[]*)) {
  880. *p = s;
  881. } else if (arguments[j] is typeid(char*)) {
  882. s ~= 0;
  883. auto q = va_arg!(char*)(args);
  884. q[0 .. s.length] = s[];
  885. } else if (arguments[j] is typeid(wchar[]*)) {
  886. auto q = va_arg!(const(wchar)[]*)(args);
  887. *q = toUTF16(s);
  888. } else if (arguments[j] is typeid(dchar[]*)) {
  889. auto q = va_arg!(const(dchar)[]*)(args);
  890. *q = toUTF32(s);
  891. }
  892. j++;
  893. i++;
  894. } break;
  895. case 'c': { // character(s)
  896. char* s = va_arg!(char*)(args);
  897. if (width < 0)
  898. width = 1;
  899. else
  900. while (iswhite(c)) {
  901. c = getc();
  902. count++;
  903. }
  904. while (width-- && !eof()) {
  905. *(s++) = c;
  906. c = getc();
  907. count++;
  908. }
  909. j++;
  910. i++;
  911. } break;
  912. case 'n': { // number of chars read so far
  913. int* p = va_arg!(int*)(args);
  914. *p = count;
  915. j++;
  916. i++;
  917. } break;
  918. default: // read character as is
  919. goto nws;
  920. }
  921. } else if (iswhite(fmt[i])) { // skip whitespace
  922. while (iswhite(c))
  923. c = getc();
  924. i++;
  925. } else { // read character as is
  926. nws:
  927. if (fmt[i] != c)
  928. break;
  929. c = getc();
  930. i++;
  931. }
  932. }
  933. ungetc(c);
  934. return count;
  935. }
  936. int readf(...) {
  937. return vreadf(_arguments, _argptr);
  938. }
  939. // returns estimated number of bytes available for immediate reading
  940. size_t available() { return 0; }
  941. /***
  942. * Write up to size bytes from buffer in the stream, returning the actual
  943. * number of bytes that were written.
  944. */
  945. abstract size_t writeBlock(const void* buffer, size_t size);
  946. // writes block of data of specified size,
  947. // throws WriteException on error
  948. void writeExact(const void* buffer, size_t size) {
  949. const(void)* p = buffer;
  950. for(;;) {
  951. if (!size) return;
  952. size_t writesize = writeBlock(p, size);
  953. if (writesize == 0) break;
  954. p += writesize;
  955. size -= writesize;
  956. }
  957. if (size != 0)
  958. throw new WriteException("unable to write to stream");
  959. }
  960. // writes the given array of bytes, returns
  961. // actual number of bytes written
  962. size_t write(const(ubyte)[] buffer) {
  963. return writeBlock(buffer.ptr, buffer.length);
  964. }
  965. // write a single value of desired type,
  966. // throw WriteException on error
  967. void write(byte x) { writeExact(&x, x.sizeof); }
  968. void write(ubyte x) { writeExact(&x, x.sizeof); }
  969. void write(short x) { writeExact(&x, x.sizeof); }
  970. void write(ushort x) { writeExact(&x, x.sizeof); }
  971. void write(int x) { writeExact(&x, x.sizeof); }
  972. void write(uint x) { writeExact(&x, x.sizeof); }
  973. void write(long x) { writeExact(&x, x.sizeof); }
  974. void write(ulong x) { writeExact(&x, x.sizeof); }
  975. void write(float x) { writeExact(&x, x.sizeof); }
  976. void write(double x) { writeExact(&x, x.sizeof); }
  977. void write(real x) { writeExact(&x, x.sizeof); }
  978. void write(ifloat x) { writeExact(&x, x.sizeof); }
  979. void write(idouble x) { writeExact(&x, x.sizeof); }
  980. void write(ireal x) { writeExact(&x, x.sizeof); }
  981. void write(cfloat x) { writeExact(&x, x.sizeof); }
  982. void write(cdouble x) { writeExact(&x, x.sizeof); }
  983. void write(creal x) { writeExact(&x, x.sizeof); }
  984. void write(char x) { writeExact(&x, x.sizeof); }
  985. void write(wchar x) { writeExact(&x, x.sizeof); }
  986. void write(dchar x) { writeExact(&x, x.sizeof); }
  987. // writes a string, together with its length
  988. void write(char[] s) {
  989. write(s.length);
  990. writeString(s);
  991. }
  992. // writes a Unicode string, together with its length
  993. void write(const(wchar)[] s) {
  994. write(s.length);
  995. writeStringW(s);
  996. }
  997. // writes a line, throws WriteException on error
  998. void writeLine(const(char)[] s) {
  999. writeString(s);
  1000. version (Win32)
  1001. writeString("\r\n");
  1002. else version (Mac)
  1003. writeString("\r");
  1004. else
  1005. writeString("\n");
  1006. }
  1007. // writes a Unicode line, throws WriteException on error
  1008. void writeLineW(const(wchar)[] s) {
  1009. writeStringW(s);
  1010. version (Win32)
  1011. writeStringW("\r\n");
  1012. else version (Mac)
  1013. writeStringW("\r");
  1014. else
  1015. writeStringW("\n");
  1016. }
  1017. // writes a string, throws WriteException on error
  1018. void writeString(const(char)[] s) {
  1019. writeExact(s.ptr, s.length);
  1020. }
  1021. // writes a Unicode string, throws WriteException on error
  1022. void writeStringW(const(wchar)[] s) {
  1023. writeExact(s.ptr, s.length * wchar.sizeof);
  1024. }
  1025. // writes data to stream using vprintf() syntax,
  1026. // returns number of bytes written
  1027. size_t vprintf(char[] format, va_list args) {
  1028. // shamelessly stolen from OutBuffer,
  1029. // by Walter's permission
  1030. char[1024] buffer;
  1031. char* p = buffer.ptr;
  1032. auto f = toStringz(format);
  1033. size_t psize = buffer.length;
  1034. size_t count;
  1035. while (true) {
  1036. version (Win32) {
  1037. count = _vsnprintf(p, psize, f, args);
  1038. if (count != -1)
  1039. break;
  1040. psize *= 2;
  1041. p = cast(char*) alloca(psize);
  1042. } else version (Posix) {
  1043. count = vsnprintf(p, psize, f, args);
  1044. if (count == -1)
  1045. psize *= 2;
  1046. else if (count >= psize)
  1047. psize = count + 1;
  1048. else
  1049. break;
  1050. p = cast(char*) alloca(psize);
  1051. } else
  1052. throw new Exception("unsupported platform");
  1053. }
  1054. writeString(p[0 .. count]);
  1055. return count;
  1056. }
  1057. // writes data to stream using printf() syntax,
  1058. // returns number of bytes written
  1059. size_t printf(char[] format, ...) {
  1060. va_list ap;
  1061. ap = cast(va_list) &format;
  1062. ap += format.sizeof;
  1063. return vprintf(format, ap);
  1064. }
  1065. private void doFormatCallback(dchar c) {
  1066. char[4] buf;
  1067. auto b = std.utf.toUTF8(buf, c);
  1068. writeString(b);
  1069. }
  1070. // writes data to stream using writef() syntax,
  1071. OutputStream writef(...) {
  1072. return writefx(_arguments,_argptr,0);
  1073. }
  1074. // writes data with trailing newline
  1075. OutputStream writefln(...) {
  1076. return writefx(_arguments,_argptr,1);
  1077. }
  1078. // writes data with optional trailing newline
  1079. OutputStream writefx(TypeInfo[] arguments, void* argptr, int newline=false) {
  1080. doFormat(&doFormatCallback,arguments,argptr);
  1081. if (newline)
  1082. writeLine("");
  1083. return this;
  1084. }
  1085. /***
  1086. * Copies all data from s into this stream.
  1087. * This may throw ReadException or WriteException on failure.
  1088. * This restores the file position of s so that it is unchanged.
  1089. */
  1090. void copyFrom(Stream s) {
  1091. if (seekable) {
  1092. ulong pos = s.position();
  1093. s.position(0);
  1094. copyFrom(s, s.size());
  1095. s.position(pos);
  1096. } else {
  1097. ubyte[128] buf;
  1098. while (!s.eof()) {
  1099. size_t m = s.readBlock(buf.ptr, buf.length);
  1100. writeExact(buf.ptr, m);
  1101. }
  1102. }
  1103. }
  1104. /***
  1105. * Copy a specified number of bytes from the given stream into this one.
  1106. * This may throw ReadException or WriteException on failure.
  1107. * Unlike the previous form, this doesn't restore the file position of s.
  1108. */
  1109. void copyFrom(Stream s, ulong count) {
  1110. ubyte[128] buf;
  1111. while (count > 0) {
  1112. size_t n = cast(size_t)(count<buf.length ? count : buf.length);
  1113. s.readExact(buf.ptr, n);
  1114. writeExact(buf.ptr, n);
  1115. count -= n;
  1116. }
  1117. }
  1118. /***
  1119. * Change the current position of the stream. whence is either SeekPos.Set, in
  1120. which case the offset is an absolute index from the beginning of the stream,
  1121. SeekPos.Current, in which case the offset is a delta from the current
  1122. position, or SeekPos.End, in which case the offset is a delta from the end of
  1123. the stream (negative or zero offsets only make sense in that case). This
  1124. returns the new file position.
  1125. */
  1126. abstract ulong seek(long offset, SeekPos whence);
  1127. /***
  1128. * Aliases for their normal seek counterparts.
  1129. */
  1130. ulong seekSet(long offset) { return seek (offset, SeekPos.Set); }
  1131. ulong seekCur(long offset) { return seek (offset, SeekPos.Current); } /// ditto
  1132. ulong seekEnd(long offset) { return seek (offset, SeekPos.End); } /// ditto
  1133. /***
  1134. * Sets file position. Equivalent to calling seek(pos, SeekPos.Set).
  1135. */
  1136. void position(ulong pos) { seek(cast(long)pos, SeekPos.Set); }
  1137. /***
  1138. * Returns current file position. Equivalent to seek(0, SeekPos.Current).
  1139. */
  1140. ulong position() { return seek(0, SeekPos.Current); }
  1141. /***
  1142. * Retrieve the size of the stream in bytes.
  1143. * The stream must be seekable or a SeekException is thrown.
  1144. */
  1145. ulong size() {
  1146. assertSeekable();
  1147. ulong pos = position(), result = seek(0, SeekPos.End);
  1148. position(pos);
  1149. return result;
  1150. }
  1151. // returns true if end of stream is reached, false otherwise
  1152. bool eof() {
  1153. // for unseekable streams we only know the end when we read it
  1154. if (readEOF && !ungetAvailable())
  1155. return true;
  1156. else if (seekable)
  1157. return position() == size();
  1158. else
  1159. return false;
  1160. }
  1161. // returns true if the stream is open
  1162. bool isOpen() { return isopen; }
  1163. // flush the buffer if writeable
  1164. void flush() {
  1165. if (unget.length > 1)
  1166. unget.length = 1; // keep at least 1 so that data ptr stays
  1167. }
  1168. // close the stream somehow; the default just flushes the buffer
  1169. void close() {
  1170. if (isopen)
  1171. flush();
  1172. readEOF = prevCr = isopen = readable = writeable = seekable = false;
  1173. }
  1174. /***
  1175. * Read the entire stream and return it as a string.
  1176. * If the stream is not seekable the contents from the current position to eof
  1177. * is read and returned.
  1178. */
  1179. override string toString() {
  1180. if (!readable)
  1181. return super.toString();
  1182. size_t pos;
  1183. size_t rdlen;
  1184. size_t blockSize;
  1185. char[] result;
  1186. if (seekable) {
  1187. ulong orig_pos = position();
  1188. position(0);
  1189. blockSize = cast(size_t)size();
  1190. result = new char[blockSize];
  1191. while (blockSize > 0) {
  1192. rdlen = readBlock(&result[pos], blockSize);
  1193. pos += rdlen;
  1194. blockSize -= rdlen;
  1195. }
  1196. position(orig_pos);
  1197. } else {
  1198. blockSize = 4096;
  1199. result = new char[blockSize];
  1200. while ((rdlen = readBlock(&result[pos], blockSize)) > 0) {
  1201. pos += rdlen;
  1202. blockSize += rdlen;
  1203. result.length = result.length + blockSize;
  1204. }
  1205. }
  1206. return cast(string) result[0 .. pos];
  1207. }
  1208. /***
  1209. * Get a hash of the stream by reading each byte and using it in a CRC-32
  1210. * checksum.
  1211. */
  1212. override size_t toHash() {
  1213. if (!readable || !seekable)
  1214. return super.toHash();
  1215. ulong pos = position();
  1216. uint crc = init_crc32 ();
  1217. position(0);
  1218. ulong len = size();
  1219. for (ulong i = 0; i < len; i++) {
  1220. ubyte c;
  1221. read(c);
  1222. crc = update_crc32(c, crc);
  1223. }
  1224. position(pos);
  1225. return crc;
  1226. }
  1227. // helper for checking that the stream is readable
  1228. final protected void assertReadable() {
  1229. if (!readable)
  1230. throw new ReadException("Stream is not readable");
  1231. }
  1232. // helper for checking that the stream is writeable
  1233. final protected void assertWriteable() {
  1234. if (!writeable)
  1235. throw new WriteException("Stream is not writeable");
  1236. }
  1237. // helper for checking that the stream is seekable
  1238. final protected void assertSeekable() {
  1239. if (!seekable)
  1240. throw new SeekException("Stream is not seekable");
  1241. }
  1242. }
  1243. /***
  1244. * A base class for streams that wrap a source stream with additional
  1245. * functionality.
  1246. *
  1247. * The method implementations forward read/write/seek calls to the
  1248. * source stream. A FilterStream can change the position of the source stream
  1249. * arbitrarily and may not keep the source stream state in sync with the
  1250. * FilterStream, even upon flushing and closing the FilterStream. It is
  1251. * recommended to not make any assumptions about the state of the source position
  1252. * and read/write state after a FilterStream has acted upon it. Specifc subclasses
  1253. * of FilterStream should document how they modify the source stream and if any
  1254. * invariants hold true between the source and filter.
  1255. */
  1256. class FilterStream : Stream {
  1257. private Stream s; // source stream
  1258. /// Property indicating when this stream closes to close the source stream as
  1259. /// well.
  1260. /// Defaults to true.
  1261. bool nestClose = true;
  1262. /// Construct a FilterStream for the given source.
  1263. this(Stream source) {
  1264. s = source;
  1265. resetSource();
  1266. }
  1267. // source getter/setter
  1268. /***
  1269. * Get the current source stream.
  1270. */
  1271. final Stream source(){return s;}
  1272. /***
  1273. * Set the current source stream.
  1274. *
  1275. * Setting the source stream closes this stream before attaching the new
  1276. * source. Attaching an open stream reopens this stream and resets the stream
  1277. * state.
  1278. */
  1279. void source(Stream s) {
  1280. close();
  1281. this.s = s;
  1282. resetSource();
  1283. }
  1284. /***
  1285. * Indicates the source stream changed state and that this stream should reset
  1286. * any readable, writeable, seekable, isopen and buffering flags.
  1287. */
  1288. void resetSource() {
  1289. if (s !is null) {
  1290. readable = s.readable;
  1291. writeable = s.writeable;
  1292. seekable = s.seekable;
  1293. isopen = s.isOpen();
  1294. } else {
  1295. readable = writeable = seekable = false;
  1296. isopen = false;
  1297. }
  1298. readEOF = prevCr = false;
  1299. }
  1300. // read from source
  1301. override size_t readBlock(void* buffer, size_t size) {
  1302. size_t res = s.readBlock(buffer,size);
  1303. readEOF = res == 0;
  1304. return res;
  1305. }
  1306. // write to source
  1307. override size_t writeBlock(const void* buffer, size_t size) {
  1308. return s.writeBlock(buffer,size);
  1309. }
  1310. // close stream
  1311. override void close() {
  1312. if (isopen) {
  1313. super.close();
  1314. if (nestClose)
  1315. s.close();
  1316. }
  1317. }
  1318. // seek on source
  1319. override ulong seek(long offset, SeekPos whence) {
  1320. readEOF = false;
  1321. return s.seek(offset,whence);
  1322. }
  1323. override size_t available () { return s.available(); }
  1324. override void flush() { super.flush(); s.flush(); }
  1325. }
  1326. /***
  1327. * This subclass is for buffering a source stream.
  1328. *
  1329. * A buffered stream must be
  1330. * closed explicitly to ensure the final buffer content is written to the source
  1331. * stream. The source stream position is changed according to the block size so
  1332. * reading or writing to the BufferedStream may not change the source stream
  1333. * position by the same amount.
  1334. */
  1335. class BufferedStream : FilterStream {
  1336. ubyte[] buffer; // buffer, if any
  1337. uint bufferCurPos; // current position in buffer
  1338. uint bufferLen; // amount of data in buffer
  1339. bool bufferDirty = false;
  1340. uint bufferSourcePos; // position in buffer of source stream position
  1341. ulong streamPos; // absolute position in source stream
  1342. /* Example of relationship between fields:
  1343. *
  1344. * s ...01234567890123456789012EOF
  1345. * buffer |-- --|
  1346. * bufferCurPos |
  1347. * bufferLen |-- --|
  1348. * bufferSourcePos |
  1349. *
  1350. */
  1351. invariant() {
  1352. assert(bufferSourcePos <= bufferLen);
  1353. assert(bufferCurPos <= bufferLen);
  1354. assert(bufferLen <= buffer.length);
  1355. }
  1356. const uint DefaultBufferSize = 8192;
  1357. /***
  1358. * Create a buffered stream for the stream source with the buffer size
  1359. * bufferSize.
  1360. */
  1361. this(Stream source, uint bufferSize = DefaultBufferSize) {
  1362. super(source);
  1363. if (bufferSize)
  1364. buffer = new ubyte[bufferSize];
  1365. }
  1366. override protected void resetSource() {
  1367. super.resetSource();
  1368. streamPos = 0;
  1369. bufferLen = bufferSourcePos = bufferCurPos = 0;
  1370. bufferDirty = false;
  1371. }
  1372. // reads block of data of specified size using any buffered data
  1373. // returns actual number of bytes read
  1374. override size_t readBlock(void* result, size_t len) {
  1375. if (len == 0) return 0;
  1376. assertReadable();
  1377. ubyte* outbuf = cast(ubyte*)result;
  1378. size_t readsize = 0;
  1379. if (bufferCurPos + len < bufferLen) {
  1380. // buffer has all the data so copy it
  1381. outbuf[0 .. len] = buffer[bufferCurPos .. bufferCurPos+len];
  1382. bufferCurPos += len;
  1383. readsize = len;
  1384. goto ExitRead;
  1385. }
  1386. readsize = bufferLen - bufferCurPos;
  1387. if (readsize > 0) {
  1388. // buffer has some data so copy what is left
  1389. outbuf[0 .. readsize] = buffer[bufferCurPos .. bufferLen];
  1390. outbuf += readsize;
  1391. bufferCurPos += readsize;
  1392. len -= readsize;
  1393. }
  1394. flush();
  1395. if (len >= buffer.length) {
  1396. // buffer can't hold the data so fill output buffer directly
  1397. size_t siz = super.readBlock(outbuf, len);
  1398. readsize += siz;
  1399. streamPos += siz;
  1400. } else {
  1401. // read a new block into buffer
  1402. bufferLen = super.readBlock(buffer.ptr, buffer.length);
  1403. if (bufferLen < len) len = bufferLen;
  1404. outbuf[0 .. len] = buffer[0 .. len];
  1405. bufferSourcePos = bufferLen;
  1406. streamPos += bufferLen;
  1407. bufferCurPos = len;
  1408. readsize += len;
  1409. }
  1410. ExitRead:
  1411. return readsize;
  1412. }
  1413. // write block of data of specified size
  1414. // returns actual number of bytes written
  1415. override size_t writeBlock(const void* result, size_t len) {
  1416. assertWriteable();
  1417. ubyte* buf = cast(ubyte*)result;
  1418. size_t writesize = 0;
  1419. if (bufferLen == 0) {
  1420. // buffer is empty so fill it if possible
  1421. if ((len < buffer.length) && (readable)) {
  1422. // read in data if the buffer is currently empty
  1423. bufferLen = s.readBlock(buffer.ptr, buffer.length);
  1424. bufferSourcePos = bufferLen;
  1425. streamPos += bufferLen;
  1426. } else if (len >= buffer.length) {
  1427. // buffer can't hold the data so write it directly and exit
  1428. writesize = s.writeBlock(buf,len);
  1429. streamPos += writesize;
  1430. goto ExitWrite;
  1431. }
  1432. }
  1433. if (bufferCurPos + len <= buffer.length) {
  1434. // buffer has space for all the data so copy it and exit
  1435. buffer[bufferCurPos .. bufferCurPos+len] = buf[0 .. len];
  1436. bufferCurPos += len;
  1437. bufferLen = bufferCurPos > bufferLen ? bufferCurPos : bufferLen;
  1438. writesize = len;
  1439. bufferDirty = true;
  1440. goto ExitWrite;
  1441. }
  1442. writesize = buffer.length - bufferCurPos;
  1443. if (writesize > 0) {
  1444. // buffer can take some data
  1445. buffer[bufferCurPos .. buffer.length] = buf[0 .. writesize];
  1446. bufferCurPos = bufferLen = buffer.length;
  1447. buf += writesize;
  1448. len -= writesize;
  1449. bufferDirty = true;
  1450. }
  1451. assert(bufferCurPos == buffer.length);
  1452. assert(bufferLen == buffer.length);
  1453. flush();
  1454. writesize += writeBlock(buf,len);
  1455. ExitWrite:
  1456. return writesize;
  1457. }
  1458. override ulong seek(long offset, SeekPos whence) {
  1459. assertSeekable();
  1460. if ((whence != SeekPos.Current) ||
  1461. (offset + bufferCurPos < 0) ||
  1462. (offset + bufferCurPos >= bufferLen)) {
  1463. flush();
  1464. streamPos = s.seek(offset,whence);
  1465. } else {
  1466. bufferCurPos += offset;
  1467. }
  1468. readEOF = false;
  1469. return streamPos-bufferSourcePos+bufferCurPos;
  1470. }
  1471. // Buffered readLine - Dave Fladebo
  1472. // reads a line, terminated by either CR, LF, CR/LF, or EOF
  1473. // reusing the memory in buffer if result will fit, otherwise
  1474. // will reallocate (using concatenation)
  1475. template TreadLine(T) {
  1476. T[] readLine(T[] inBuffer)
  1477. {
  1478. size_t lineSize = 0;
  1479. bool haveCR = false;
  1480. T c = '\0';
  1481. size_t idx = 0;
  1482. ubyte* pc = cast(ubyte*)&c;
  1483. L0:
  1484. for(;;) {
  1485. uint start = bufferCurPos;
  1486. L1:
  1487. foreach(ubyte b; buffer[start .. bufferLen]) {
  1488. bufferCurPos++;
  1489. pc[idx] = b;
  1490. if(idx < T.sizeof - 1) {
  1491. idx++;
  1492. continue L1;
  1493. } else {
  1494. idx = 0;
  1495. }
  1496. if(c == '\n' || haveCR) {
  1497. if(haveCR && c != '\n') bufferCurPos--;
  1498. break L0;
  1499. } else {
  1500. if(c == '\r') {
  1501. haveCR = true;
  1502. } else {
  1503. if(lineSize < inBuffer.length) {
  1504. inBuffer[lineSize] = c;
  1505. } else {
  1506. inBuffer ~= c;
  1507. }
  1508. lineSize++;
  1509. }
  1510. }
  1511. }
  1512. flush();
  1513. size_t res = super.readBlock(buffer.ptr, buffer.length);
  1514. if(!res) break L0; // EOF
  1515. bufferSourcePos = bufferLen = res;
  1516. streamPos += res;
  1517. }
  1518. return inBuffer[0 .. lineSize];
  1519. }
  1520. } // template TreadLine(T)
  1521. override char[] readLine(char[] inBuffer) {
  1522. if (ungetAvailable())
  1523. return super.readLine(inBuffer);
  1524. else
  1525. return TreadLine!(char).readLine(inBuffer);
  1526. }
  1527. alias Stream.readLine readLine;
  1528. override wchar[] readLineW(wchar[] inBuffer) {
  1529. if (ungetAvailable())
  1530. return super.readLineW(inBuffer);
  1531. else
  1532. return TreadLine!(wchar).readLine(inBuffer);
  1533. }
  1534. alias Stream.readLineW readLineW;
  1535. override void flush()
  1536. out {
  1537. assert(bufferCurPos == 0);
  1538. assert(bufferSourcePos == 0);
  1539. assert(bufferLen == 0);
  1540. }
  1541. body {
  1542. if (writeable && bufferDirty) {
  1543. if (bufferSourcePos != 0 && seekable) {
  1544. // move actual file pointer to front of buffer
  1545. streamPos = s.seek(-bufferSourcePos, SeekPos.Current);
  1546. }
  1547. // write buffer out
  1548. bufferSourcePos = s.writeBlock(buffer.ptr, bufferLen);
  1549. if (bufferSourcePos != bufferLen) {
  1550. throw new WriteException("Unable to write to stream");
  1551. }
  1552. }
  1553. super.flush();
  1554. long diff = cast(long)bufferCurPos-bufferSourcePos;
  1555. if (diff != 0 && seekable) {
  1556. // move actual file pointer to current position
  1557. streamPos = s.seek(diff, SeekPos.Current);
  1558. }
  1559. // reset buffer data to be empty
  1560. bufferSourcePos = bufferCurPos = bufferLen = 0;
  1561. bufferDirty = false;
  1562. }
  1563. // returns true if end of stream is reached, false otherwise
  1564. override bool eof() {
  1565. if ((buffer.length == 0) || !readable) {
  1566. return super.eof();
  1567. }
  1568. // some simple tests to avoid flushing
  1569. if (ungetAvailable() || bufferCurPos != bufferLen)
  1570. return false;
  1571. if (bufferLen == buffer.length)
  1572. flush();
  1573. size_t res = super.readBlock(&buffer[bufferLen],buffer.length-bufferLen);
  1574. bufferSourcePos += res;
  1575. bufferLen += res;
  1576. streamPos += res;
  1577. return readEOF;
  1578. }
  1579. // returns size of stream
  1580. override ulong size() {
  1581. if (bufferDirty) flush();
  1582. return s.size();
  1583. }
  1584. // returns estimated number of bytes available for immediate reading
  1585. override size_t available() {
  1586. return bufferLen - bufferCurPos;
  1587. }
  1588. }
  1589. /// An exception for File errors.
  1590. class StreamFileException: StreamException {
  1591. /// Construct a StreamFileException with given error message.
  1592. this(string msg) { super(msg); }
  1593. }
  1594. /// An exception for errors during File.open.
  1595. class OpenException: StreamFileException {
  1596. /// Construct an OpenFileException with given error message.
  1597. this(string msg) { super(msg); }
  1598. }
  1599. // access modes; may be or'ed
  1600. enum FileMode {
  1601. In = 1,
  1602. Out = 2,
  1603. OutNew = 6, // includes FileMode.Out
  1604. Append = 10 // includes FileMode.Out
  1605. }
  1606. version (Win32) {
  1607. private import std.c.windows.windows;
  1608. extern (Windows) {
  1609. void FlushFileBuffers(HANDLE hFile);
  1610. DWORD GetFileType(HANDLE hFile);
  1611. }
  1612. }
  1613. version (Posix) {
  1614. private import core.sys.posix.fcntl;
  1615. private import core.sys.posix.unistd;
  1616. alias int HANDLE;
  1617. }
  1618. /// This subclass is for unbu…

Large files files are truncated, but you can click here to view the full file