/// <summary> /// Read data from the stream into the specified buffer and increment the stream position. /// </summary> /// <param name="buffer">Byte array to use as a buffer.</param> /// <param name="offset">The offset within the buffer indicating where to copy the read data.</param> /// <param name="count">The number of bytes to populate within the buffer.</param> /// <returns>An integer representing the number of bytes read.</returns> public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset < 0) { throw new ArgumentOutOfRangeException("Offset must be zero or greater."); } if (count < 0) { throw new ArgumentOutOfRangeException("Count must be zero or greater."); } if ((offset + count) > buffer.Length) { throw new ArgumentOutOfRangeException("Offset and count combined must not exceed buffer length."); } if (offset >= Length) { return(0); } DedupeObjectMap map = _Database.GetObjectMapForPosition(_Metadata.Key, _Position); if (map == null) { return(0); } if (map.ChunkAddress > Position) { throw new IOException("Data error while reading chunks from object."); } byte[] chunkData = _Callbacks.ReadChunk(map.ChunkKey); int chunkDataReadStart = 0; if (map.ChunkAddress < Position) { chunkDataReadStart += (int)(Position - map.ChunkAddress); } int bytesAvailInChunk = (int)(map.ChunkLength - chunkDataReadStart); if (count >= bytesAvailInChunk) { Buffer.BlockCopy(chunkData, chunkDataReadStart, buffer, offset, bytesAvailInChunk); _Position += bytesAvailInChunk; return(bytesAvailInChunk); } else { Buffer.BlockCopy(chunkData, chunkDataReadStart, buffer, offset, count); _Position += count; return(count); } }
/// <summary> /// Retrieve an object from the deduplication index. /// This method will use the callbacks supplied in the method signature. /// </summary> /// <param name="key">The object key.</param> /// <param name="callbacks">CallbackMethods object containing callback methods.</param> /// <returns>Object data.</returns> public DedupeObject Get(string key, DedupeCallbacks callbacks) { if (String.IsNullOrEmpty(key)) { throw new ArgumentNullException(nameof(key)); } if (callbacks == null) { throw new ArgumentNullException(nameof(callbacks)); } if (callbacks.ReadChunk == null) { throw new ArgumentException("ReadChunk callback must be specified."); } key = DedupeCommon.SanitizeString(key); DedupeObject md = _Database.GetObjectMetadata(key); if (md == null) { throw new KeyNotFoundException("Object key '" + key + "' not found."); } if (md.Chunks == null || md.Chunks.Count < 1) { throw new IOException("No chunks returned for object key '" + key + "'."); } MemoryStream stream = new MemoryStream(); long contentLength = 0; foreach (DedupeObjectMap curr in md.ObjectMap) { byte[] chunkData = callbacks.ReadChunk(curr.ChunkKey); if (chunkData == null || chunkData.Length < 1) { throw new IOException("Unable to read chunk '" + curr.ChunkKey + "'."); } stream.Write(chunkData, 0, chunkData.Length); contentLength += chunkData.Length; } if (contentLength > 0) { stream.Seek(0, SeekOrigin.Begin); } md.DataStream = stream; return(md); }