/// <summary> /// Retrieve an object from the deduplication index. /// This method will use the callbacks supplied in the method signature. /// </summary> /// <param name="objectName">The name of the object.</param> /// <param name="callbacks">CallbackMethods object containing callback methods.</param> /// <param name="contentLength">The length of the data.</param> /// <param name="stream">The stream containing the data.</param> /// <returns>True if successful.</returns> public bool RetrieveObject(string objectName, CallbackMethods callbacks, out long contentLength, out Stream stream) { stream = null; contentLength = 0; if (String.IsNullOrEmpty(objectName)) { throw new ArgumentNullException(nameof(objectName)); } if (callbacks == null) { throw new ArgumentNullException(nameof(callbacks)); } if (callbacks.ReadChunk == null) { throw new ArgumentException("ReadChunk callback must be specified."); } objectName = DedupeCommon.SanitizeString(objectName); ObjectMetadata md = null; lock (_ChunkLock) { if (!_Database.GetObjectMetadata(objectName, out md)) { Log("Unable to retrieve object metadata for object " + objectName); return(false); } if (md.Chunks == null || md.Chunks.Count < 1) { Log("No chunks returned"); return(false); } stream = new MemoryStream(); foreach (Chunk curr in md.Chunks) { byte[] chunkData = callbacks.ReadChunk(curr.Key); if (chunkData == null || chunkData.Length < 1) { Log("Unable to read chunk " + curr.Key); return(false); } stream.Write(chunkData, 0, chunkData.Length); contentLength += chunkData.Length; } if (contentLength > 0) { stream.Seek(0, SeekOrigin.Begin); } } return(true); }
/// <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); } Chunk chunk = null; if (!_Database.GetChunkForPosition(_Metadata.Name, _Position, out chunk)) { return(0); } if (chunk == null) { return(0); } if (chunk.Address > Position) { throw new IOException("Data error while reading chunks from object."); } byte[] chunkData = _Callbacks.ReadChunk(chunk.Key); int chunkDataReadStart = 0; if (chunk.Address < Position) { chunkDataReadStart += (int)(Position - chunk.Address); } int bytesAvailInChunk = (int)(chunk.Length - 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); } }