PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/AllInOne/main/POIFS/FileSystem/POIFSDocumentReader.cs

#
C# | 452 lines | 213 code | 23 blank | 216 comment | 26 complexity | 7ff4fa69f88a9e39c466ffca6c128eae MD5 | raw file
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for Additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. /* ================================================================
  16. * About NPOI
  17. * Author: Tony Qu
  18. * Author's email: tonyqus (at) gmail.com
  19. * Author's Blog: tonyqus.wordpress.com.cn (wp.tonyqus.cn)
  20. * HomePage: http://www.codeplex.com/npoi
  21. * Contributors:
  22. *
  23. * ==============================================================*/
  24. using System;
  25. using System.Collections.Generic;
  26. using System.Text;
  27. using System.IO;
  28. namespace NPOI.POIFS.FileSystem
  29. {
  30. /// <summary>
  31. /// This class provides methods to read a DocumentEntry managed by a
  32. /// Filesystem instance.
  33. /// @author Marc Johnson (mjohnson at apache dot org)
  34. /// </summary>
  35. public class POIFSDocumentReader:Stream
  36. {
  37. private bool _closed;
  38. private int _current_offset;
  39. private POIFSDocument _document;
  40. private int _document_size;
  41. private byte[] _tiny_buffer;
  42. private const int _EOD = 0;
  43. /// <summary>
  44. /// Create an InputStream from the specified DocumentEntry
  45. /// </summary>
  46. /// <param name="document">the DocumentEntry to be read</param>
  47. public POIFSDocumentReader(DocumentEntry document)
  48. {
  49. this._current_offset = 0;
  50. this._document_size = document.Size;
  51. this._closed = false;
  52. this._tiny_buffer = null;
  53. if (!(document is DocumentNode))
  54. {
  55. throw new IOException("Cannot open internal document storage");
  56. }
  57. this._document = ((DocumentNode)document).Document;
  58. }
  59. /// <summary>
  60. /// Create an InputStream from the specified Document
  61. /// </summary>
  62. /// <param name="document">the Document to be read</param>
  63. public POIFSDocumentReader(POIFSDocument document)
  64. {
  65. this._current_offset = 0;
  66. this._document_size = document.Size;
  67. this._closed = false;
  68. this._tiny_buffer = null;
  69. this._document = document;
  70. }
  71. /// <summary>
  72. /// at the end Of document.
  73. /// </summary>
  74. /// <returns></returns>
  75. private bool EOD
  76. {
  77. get
  78. {
  79. return (this._current_offset == this._document_size);
  80. }
  81. }
  82. /// <summary>
  83. /// Returns the number of bytes that can be read (or skipped over)
  84. /// from this input stream without blocking by the next caller of a
  85. /// method for this input stream. The next caller might be the same
  86. /// thread or or another thread.
  87. /// </summary>
  88. /// <value>the number of bytes that can be read from this input
  89. /// stream without blocking.</value>
  90. public int Available
  91. {
  92. get {
  93. if (_closed)
  94. throw new IOException("This stream is closed");
  95. return (int)(this.Length - this.Position);
  96. }
  97. }
  98. /// <summary>
  99. /// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream.
  100. /// </summary>
  101. public override void Close()
  102. {
  103. this._closed = true;
  104. }
  105. private void DieIfClosed()
  106. {
  107. if (this._closed)
  108. {
  109. throw new IOException("cannot perform requested operation on a closed stream");
  110. }
  111. }
  112. public override void Flush()
  113. {
  114. throw new NotImplementedException();
  115. }
  116. /// <summary>
  117. /// Reads some number of bytes from the input stream and stores
  118. /// them into the buffer array b. The number of bytes actually read
  119. /// is returned as an integer. The definition of this method in
  120. /// java.io.InputStream allows this method to block, but it won't.
  121. /// If b is null, a NullPointerException is thrown. If the length
  122. /// of b is zero, then no bytes are read and 0 is returned;
  123. /// otherwise, there is an attempt to read at least one byte. If no
  124. /// byte is available because the stream is at end of file, the
  125. /// value -1 is returned; otherwise, at least one byte is read and
  126. /// stored into b.
  127. /// The first byte read is stored into element b[0], the next one
  128. /// into b[1], and so on. The number of bytes read is, at most,
  129. /// equal to the length of b. Let k be the number of bytes actually
  130. /// read; these bytes will be stored in elements b[0] through
  131. /// b[k-1], leaving elements b[k] through b[b.length-1] unaffected.
  132. /// If the first byte cannot be read for any reason other than end
  133. /// of file, then an IOException is thrown. In particular, an
  134. /// IOException is thrown if the input stream has been closed.
  135. /// The read(b) method for class InputStream has the same effect as:
  136. /// </summary>
  137. /// <param name="b">the buffer into which the data is read.</param>
  138. /// <returns>the total number of bytes read into the buffer, or -1
  139. /// if there is no more data because the end of the stream
  140. /// has been reached.</returns>
  141. public int Read(byte[] b)
  142. {
  143. return this.Read(b, 0, b.Length);
  144. }
  145. /// <summary>
  146. /// Reads up to len bytes of data from the input stream into an
  147. /// array of bytes. An attempt is made to read as many as len
  148. /// bytes, but a smaller number may be read, possibly zero. The
  149. /// number of bytes actually read is returned as an integer.
  150. /// The definition of this method in java.io.InputStream allows it
  151. /// to block, but it won't.
  152. /// If b is null, a NullPointerException is thrown.
  153. /// If off is negative, or len is negative, or off+len is greater
  154. /// than the length of the array b, then an
  155. /// IndexOutOfBoundsException is thrown.
  156. /// If len is zero, then no bytes are read and 0 is returned;
  157. /// otherwise, there is an attempt to read at least one byte. If no
  158. /// byte is available because the stream is at end of file, the
  159. /// value -1 is returned; otherwise, at least one byte is read and
  160. /// stored into b.
  161. /// The first byte read is stored into element b[off], the next one
  162. /// into b[off+1], and so on. The number of bytes read is, at most,
  163. /// equal to len. Let k be the number of bytes actually read; these
  164. /// bytes will be stored in elements b[off] through b[off+k-1],
  165. /// leaving elements b[off+k] through b[off+len-1] unaffected.
  166. /// In every case, elements b[0] through b[off] and elements
  167. /// b[off+len] through b[b.length-1] are unaffected.
  168. /// If the first byte cannot be read for any reason other than end
  169. /// of file, then an IOException is thrown. In particular, an
  170. /// IOException is thrown if the input stream has been closed.
  171. /// </summary>
  172. /// <param name="b">the buffer into which the data is read.</param>
  173. /// <param name="off">the start offset in array b at which the data is
  174. /// written.</param>
  175. /// <param name="len">the maximum number of bytes to read.</param>
  176. /// <returns>the total number of bytes read into the buffer, or -1
  177. /// if there is no more data because the end of the stream
  178. /// has been reached.</returns>
  179. public override int Read(byte[] b, int off, int len)
  180. {
  181. this.DieIfClosed();
  182. if (b == null)
  183. {
  184. throw new NullReferenceException("buffer is null");
  185. }
  186. if (((off < 0) || (len < 0)) || (b.Length < (off + len)))
  187. {
  188. throw new IndexOutOfRangeException("can't read past buffer boundaries");
  189. }
  190. if (len == 0)
  191. {
  192. return 0;
  193. }
  194. if (this.EOD)
  195. {
  196. return -1;
  197. }
  198. int length = Math.Min(this.Available, len);
  199. if ((off == 0) && (length == b.Length))
  200. {
  201. this._document.Read(b, this._current_offset);
  202. }
  203. else
  204. {
  205. byte[] buffer = new byte[length];
  206. this._document.Read(buffer, this._current_offset);
  207. Array.Copy(buffer, 0, b, off, length);
  208. }
  209. this._current_offset += length;
  210. return length;
  211. }
  212. /// <summary>
  213. /// Reads the next byte of data from the input stream. The value
  214. /// byte is returned as an int in the range 0 to 255. If no byte is
  215. /// available because the end of the stream has been reached, the
  216. /// value -1 is returned. The definition of this method in
  217. /// java.io.InputStream allows this method to block, but it won't.
  218. /// </summary>
  219. /// <returns>the next byte of data, or -1 if the end of the stream
  220. /// is reached.
  221. /// </returns>
  222. public override int ReadByte()
  223. {
  224. this.DieIfClosed();
  225. if (this.EOD)
  226. {
  227. return -1;
  228. }
  229. if (this._tiny_buffer == null)
  230. {
  231. this._tiny_buffer = new byte[1];
  232. }
  233. this._document.Read(this._tiny_buffer, this._current_offset++);
  234. return (this._tiny_buffer[0] & 0xff);
  235. }
  236. /// <summary>
  237. /// When overridden in a derived class, sets the position within the current stream.
  238. /// </summary>
  239. /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>
  240. /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"/> indicating the reference point used to obtain the new position.</param>
  241. /// <returns>
  242. /// The new position within the current stream.
  243. /// </returns>
  244. /// <exception cref="T:System.IO.IOException">
  245. /// An I/O error occurs.
  246. /// </exception>
  247. /// <exception cref="T:System.NotSupportedException">
  248. /// The stream does not support seeking, such as if the stream is constructed from a pipe or console output.
  249. /// </exception>
  250. /// <exception cref="T:System.ObjectDisposedException">
  251. /// Methods were called after the stream was closed.
  252. /// </exception>
  253. public override long Seek(long offset, SeekOrigin origin)
  254. {
  255. if (!this.CanSeek)
  256. {
  257. throw new NotSupportedException();
  258. }
  259. int dwOrigin = 0;
  260. switch (origin)
  261. {
  262. case SeekOrigin.Begin:
  263. dwOrigin = 0;
  264. if (0L > offset)
  265. {
  266. throw new ArgumentOutOfRangeException("offset","offset must be positive");
  267. }
  268. this.Position = offset<this.Length?offset:this.Length;
  269. break;
  270. case SeekOrigin.Current:
  271. dwOrigin = 1;
  272. this.Position = (this.Position + offset) < this.Length ? (this.Position + offset) : this.Length;
  273. break;
  274. case SeekOrigin.End:
  275. dwOrigin = 2;
  276. this.Position = this.Length;
  277. break;
  278. default:
  279. throw new ArgumentException("incorrect SeekOrigin","origin");
  280. }
  281. return Position;
  282. }
  283. public override void SetLength(long value)
  284. {
  285. }
  286. /// <summary>
  287. /// Skips the specified n.
  288. /// </summary>
  289. /// <param name="n">The n.</param>
  290. /// <returns></returns>
  291. public long Skip(long n)
  292. {
  293. this.DieIfClosed();
  294. if (n < 0L)
  295. {
  296. return 0L;
  297. }
  298. int num = this._current_offset + ((int)n);
  299. if (num < this._current_offset)
  300. {
  301. num = this._document_size;
  302. }
  303. else if (num > this._document_size)
  304. {
  305. num = this._document_size;
  306. }
  307. long num2 = num - this._current_offset;
  308. this._current_offset = num;
  309. return num2;
  310. }
  311. /// <summary>
  312. /// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
  313. /// </summary>
  314. /// <param name="buffer">An array of bytes. This method copies <paramref name="count"/> bytes from <paramref name="buffer"/> to the current stream.</param>
  315. /// <param name="offset">The zero-based byte offset in <paramref name="buffer"/> at which to begin copying bytes to the current stream.</param>
  316. /// <param name="count">The number of bytes to be written to the current stream.</param>
  317. /// <exception cref="T:System.ArgumentException">
  318. /// The sum of <paramref name="offset"/> and <paramref name="count"/> is greater than the buffer length.
  319. /// </exception>
  320. /// <exception cref="T:System.ArgumentNullException">
  321. /// <paramref name="buffer"/> is null.
  322. /// </exception>
  323. /// <exception cref="T:System.ArgumentOutOfRangeException">
  324. /// <paramref name="offset"/> or <paramref name="count"/> is negative.
  325. /// </exception>
  326. /// <exception cref="T:System.IO.IOException">
  327. /// An I/O error occurs.
  328. /// </exception>
  329. /// <exception cref="T:System.NotSupportedException">
  330. /// The stream does not support writing.
  331. /// </exception>
  332. /// <exception cref="T:System.ObjectDisposedException">
  333. /// Methods were called after the stream was closed.
  334. /// </exception>
  335. public override void Write(byte[] buffer, int offset, int count)
  336. {
  337. throw new NotImplementedException();
  338. }
  339. // Properties
  340. /// <summary>
  341. /// When overridden in a derived class, gets a value indicating whether the current stream supports reading.
  342. /// </summary>
  343. /// <value></value>
  344. /// <returns>true if the stream supports reading; otherwise, false.
  345. /// </returns>
  346. public override bool CanRead
  347. {
  348. get
  349. {
  350. return true;
  351. }
  352. }
  353. /// <summary>
  354. /// When overridden in a derived class, gets a value indicating whether the current stream supports seeking.
  355. /// </summary>
  356. /// <value></value>
  357. /// <returns>true if the stream supports seeking; otherwise, false.
  358. /// </returns>
  359. public override bool CanSeek
  360. {
  361. get
  362. {
  363. return true;
  364. }
  365. }
  366. /// <summary>
  367. /// When overridden in a derived class, gets a value indicating whether the current stream supports writing.
  368. /// </summary>
  369. /// <value></value>
  370. /// <returns>true if the stream supports writing; otherwise, false.
  371. /// </returns>
  372. public override bool CanWrite
  373. {
  374. get
  375. {
  376. return false;
  377. }
  378. }
  379. /// <summary>
  380. /// When overridden in a derived class, gets the length in bytes of the stream.
  381. /// </summary>
  382. /// <value></value>
  383. /// <returns>
  384. /// A long value representing the length of the stream in bytes.
  385. /// </returns>
  386. /// <exception cref="T:System.NotSupportedException">
  387. /// A class derived from Stream does not support seeking.
  388. /// </exception>
  389. /// <exception cref="T:System.ObjectDisposedException">
  390. /// Methods were called after the stream was closed.
  391. /// </exception>
  392. public override long Length
  393. {
  394. get
  395. {
  396. return (long)this._document_size;
  397. }
  398. }
  399. /// <summary>
  400. /// When overridden in a derived class, gets or sets the position within the current stream.
  401. /// </summary>
  402. /// <value></value>
  403. /// <returns>
  404. /// The current position within the stream.
  405. /// </returns>
  406. /// <exception cref="T:System.IO.IOException">
  407. /// An I/O error occurs.
  408. /// </exception>
  409. /// <exception cref="T:System.NotSupportedException">
  410. /// The stream does not support seeking.
  411. /// </exception>
  412. /// <exception cref="T:System.ObjectDisposedException">
  413. /// Methods were called after the stream was closed.
  414. /// </exception>
  415. public override long Position
  416. {
  417. get
  418. {
  419. return (long)this._current_offset;
  420. }
  421. set
  422. {
  423. this._current_offset = Convert.ToInt32(value);
  424. }
  425. }
  426. }
  427. }