Explicitly allow IFX_WriteStream::WriteBlock() calls with size of 0.
Make it clear that the interface allows this. Fix implementations to be
consistent with the interface, and remove a few checks that skipped
WriteBlock() calls because the size is 0.
At a test case to make sure CFX_MemoryStream::WriteBlock() works as
expected.
Also consistently not return false in WriteBlock() implementation when
the data pointer is null.
Change-Id: I4962f56b66c31c53339feb120f5a33d440fa72d7
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/98090
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_creator.cpp b/core/fpdfapi/edit/cpdf_creator.cpp
index c7f7424..76c9e93 100644
--- a/core/fpdfapi/edit/cpdf_creator.cpp
+++ b/core/fpdfapi/edit/cpdf_creator.cpp
@@ -74,9 +74,10 @@
}
bool CFX_FileBufferArchive::WriteBlock(const void* pBuf, size_t size) {
- DCHECK(pBuf);
- DCHECK(size > 0);
+ if (size == 0)
+ return true;
+ DCHECK(pBuf);
auto* pSrc = reinterpret_cast<const uint8_t*>(pBuf);
pdfium::span<const uint8_t> src_span(pSrc, size);
while (!src_span.empty()) {
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp
index 96cc237..674f0ba 100644
--- a/core/fpdfapi/parser/cpdf_stream.cpp
+++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -212,7 +212,7 @@
if (!archive->WriteString("stream\r\n"))
return false;
- if (size && !archive->WriteBlock(data.data(), size))
+ if (!archive->WriteBlock(data.data(), size))
return false;
if (!archive->WriteString("\r\nendstream"))
diff --git a/core/fxcrt/cfx_memorystream.cpp b/core/fxcrt/cfx_memorystream.cpp
index 5ca97ed..4361fdb 100644
--- a/core/fxcrt/cfx_memorystream.cpp
+++ b/core/fxcrt/cfx_memorystream.cpp
@@ -64,9 +64,13 @@
bool CFX_MemoryStream::WriteBlockAtOffset(const void* buffer,
FX_FILESIZE offset,
size_t size) {
- if (!buffer || offset < 0 || !size)
+ if (offset < 0)
return false;
+ if (size == 0)
+ return true;
+
+ DCHECK(buffer);
FX_SAFE_SIZE_T safe_new_pos = size;
safe_new_pos += offset;
if (!safe_new_pos.IsValid())
diff --git a/core/fxcrt/cfx_memorystream_unittest.cpp b/core/fxcrt/cfx_memorystream_unittest.cpp
index da71e27..716e47b 100644
--- a/core/fxcrt/cfx_memorystream_unittest.cpp
+++ b/core/fxcrt/cfx_memorystream_unittest.cpp
@@ -48,3 +48,20 @@
ASSERT_TRUE(stream->ReadBlockAtOffset(buffer, 2, sizeof(buffer)));
ASSERT_THAT(buffer, testing::ElementsAre('c', '\0', '\0', 'a'));
}
+
+TEST(CFXMemoryStreamTest, WriteZeroBytes) {
+ auto stream = pdfium::MakeRetain<CFX_MemoryStream>();
+ const uint8_t kData1[] = {'a', 'b', 'c'};
+ ASSERT_TRUE(stream->WriteBlock(kData1, sizeof(kData1)));
+ auto stream_contents =
+ pdfium::make_span(stream->GetBuffer(), stream->GetSize());
+ ASSERT_THAT(stream_contents, testing::ElementsAre('a', 'b', 'c'));
+
+ ASSERT_TRUE(stream->WriteBlock(kData1, 0));
+ stream_contents = pdfium::make_span(stream->GetBuffer(), stream->GetSize());
+ ASSERT_THAT(stream_contents, testing::ElementsAre('a', 'b', 'c'));
+
+ ASSERT_TRUE(stream->WriteBlock(nullptr, 0));
+ stream_contents = pdfium::make_span(stream->GetBuffer(), stream->GetSize());
+ ASSERT_THAT(stream_contents, testing::ElementsAre('a', 'b', 'c'));
+}
diff --git a/core/fxcrt/fx_stream.h b/core/fxcrt/fx_stream.h
index f82b264..0154b978 100644
--- a/core/fxcrt/fx_stream.h
+++ b/core/fxcrt/fx_stream.h
@@ -16,6 +16,8 @@
class IFX_WriteStream {
public:
+ // When `size` is 0, treat it as a no-op and return true. That is also the
+ // only time when `pData` can be null.
virtual bool WriteBlock(const void* pData, size_t size) = 0;
bool WriteString(ByteStringView str);
diff --git a/fpdfsdk/fpdf_ppo_embeddertest.cpp b/fpdfsdk/fpdf_ppo_embeddertest.cpp
index ee776ba..8c518cc 100644
--- a/fpdfsdk/fpdf_ppo_embeddertest.cpp
+++ b/fpdfsdk/fpdf_ppo_embeddertest.cpp
@@ -24,7 +24,7 @@
int FakeBlockWriter(FPDF_FILEWRITE* pThis,
const void* pData,
unsigned long size) {
- return size;
+ return 1; // Always succeeds.
}
constexpr int kRectanglesMultiPagesPageCount = 2;