зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1634436 - Add support for seeking (nsISeekableStream). r=dom-workers-and-storage-reviewers,janv
Differential Revision: https://phabricator.services.mozilla.com/D74669
This commit is contained in:
Родитель
de661a3fd7
Коммит
672ce1ce54
|
@ -9,11 +9,24 @@
|
|||
|
||||
namespace mozilla::dom::quota {
|
||||
|
||||
NS_IMPL_ISUPPORTS(DecryptingInputStreamBase, nsIInputStream);
|
||||
NS_IMPL_ADDREF(DecryptingInputStreamBase);
|
||||
NS_IMPL_RELEASE(DecryptingInputStreamBase);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(DecryptingInputStreamBase)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
DecryptingInputStreamBase::DecryptingInputStreamBase(
|
||||
MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream, size_t aBlockSize)
|
||||
: mBaseStream(std::move(aBaseStream)), mBlockSize(aBlockSize) {}
|
||||
: mBaseStream(std::move(aBaseStream)), mBlockSize(aBlockSize) {
|
||||
const nsCOMPtr<nsISeekableStream> seekableStream =
|
||||
do_QueryInterface(mBaseStream->get());
|
||||
MOZ_ASSERT(seekableStream &&
|
||||
SameCOMIdentity(mBaseStream->get(), seekableStream));
|
||||
mBaseSeekableStream.init(WrapNotNullUnchecked(seekableStream));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DecryptingInputStreamBase::Read(char* aBuf, uint32_t aCount,
|
||||
uint32_t* aBytesReadOut) {
|
||||
|
@ -25,6 +38,12 @@ NS_IMETHODIMP DecryptingInputStreamBase::IsNonBlocking(bool* aNonBlockingOut) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP DecryptingInputStreamBase::SetEOF() {
|
||||
// Cannot truncate a read-only stream.
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
size_t DecryptingInputStreamBase::PlainLength() const {
|
||||
MOZ_ASSERT(mNextByte <= mPlainBytes);
|
||||
return mPlainBytes - mNextByte;
|
||||
|
|
|
@ -10,18 +10,22 @@
|
|||
#include "mozilla/InitializedOnce.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
|
||||
#include "EncryptedBlock.h"
|
||||
|
||||
namespace mozilla::dom::quota {
|
||||
|
||||
class DecryptingInputStreamBase : public nsIInputStream {
|
||||
class DecryptingInputStreamBase : public nsIInputStream,
|
||||
public nsISeekableStream {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* _retval) final;
|
||||
NS_IMETHOD IsNonBlocking(bool* _retval) final;
|
||||
|
||||
NS_IMETHOD SetEOF() final;
|
||||
|
||||
protected:
|
||||
DecryptingInputStreamBase(MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream,
|
||||
size_t aBlockSize);
|
||||
|
@ -35,6 +39,7 @@ class DecryptingInputStreamBase : public nsIInputStream {
|
|||
size_t EncryptedBufferLength() const;
|
||||
|
||||
InitializedOnce<const NotNull<nsCOMPtr<nsIInputStream>>> mBaseStream;
|
||||
LazyInitializedOnce<const NotNull<nsISeekableStream*>> mBaseSeekableStream;
|
||||
|
||||
// Number of bytes of plain data in mBuffer.
|
||||
size_t mPlainBytes = 0;
|
||||
|
@ -43,6 +48,8 @@ class DecryptingInputStreamBase : public nsIInputStream {
|
|||
size_t mNextByte = 0;
|
||||
|
||||
const size_t mBlockSize;
|
||||
|
||||
size_t mLastBlockLength = 0;
|
||||
};
|
||||
|
||||
// Wraps another nsIInputStream which contains data written using
|
||||
|
@ -63,6 +70,10 @@ class DecryptingInputStream final : public DecryptingInputStreamBase {
|
|||
NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t* _retval) override;
|
||||
|
||||
NS_DECL_NSITELLABLESTREAM
|
||||
|
||||
NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset) override;
|
||||
|
||||
private:
|
||||
~DecryptingInputStream();
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::ReadSegments(
|
|||
|
||||
if (mNextByte == mPlainBytes) {
|
||||
mNextByte = 0;
|
||||
mLastBlockLength = mPlainBytes;
|
||||
mPlainBytes = 0;
|
||||
}
|
||||
|
||||
|
@ -245,6 +246,167 @@ bool DecryptingInputStream<CipherStrategy>::EnsureBuffers() {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename CipherStrategy>
|
||||
NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Tell(
|
||||
int64_t* const aRetval) {
|
||||
MOZ_ASSERT(aRetval);
|
||||
|
||||
if (!mBaseStream) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
int64_t basePosition;
|
||||
nsresult rv = (*mBaseSeekableStream)->Tell(&basePosition);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
const auto fullBlocks = basePosition / mBlockSize;
|
||||
MOZ_ASSERT(0 == basePosition % mBlockSize);
|
||||
|
||||
*aRetval = (fullBlocks - ((mPlainBytes || mLastBlockLength) ? 1 : 0)) *
|
||||
mEncryptedBlock->MaxPayloadLength() +
|
||||
mNextByte + (mNextByte ? 0 : mLastBlockLength);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template <typename CipherStrategy>
|
||||
NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Seek(const int32_t aWhence,
|
||||
int64_t aOffset) {
|
||||
if (!mBaseStream) {
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
if (!EnsureBuffers()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int64_t baseBlocksOffset;
|
||||
int64_t nextByteOffset;
|
||||
switch (aWhence) {
|
||||
case NS_SEEK_CUR:
|
||||
// XXX Simplify this without using Tell.
|
||||
{
|
||||
int64_t current;
|
||||
nsresult rv = Tell(¤t);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
aOffset += current;
|
||||
}
|
||||
break;
|
||||
case NS_SEEK_SET:
|
||||
break;
|
||||
|
||||
case NS_SEEK_END:
|
||||
// XXX Simplify this without using Seek/Tell.
|
||||
{
|
||||
// XXX The size of the stream could also be queried and stored once
|
||||
// only.
|
||||
nsresult rv = (*mBaseSeekableStream)->Seek(NS_SEEK_SET, 0);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint64_t baseStreamSize;
|
||||
rv = (*mBaseStream)->Available(&baseStreamSize);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
auto decryptedStreamSizeOrErr = [baseStreamSize,
|
||||
this]() -> Result<int64_t, nsresult> {
|
||||
if (!baseStreamSize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
(*mBaseSeekableStream)
|
||||
->Seek(NS_SEEK_END, -static_cast<int64_t>(mBlockSize));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return Err(rv);
|
||||
}
|
||||
|
||||
uint32_t bytesRead;
|
||||
rv = ParseNextChunk(&bytesRead);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return Err(rv);
|
||||
}
|
||||
MOZ_ASSERT(bytesRead);
|
||||
|
||||
// XXX Shouldn't ParseNextChunk better update mPlainBytes?
|
||||
mPlainBytes = bytesRead;
|
||||
|
||||
mNextByte = bytesRead;
|
||||
|
||||
int64_t current;
|
||||
rv = Tell(¤t);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return Err(rv);
|
||||
}
|
||||
|
||||
return current;
|
||||
}();
|
||||
|
||||
if (decryptedStreamSizeOrErr.isErr()) {
|
||||
return decryptedStreamSizeOrErr.unwrapErr();
|
||||
}
|
||||
|
||||
aOffset += decryptedStreamSizeOrErr.unwrap();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
baseBlocksOffset = aOffset / mEncryptedBlock->MaxPayloadLength();
|
||||
nextByteOffset = aOffset % mEncryptedBlock->MaxPayloadLength();
|
||||
|
||||
// XXX If we remain in the same block as before, we can skip this.
|
||||
nsresult rv =
|
||||
(*mBaseSeekableStream)->Seek(NS_SEEK_SET, baseBlocksOffset * mBlockSize);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mNextByte = 0;
|
||||
mPlainBytes = 0;
|
||||
|
||||
uint32_t readBytes;
|
||||
rv = ParseNextChunk(&readBytes);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// XXX Do we need to do more here? Restore any previous state?
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We positioned after the last block, we must read that to know its size.
|
||||
// XXX We could know earlier if we positioned us after the last block.
|
||||
if (!readBytes) {
|
||||
if (baseBlocksOffset == 0) {
|
||||
// The stream is empty.
|
||||
return aOffset == 0 ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
nsresult rv = (*mBaseSeekableStream)->Seek(NS_SEEK_CUR, -mBlockSize);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = ParseNextChunk(&readBytes);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// XXX Do we need to do more here? Restore any previous state?
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
mPlainBytes = readBytes;
|
||||
mNextByte = nextByteOffset;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom::quota
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,12 +24,14 @@ namespace mozilla::dom::quota {
|
|||
// Similar to ArrayBufferInputStream from netwerk/base/ArrayBufferInputStream.h,
|
||||
// but this is initialized from a Span on construction, rather than lazily from
|
||||
// a JS ArrayBuffer.
|
||||
class ArrayBufferInputStream : public nsIInputStream {
|
||||
class ArrayBufferInputStream : public nsIInputStream, public nsISeekableStream {
|
||||
public:
|
||||
explicit ArrayBufferInputStream(mozilla::Span<const uint8_t> aData);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSITELLABLESTREAM
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
|
||||
private:
|
||||
virtual ~ArrayBufferInputStream() = default;
|
||||
|
@ -40,7 +42,14 @@ class ArrayBufferInputStream : public nsIInputStream {
|
|||
bool mClosed;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIInputStream);
|
||||
NS_IMPL_ADDREF(ArrayBufferInputStream);
|
||||
NS_IMPL_RELEASE(ArrayBufferInputStream);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(ArrayBufferInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
ArrayBufferInputStream::ArrayBufferInputStream(
|
||||
mozilla::Span<const uint8_t> aData)
|
||||
|
@ -127,6 +136,47 @@ ArrayBufferInputStream::IsNonBlocking(bool* aNonBlocking) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ArrayBufferInputStream::Tell(int64_t* const aRetval) {
|
||||
MOZ_ASSERT(aRetval);
|
||||
|
||||
*aRetval = mPos;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ArrayBufferInputStream::Seek(const int32_t aWhence,
|
||||
const int64_t aOffset) {
|
||||
// XXX This is not safe. it's hard to use CheckedInt here, though. As long as
|
||||
// the class is only used for testing purposes, that's probably fine.
|
||||
|
||||
int32_t newPos = mPos;
|
||||
switch (aWhence) {
|
||||
case NS_SEEK_SET:
|
||||
newPos = aOffset;
|
||||
break;
|
||||
case NS_SEEK_CUR:
|
||||
newPos += aOffset;
|
||||
break;
|
||||
case NS_SEEK_END:
|
||||
newPos = mBufferLength;
|
||||
newPos += aOffset;
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
if (newPos < 0 || static_cast<uint32_t>(newPos) > mBufferLength) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
mPos = newPos;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ArrayBufferInputStream::SetEOF() {
|
||||
// Truncating is not supported on a read-only stream.
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom::quota
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -273,6 +323,12 @@ static void ReadTestData(
|
|||
EXPECT_EQ(currentExpected.Length(), read);
|
||||
EXPECT_EQ(currentExpected,
|
||||
Span{readData}.First(currentExpected.Length()).AsConst());
|
||||
|
||||
// Check that Tell tells the right position.
|
||||
int64_t pos;
|
||||
EXPECT_EQ(NS_OK, inStream->Tell(&pos));
|
||||
EXPECT_EQ(aExpectedData.Length() - remainder.Length(),
|
||||
static_cast<uint64_t>(pos));
|
||||
}
|
||||
|
||||
// Expect EOF.
|
||||
|
@ -383,6 +439,147 @@ TEST_P(ParametrizedCryptTest, DummyCipherStrategy_IncompleteBlock) {
|
|||
readData.Length(), &read));
|
||||
}
|
||||
|
||||
enum struct SeekOffset {
|
||||
Zero,
|
||||
MinusHalfDataSize,
|
||||
PlusHalfDataSize,
|
||||
PlusDataSize,
|
||||
MinusDataSize
|
||||
};
|
||||
using SeekOp = std::pair<int32_t, SeekOffset>;
|
||||
|
||||
using PackedSeekTestParams = std::tuple<size_t, size_t, std::vector<SeekOp>>;
|
||||
|
||||
struct SeekTestParams {
|
||||
size_t mDataSize;
|
||||
size_t mBlockSize;
|
||||
std::vector<SeekOp> mSeekOps;
|
||||
|
||||
MOZ_IMPLICIT SeekTestParams(const PackedSeekTestParams& aPackedParams)
|
||||
: mDataSize(std::get<0>(aPackedParams)),
|
||||
mBlockSize(std::get<1>(aPackedParams)),
|
||||
mSeekOps(std::get<2>(aPackedParams)) {}
|
||||
};
|
||||
|
||||
std::string SeekTestParamToString(
|
||||
const testing::TestParamInfo<PackedSeekTestParams>& aTestParams) {
|
||||
const SeekTestParams& testParams = aTestParams.param;
|
||||
|
||||
static constexpr char kSeparator[] = "_";
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "data" << testParams.mDataSize << kSeparator << "writechunk"
|
||||
<< testParams.mBlockSize << kSeparator;
|
||||
for (const auto& seekOp : testParams.mSeekOps) {
|
||||
switch (seekOp.first) {
|
||||
case nsISeekableStream::NS_SEEK_SET:
|
||||
ss << "Set";
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_CUR:
|
||||
ss << "Cur";
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_END:
|
||||
ss << "End";
|
||||
break;
|
||||
};
|
||||
switch (seekOp.second) {
|
||||
case SeekOffset::Zero:
|
||||
ss << "Zero";
|
||||
break;
|
||||
case SeekOffset::MinusHalfDataSize:
|
||||
ss << "MinusHalfDataSize";
|
||||
break;
|
||||
case SeekOffset::PlusHalfDataSize:
|
||||
ss << "PlusHalfDataSize";
|
||||
break;
|
||||
case SeekOffset::MinusDataSize:
|
||||
ss << "MinusDataSize";
|
||||
break;
|
||||
case SeekOffset::PlusDataSize:
|
||||
ss << "PlusDataSize";
|
||||
break;
|
||||
};
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
class ParametrizedSeekCryptTest
|
||||
: public DOM_Quota_EncryptedStream,
|
||||
public testing::WithParamInterface<PackedSeekTestParams> {};
|
||||
|
||||
TEST_P(ParametrizedSeekCryptTest, DummyCipherStrategy_Seek) {
|
||||
using CipherStrategy = DummyCipherStrategy;
|
||||
const CipherStrategy cipherStrategy;
|
||||
const SeekTestParams& testParams = GetParam();
|
||||
|
||||
const auto baseOutputStream =
|
||||
WrapNotNull(RefPtr<dom::quota::MemoryOutputStream>{
|
||||
dom::quota::MemoryOutputStream::Create(2048)});
|
||||
|
||||
const auto data = MakeTestData(testParams.mDataSize);
|
||||
|
||||
WriteTestData(nsCOMPtr<nsIOutputStream>{baseOutputStream.get()}, Span{data},
|
||||
testParams.mDataSize, testParams.mBlockSize, cipherStrategy,
|
||||
CipherStrategy::KeyType{}, FlushMode::Never);
|
||||
|
||||
const auto baseInputStream =
|
||||
MakeRefPtr<ArrayBufferInputStream>(baseOutputStream->Data());
|
||||
|
||||
const auto inStream = MakeSafeRefPtr<DecryptingInputStream<CipherStrategy>>(
|
||||
WrapNotNull(nsCOMPtr<nsIInputStream>{baseInputStream}),
|
||||
testParams.mBlockSize, cipherStrategy, CipherStrategy::KeyType{});
|
||||
|
||||
uint32_t accumulatedOffset = 0;
|
||||
for (const auto& seekOp : testParams.mSeekOps) {
|
||||
const auto offset = [offsetKind = seekOp.second,
|
||||
dataSize = testParams.mDataSize]() -> int64_t {
|
||||
switch (offsetKind) {
|
||||
case SeekOffset::Zero:
|
||||
return 0;
|
||||
case SeekOffset::MinusHalfDataSize:
|
||||
return -static_cast<int64_t>(dataSize) / 2;
|
||||
case SeekOffset::PlusHalfDataSize:
|
||||
return dataSize / 2;
|
||||
case SeekOffset::MinusDataSize:
|
||||
return -static_cast<int64_t>(dataSize);
|
||||
case SeekOffset::PlusDataSize:
|
||||
return dataSize;
|
||||
}
|
||||
MOZ_CRASH("Unknown SeekOffset");
|
||||
}();
|
||||
switch (seekOp.first) {
|
||||
case nsISeekableStream::NS_SEEK_SET:
|
||||
accumulatedOffset = offset;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_CUR:
|
||||
accumulatedOffset += offset;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_END:
|
||||
accumulatedOffset = testParams.mDataSize + offset;
|
||||
break;
|
||||
}
|
||||
EXPECT_EQ(NS_OK, inStream->Seek(seekOp.first, offset));
|
||||
}
|
||||
|
||||
{
|
||||
int64_t actualOffset;
|
||||
EXPECT_EQ(NS_OK, inStream->Tell(&actualOffset));
|
||||
|
||||
EXPECT_EQ(actualOffset, accumulatedOffset);
|
||||
}
|
||||
|
||||
auto readData = nsTArray<uint8_t>();
|
||||
readData.SetLength(data.Length());
|
||||
uint32_t read;
|
||||
EXPECT_EQ(NS_OK, inStream->Read(reinterpret_cast<char*>(readData.Elements()),
|
||||
readData.Length(), &read));
|
||||
// XXX Or should 'read' indicate the actual number of bytes read,
|
||||
// including the encryption overhead?
|
||||
EXPECT_EQ(testParams.mDataSize - accumulatedOffset, read);
|
||||
EXPECT_EQ(Span{data}.SplitAt(accumulatedOffset).second,
|
||||
Span{readData}.First(read).AsConst());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
DOM_Quota_EncryptedStream_Parametrized, ParametrizedCryptTest,
|
||||
testing::Combine(
|
||||
|
@ -397,3 +594,35 @@ INSTANTIATE_TEST_CASE_P(
|
|||
/* flushMode */
|
||||
testing::Values(FlushMode::Never, FlushMode::AfterEachChunk)),
|
||||
TestParamToString);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
DOM_IndexedDB_EncryptedStream_ParametrizedSeek, ParametrizedSeekCryptTest,
|
||||
testing::Combine(
|
||||
/* dataSize */ testing::Values(0u, 16u, 256u, 512u, 513u),
|
||||
/* blockSize */ testing::Values(256u, 1024u /*, 8192u*/),
|
||||
/* seekOperations */
|
||||
testing::Values(/* NS_SEEK_SET only, single ops */
|
||||
std::vector<SeekOp>{{nsISeekableStream::NS_SEEK_SET,
|
||||
SeekOffset::PlusDataSize}},
|
||||
std::vector<SeekOp>{{nsISeekableStream::NS_SEEK_SET,
|
||||
SeekOffset::PlusHalfDataSize}},
|
||||
/* NS_SEEK_SET only, multiple ops */
|
||||
std::vector<SeekOp>{
|
||||
{nsISeekableStream::NS_SEEK_SET,
|
||||
SeekOffset::PlusHalfDataSize},
|
||||
{nsISeekableStream::NS_SEEK_SET, SeekOffset::Zero}},
|
||||
/* NS_SEEK_CUR only, single ops */
|
||||
std::vector<SeekOp>{
|
||||
{nsISeekableStream::NS_SEEK_CUR, SeekOffset::Zero}},
|
||||
std::vector<SeekOp>{{nsISeekableStream::NS_SEEK_CUR,
|
||||
SeekOffset::PlusDataSize}},
|
||||
std::vector<SeekOp>{{nsISeekableStream::NS_SEEK_CUR,
|
||||
SeekOffset::PlusHalfDataSize}},
|
||||
/* NS_SEEK_END only, single ops */
|
||||
std::vector<SeekOp>{
|
||||
{nsISeekableStream::NS_SEEK_END, SeekOffset::Zero}},
|
||||
std::vector<SeekOp>{{nsISeekableStream::NS_SEEK_END,
|
||||
SeekOffset::MinusDataSize}},
|
||||
std::vector<SeekOp>{{nsISeekableStream::NS_SEEK_END,
|
||||
SeekOffset::MinusHalfDataSize}})),
|
||||
SeekTestParamToString);
|
||||
|
|
Загрузка…
Ссылка в новой задаче