PageRenderTime 3773ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/ZipPla/iTextSharp/iTextSharp/text/io/GroupedRandomAccessSource.cs

https://bitbucket.org/udaken/zippla-mirror
C# | 267 lines | 103 code | 37 blank | 127 comment | 17 complexity | dd554f7ec95f116c967cfd8c7b517452 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. /*
  4. * $Id: GroupedRandomAccessSource.java 5551 2012-11-21 18:47:14Z trumpetinc $
  5. *
  6. * This file is part of the iText (R) project.
  7. * Copyright (c) 1998-2016 iText Group NV
  8. * BVBA Authors: Kevin Day, Bruno Lowagie, et al.
  9. *
  10. * This program is free software; you can redistribute it and/or modify it under
  11. * the terms of the GNU Affero General License version 3 as published by the
  12. * Free Software Foundation with the addition of the following permission added
  13. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  14. * IN WHICH THE COPYRIGHT IS OWNED BY ITEXT GROUP, ITEXT GROUP DISCLAIMS THE WARRANTY OF NON
  15. * INFRINGEMENT OF THIRD PARTY RIGHTS.
  16. *
  17. * This program is distributed in the hope that it will be useful, but WITHOUT
  18. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  19. * FOR A PARTICULAR PURPOSE. See the GNU Affero General License for more
  20. * details. You should have received a copy of the GNU Affero General License
  21. * along with this program; if not, see http://www.gnu.org/licenses or write to
  22. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  23. * MA, 02110-1301 USA, or download the license from the following URL:
  24. * http://itextpdf.com/terms-of-use/
  25. *
  26. * The interactive user interfaces in modified source and object code versions
  27. * of this program must display Appropriate Legal Notices, as required under
  28. * Section 5 of the GNU Affero General License.
  29. *
  30. * In accordance with Section 7(b) of the GNU Affero General License, a covered
  31. * work must retain the producer line in every PDF that is created or
  32. * manipulated using iText.
  33. *
  34. * You can be released from the requirements of the license by purchasing a
  35. * commercial license. Buying such a license is mandatory as soon as you develop
  36. * commercial activities involving the iText software without disclosing the
  37. * source code of your own applications. These activities include: offering paid
  38. * services to customers as an ASP, serving PDFs on the fly in a web
  39. * application, shipping iText with a closed source product.
  40. *
  41. * For more information, please contact iText Software Corp. at this address:
  42. * sales@itextpdf.com
  43. */
  44. namespace iTextSharp.text.io {
  45. /**
  46. * A RandomAccessSource that is based on a set of underlying sources, treating the sources as if they were a contiguous block of data.
  47. * @since 5.3.5
  48. */
  49. internal class GroupedRandomAccessSource : IRandomAccessSource {
  50. /**
  51. * The underlying sources (along with some meta data to quickly determine where each source begins and ends)
  52. */
  53. private readonly SourceEntry[] sources;
  54. /**
  55. * Cached value to make multiple reads from the same underlying source more efficient
  56. */
  57. private SourceEntry currentSourceEntry;
  58. /**
  59. * Cached size of the underlying channel
  60. */
  61. private readonly long size;
  62. /**
  63. * Constructs a new {@link GroupedRandomAccessSource} based on the specified set of sources
  64. * @param sources the sources used to build this group
  65. */
  66. public GroupedRandomAccessSource(ICollection<IRandomAccessSource> sources) {
  67. this.sources = new SourceEntry[sources.Count];
  68. long totalSize = 0;
  69. int i = 0;
  70. foreach (IRandomAccessSource ras in sources) {
  71. this.sources[i] = new SourceEntry(i, ras, totalSize);
  72. ++i;
  73. totalSize += ras.Length;
  74. }
  75. size = totalSize;
  76. currentSourceEntry = this.sources[sources.Count-1];
  77. SourceInUse(currentSourceEntry.source);
  78. }
  79. /**
  80. * For a given offset, return the index of the source that contains the specified offset.
  81. * This is an optimization feature to help optimize the access of the correct source without having to iterate
  82. * through every single source each time. It is safe to always return 0, in which case the full set of sources will be searched.
  83. * Subclasses should override this method if they are able to compute the source index more efficiently (for example {@link FileChannelRandomAccessSource} takes advantage of fixed size page buffers to compute the index)
  84. * @param offset the offset
  85. * @return the index of the input source that contains the specified offset, or 0 if unknown
  86. */
  87. protected internal virtual int GetStartingSourceIndex(long offset){
  88. if (offset >= currentSourceEntry.firstByte)
  89. return currentSourceEntry.index;
  90. return 0;
  91. }
  92. /**
  93. * Returns the SourceEntry that contains the byte at the specified offset
  94. * sourceReleased is called as a notification callback so subclasses can take care of cleanup when the source is no longer the active source
  95. * @param offset the offset of the byte to look for
  96. * @return the SourceEntry that contains the byte at the specified offset
  97. * @throws IOException if there is a problem with IO (usually the result of the sourceReleased() call)
  98. */
  99. private SourceEntry GetSourceEntryForOffset(long offset) {
  100. if (offset >= size)
  101. return null;
  102. if (offset >= currentSourceEntry.firstByte && offset <= currentSourceEntry.lastByte)
  103. return currentSourceEntry;
  104. // hook to allow subclasses to release resources if necessary
  105. SourceReleased(currentSourceEntry.source);
  106. int startAt = GetStartingSourceIndex(offset);
  107. for(int i = startAt; i < sources.Length; i++){
  108. if (offset >= sources[i].firstByte && offset <= sources[i].lastByte){
  109. currentSourceEntry = sources[i];
  110. SourceInUse(currentSourceEntry.source);
  111. return currentSourceEntry;
  112. }
  113. }
  114. return null;
  115. }
  116. /**
  117. * Called when a given source is no longer the active source. This gives subclasses the abilty to release resources, if appropriate.
  118. * @param source the source that is no longer the active source
  119. * @throws IOException if there are any problems
  120. */
  121. protected internal virtual void SourceReleased(IRandomAccessSource source) {
  122. // by default, do nothing
  123. }
  124. /**
  125. * Called when a given source is about to become the active source. This gives subclasses the abilty to retrieve resources, if appropriate.
  126. * @param source the source that is about to become the active source
  127. * @throws IOException if there are any problems
  128. */
  129. protected internal virtual void SourceInUse(IRandomAccessSource source) {
  130. // by default, do nothing
  131. }
  132. /**
  133. * {@inheritDoc}
  134. * The source that contains the byte at position is retrieved, the correct offset into that source computed, then the value
  135. * from that offset in the underlying source is returned.
  136. */
  137. public virtual int Get(long position) {
  138. SourceEntry entry = GetSourceEntryForOffset(position);
  139. if (entry == null) // we have run out of data to read from
  140. return -1;
  141. return entry.source.Get(entry.OffsetN(position));
  142. }
  143. /**
  144. * {@inheritDoc}
  145. */
  146. public virtual int Get(long position, byte[] bytes, int off, int len) {
  147. SourceEntry entry = GetSourceEntryForOffset(position);
  148. if (entry == null) // we have run out of data to read from
  149. return -1;
  150. long offN = entry.OffsetN(position);
  151. int remaining = len;
  152. while(remaining > 0){
  153. if (entry == null) // we have run out of data to read from
  154. break;
  155. if (offN > entry.source.Length)
  156. break;
  157. int count = entry.source.Get(offN, bytes, off, remaining);
  158. if (count == -1)
  159. break;
  160. off += count;
  161. position += count;
  162. remaining -= count;
  163. offN = 0;
  164. entry = GetSourceEntryForOffset(position);
  165. }
  166. return remaining == len ? -1 : len - remaining;
  167. }
  168. /**
  169. * {@inheritDoc}
  170. */
  171. public virtual long Length {
  172. get {
  173. return size;
  174. }
  175. }
  176. /**
  177. * {@inheritDoc}
  178. * Closes all of the underlying sources
  179. */
  180. public virtual void Close() {
  181. foreach (SourceEntry entry in sources) {
  182. entry.source.Close();
  183. }
  184. }
  185. virtual public void Dispose() {
  186. Close();
  187. }
  188. /**
  189. * Used to track each source, along with useful meta data
  190. */
  191. private sealed class SourceEntry{
  192. /**
  193. * The underlying source
  194. */
  195. internal readonly IRandomAccessSource source;
  196. /**
  197. * The first byte (in the coordinates of the GroupedRandomAccessSource) that this source contains
  198. */
  199. internal readonly long firstByte;
  200. /**
  201. * The last byte (in the coordinates of the GroupedRandomAccessSource) that this source contains
  202. */
  203. internal readonly long lastByte;
  204. /**
  205. * The index of this source in the GroupedRandomAccessSource
  206. */
  207. internal readonly int index;
  208. /**
  209. * Standard constructor
  210. * @param index the index
  211. * @param source the source
  212. * @param offset the offset of the source in the GroupedRandomAccessSource
  213. */
  214. internal SourceEntry(int index, IRandomAccessSource source, long offset) {
  215. this.index = index;
  216. this.source = source;
  217. this.firstByte = offset;
  218. this.lastByte = offset + source.Length - 1;
  219. }
  220. /**
  221. * Given an absolute offset (in the GroupedRandomAccessSource coordinates), calculate the effective offset in the underlying source
  222. * @param absoluteOffset the offset in the parent GroupedRandomAccessSource
  223. * @return the effective offset in the underlying source
  224. */
  225. internal long OffsetN(long absoluteOffset){
  226. return absoluteOffset - firstByte;
  227. }
  228. }
  229. }
  230. }