/// <summary><inheritDoc/></summary> public virtual int Get(long position, byte[] bytes, int off, int len) { GroupedRandomAccessSource.SourceEntry entry = GetSourceEntryForOffset(position); // if true, we have run out of data to read from if (entry == null) { return(-1); } long offN = entry.OffsetN(position); int remaining = len; while (remaining > 0) { // if true, we have run out of data to read from if (entry == null) { break; } if (offN > entry.source.Length()) { break; } int count = entry.source.Get(offN, bytes, off, remaining); if (count == -1) { break; } off += count; position += count; remaining -= count; offN = 0; entry = GetSourceEntryForOffset(position); } return(remaining == len ? -1 : len - remaining); }
/// <summary> /// Returns the SourceEntry that contains the byte at the specified offset /// sourceReleased is called as a notification callback so subclasses can take care of cleanup /// when the source is no longer the active source /// </summary> /// <param name="offset">the offset of the byte to look for</param> /// <returns>the SourceEntry that contains the byte at the specified offset</returns> private GroupedRandomAccessSource.SourceEntry GetSourceEntryForOffset(long offset) { if (offset >= size) { return(null); } if (offset >= currentSourceEntry.firstByte && offset <= currentSourceEntry.lastByte) { return(currentSourceEntry); } // hook to allow subclasses to release resources if necessary SourceReleased(currentSourceEntry.source); int startAt = GetStartingSourceIndex(offset); for (int i = startAt; i < sources.Length; i++) { if (offset >= sources[i].firstByte && offset <= sources[i].lastByte) { currentSourceEntry = sources[i]; SourceInUse(currentSourceEntry.source); return(currentSourceEntry); } } return(null); }
// by default, do nothing /// <summary> /// <inheritDoc/> /// The source that contains the byte at position is retrieved, the correct offset into that source computed, then the value /// from that offset in the underlying source is returned. /// </summary> public virtual int Get(long position) { GroupedRandomAccessSource.SourceEntry entry = GetSourceEntryForOffset(position); // if true, we have run out of data to read from if (entry == null) { return(-1); } return(entry.source.Get(entry.OffsetN(position))); }
/// <summary> /// Constructs a new /// <see cref="GroupedRandomAccessSource"/> /// based on the specified set of sources /// </summary> /// <param name="sources">the sources used to build this group</param> public GroupedRandomAccessSource(IRandomAccessSource[] sources) { this.sources = new GroupedRandomAccessSource.SourceEntry[sources.Length]; long totalSize = 0; for (int i = 0; i < sources.Length; i++) { this.sources[i] = new GroupedRandomAccessSource.SourceEntry(i, sources[i], totalSize); totalSize += sources[i].Length(); } size = totalSize; currentSourceEntry = this.sources[sources.Length - 1]; SourceInUse(currentSourceEntry.source); }