#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2013 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License // If the library is compiled as a DLL, this ensures symbols are exported #define NUCLEX_STORAGE_SOURCE 1 #include "BlobLookInStream.h" // Somehow Windows.h seems to get included at this point. #undef min #undef max #include namespace Nuclex { namespace Storage { namespace FileSystem { namespace SevenZip { // ------------------------------------------------------------------------------------------- // BlobLookInStream::BlobLookInStream(const std::shared_ptr &blob) : blob(blob), location(0), length(blob->GetSize()) { Look = &BlobLookInStream::look; Skip = &BlobLookInStream::skip; Read = &BlobLookInStream::read; Seek = &BlobLookInStream::seek; } // ------------------------------------------------------------------------------------------- // SRes BlobLookInStream::look(void *self, const void **buffer, size_t *length) { BlobLookInStream *blobLookInStream = static_cast(self); size_t localLength = *length; std::uint64_t remaining = blobLookInStream->length - blobLookInStream->location; if(localLength > remaining) { localLength = remaining; } if(localLength > 0) { try { blobLookInStream->buffer.resize(localLength); blobLookInStream->blob->ReadAt( blobLookInStream->location, &blobLookInStream->buffer[0], localLength ); } catch(const std::exception &) { return SZ_ERROR_FAIL; } } *buffer = static_cast(&blobLookInStream->buffer[0]); *length = localLength; return SZ_OK; } // ------------------------------------------------------------------------------------------- // SRes BlobLookInStream::skip(void *self, size_t offset) { BlobLookInStream *blobLookInStream = static_cast(self); std::uint64_t remaining = blobLookInStream->length - blobLookInStream->location; if(offset < remaining) { blobLookInStream->location += offset; } else { blobLookInStream->location = blobLookInStream->length; } return SZ_OK; } // ------------------------------------------------------------------------------------------- // SRes BlobLookInStream::read(void *self, void *buffer, size_t *length) { BlobLookInStream *blobLookInStream = static_cast(self); size_t localLength = *length; std::uint64_t remaining = blobLookInStream->length - blobLookInStream->location; if(localLength > remaining) { localLength = static_cast(localLength); *length = localLength; } if(localLength > 0) { try { blobLookInStream->blob->ReadAt(blobLookInStream->location, buffer, localLength); blobLookInStream->location += localLength; } catch(const std::exception &) { return SZ_ERROR_FAIL; } } return SZ_OK; } // ------------------------------------------------------------------------------------------- // SRes BlobLookInStream::seek(void *self, Int64 *position, ESzSeek origin) { BlobLookInStream *blobLookInStream = static_cast(self); // Why do does Nuclex.Storage.Native not work with file pointers and not implement // a seek() method? Here's why: std::int64_t localPosition = *position; switch(origin) { // Seek to absolute position case SZ_SEEK_SET: { if(localPosition < 0) { // Negative positions are impossible blobLookInStream->location = 0; } else { // Limit position to blob length blobLookInStream->location = std::min( blobLookInStream->length, static_cast(localPosition) ); } break; } // Seek relative to current position case SZ_SEEK_CUR: { if(localPosition < 0) { // Negative offsets clip to 0 if(static_cast(-localPosition) > blobLookInStream->location) { blobLookInStream->location = 0; // Went before the beginning } else { blobLookInStream->location += localPosition; // Still within the blob } } else { // Positive offsets clip at blob length std::uint64_t remaining = blobLookInStream->length - blobLookInStream->location; if(static_cast(localPosition) > remaining) { blobLookInStream->location = blobLookInStream->length; // Went past the end } else { blobLookInStream->location += localPosition; // Still within the blob } } break; } // Seek relative to end of blob case SZ_SEEK_END: { if(localPosition < 0) { // Only negative offsets can be within the blob if(static_cast(-localPosition) > blobLookInStream->length) { blobLookInStream->location = 0; // Went past beginning } else { // Still within the blob blobLookInStream->location = blobLookInStream->length + localPosition; } } else { blobLookInStream->location = blobLookInStream->length; // Went past the end } break; } // Unknown seek mode default: { return SZ_ERROR_PARAM; } } // Validity check (only affects blobs with a size of >8 EiB...) const std::uint64_t int64Max = static_cast( std::numeric_limits::max() ); if(blobLookInStream->location > int64Max) { return SZ_ERROR_PARAM; // Position beyond signed 64 integer limit } *position = static_cast(blobLookInStream->location); return SZ_OK; } // ------------------------------------------------------------------------------------------- // }}}} // namespace Nuclex::Storage::FileSystem::SevenZip