summaryrefslogtreecommitdiff
path: root/core/fpdfapi/edit
diff options
context:
space:
mode:
authorDan Sinclair <dsinclair@chromium.org>2017-05-09 12:36:08 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-05-09 17:48:44 +0000
commita0b1954794b7a8a279ba00787628cc7f8d1419d9 (patch)
tree4556b78b9550dbb80baa52e0eee016395f223c4e /core/fpdfapi/edit
parente02b2bc896b0872ce1a9d0997946b07dc76b9f7b (diff)
downloadpdfium-a0b1954794b7a8a279ba00787628cc7f8d1419d9.tar.xz
Rename fpdf_edit_create.cpp to cpdf_creator.cpp
This Cl renames the fpdf_edit_create file to better match the cpdf_creator content. The CPDF_ObjectStream and CPDF_XRefStream code is moved out to their own .cpp files. Needed anonymous classes are split out as well. Change-Id: Ic83fb319ce28c816db82a4286e22032dc68811bc Reviewed-on: https://pdfium-review.googlesource.com/5171 Commit-Queue: dsinclair <dsinclair@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org> Reviewed-by: Nicolás Peña <npm@chromium.org>
Diffstat (limited to 'core/fpdfapi/edit')
-rw-r--r--core/fpdfapi/edit/cpdf_creator.cpp (renamed from core/fpdfapi/edit/fpdf_edit_create.cpp)668
-rw-r--r--core/fpdfapi/edit/cpdf_encryptor.cpp32
-rw-r--r--core/fpdfapi/edit/cpdf_encryptor.h31
-rw-r--r--core/fpdfapi/edit/cpdf_flateencoder.cpp77
-rw-r--r--core/fpdfapi/edit/cpdf_flateencoder.h41
-rw-r--r--core/fpdfapi/edit/cpdf_objectstream.cpp109
-rw-r--r--core/fpdfapi/edit/cpdf_objectstream.h13
-rw-r--r--core/fpdfapi/edit/cpdf_xrefstream.cpp412
-rw-r--r--core/fpdfapi/edit/cpdf_xrefstream.h20
9 files changed, 758 insertions, 645 deletions
diff --git a/core/fpdfapi/edit/fpdf_edit_create.cpp b/core/fpdfapi/edit/cpdf_creator.cpp
index 42fe13d4e9..32dd28456e 100644
--- a/core/fpdfapi/edit/fpdf_edit_create.cpp
+++ b/core/fpdfapi/edit/cpdf_creator.cpp
@@ -4,134 +4,25 @@
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-#include <memory>
-#include <vector>
-
#include "core/fpdfapi/edit/cpdf_creator.h"
+
+#include "core/fpdfapi/edit/cpdf_encryptor.h"
+#include "core/fpdfapi/edit/cpdf_flateencoder.h"
#include "core/fpdfapi/edit/cpdf_objectstream.h"
#include "core/fpdfapi/edit/cpdf_xrefstream.h"
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_crypto_handler.h"
-#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_document.h"
-#include "core/fpdfapi/parser/cpdf_name.h"
#include "core/fpdfapi/parser/cpdf_number.h"
#include "core/fpdfapi/parser/cpdf_parser.h"
-#include "core/fpdfapi/parser/cpdf_reference.h"
#include "core/fpdfapi/parser/cpdf_security_handler.h"
-#include "core/fpdfapi/parser/cpdf_stream.h"
-#include "core/fpdfapi/parser/cpdf_stream_acc.h"
#include "core/fpdfapi/parser/cpdf_string.h"
#include "core/fpdfapi/parser/fpdf_parser_decode.h"
-#include "core/fpdfapi/parser/fpdf_parser_utility.h"
-#include "core/fxcrt/cfx_maybe_owned.h"
#include "core/fxcrt/fx_extension.h"
-#include "third_party/base/numerics/safe_math.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
namespace {
const uint32_t kXRefStreamMaxSize = 10000;
-const int kObjectStreamMaxLength = 256 * 1024;
-
-int32_t WriteTrailer(CPDF_Document* pDocument,
- CFX_FileBufferArchive* pFile,
- CPDF_Array* pIDArray) {
- FX_FILESIZE offset = 0;
- int32_t len = 0;
- CPDF_Parser* pParser = pDocument->GetParser();
- if (pParser) {
- CPDF_Dictionary* p = pParser->GetTrailer();
- for (const auto& it : *p) {
- const CFX_ByteString& key = it.first;
- CPDF_Object* pValue = it.second.get();
- if (key == "Encrypt" || key == "Size" || key == "Filter" ||
- key == "Index" || key == "Length" || key == "Prev" || key == "W" ||
- key == "XRefStm" || key == "Type" || key == "ID") {
- continue;
- }
- if (key == "DecodeParms")
- continue;
- if (pFile->AppendString(("/")) < 0)
- return -1;
- if ((len = pFile->AppendString(PDF_NameEncode(key).AsStringC())) < 0)
- return -1;
-
- offset += len + 1;
- if (!pValue->IsInline()) {
- if (pFile->AppendString(" ") < 0)
- return -1;
- if ((len = pFile->AppendDWord(pValue->GetObjNum())) < 0)
- return -1;
- if (pFile->AppendString(" 0 R ") < 0)
- return -1;
-
- offset += len + 6;
- } else {
- if (!pValue->WriteTo(pFile, &offset))
- return -1;
- }
- }
- if (pIDArray) {
- if (pFile->AppendString(("/ID")) < 0)
- return -1;
-
- offset += 3;
- if (!pIDArray->WriteTo(pFile, &offset))
- return -1;
- }
- return offset;
- }
- if (pFile->AppendString("\r\n/Root ") < 0)
- return -1;
- if ((len = pFile->AppendDWord(pDocument->GetRoot()->GetObjNum())) < 0)
- return -1;
- if (pFile->AppendString(" 0 R\r\n") < 0)
- return -1;
-
- offset += len + 14;
- if (pDocument->GetInfo()) {
- if (pFile->AppendString("/Info ") < 0)
- return -1;
- if ((len = pFile->AppendDWord(pDocument->GetInfo()->GetObjNum())) < 0)
- return -1;
- if (pFile->AppendString(" 0 R\r\n") < 0)
- return -1;
-
- offset += len + 12;
- }
- if (pIDArray) {
- if (pFile->AppendString(("/ID")) < 0)
- return -1;
-
- offset += 3;
- if (!pIDArray->WriteTo(pFile, &offset))
- return -1;
- }
- return offset;
-}
-
-int32_t WriteEncryptDictObjectReference(uint32_t dwObjNum,
- CFX_FileBufferArchive* pFile) {
- ASSERT(pFile);
-
- FX_FILESIZE offset = 0;
- int32_t len = 0;
- if (pFile->AppendString("/Encrypt") < 0)
- return -1;
-
- offset += 8;
- if (pFile->AppendString(" ") < 0)
- return -1;
- if ((len = pFile->AppendDWord(dwObjNum)) < 0)
- return -1;
- if (pFile->AppendString(" 0 R ") < 0)
- return -1;
-
- offset += len + 6;
- return offset;
-}
std::vector<uint8_t> GenerateFileID(uint32_t dwSeed1, uint32_t dwSeed2) {
std::vector<uint8_t> buffer(sizeof(uint32_t) * 4);
@@ -149,38 +40,6 @@ std::vector<uint8_t> GenerateFileID(uint32_t dwSeed1, uint32_t dwSeed2) {
return buffer;
}
-void AppendIndex0(CFX_ByteTextBuf& buffer, bool bFirstObject) {
- buffer.AppendByte(0);
- buffer.AppendByte(0);
- buffer.AppendByte(0);
- buffer.AppendByte(0);
- buffer.AppendByte(0);
-
- const uint8_t byte = bFirstObject ? 0xFF : 0;
- buffer.AppendByte(byte);
- buffer.AppendByte(byte);
-}
-
-void AppendIndex1(CFX_ByteTextBuf& buffer, FX_FILESIZE offset) {
- buffer.AppendByte(1);
- buffer.AppendByte(static_cast<uint8_t>(offset >> 24));
- buffer.AppendByte(static_cast<uint8_t>(offset >> 16));
- buffer.AppendByte(static_cast<uint8_t>(offset >> 8));
- buffer.AppendByte(static_cast<uint8_t>(offset));
- buffer.AppendByte(0);
- buffer.AppendByte(0);
-}
-
-void AppendIndex2(CFX_ByteTextBuf& buffer, uint32_t objnum, int32_t index) {
- buffer.AppendByte(2);
- buffer.AppendByte(static_cast<uint8_t>(objnum >> 24));
- buffer.AppendByte(static_cast<uint8_t>(objnum >> 16));
- buffer.AppendByte(static_cast<uint8_t>(objnum >> 8));
- buffer.AppendByte(static_cast<uint8_t>(objnum));
- buffer.AppendByte(static_cast<uint8_t>(index >> 8));
- buffer.AppendByte(static_cast<uint8_t>(index));
-}
-
int32_t OutputIndex(CFX_FileBufferArchive* pFile, FX_FILESIZE offset) {
if (pFile->AppendByte(static_cast<uint8_t>(offset >> 24)) < 0)
return -1;
@@ -195,474 +54,8 @@ int32_t OutputIndex(CFX_FileBufferArchive* pFile, FX_FILESIZE offset) {
return 0;
}
-class CPDF_FlateEncoder {
- public:
- CPDF_FlateEncoder(CPDF_Stream* pStream, bool bFlateEncode);
- CPDF_FlateEncoder(const uint8_t* pBuffer,
- uint32_t size,
- bool bFlateEncode,
- bool bXRefStream);
- ~CPDF_FlateEncoder();
-
- void CloneDict();
-
- uint32_t m_dwSize;
- CFX_MaybeOwned<uint8_t, FxFreeDeleter> m_pData;
- CFX_MaybeOwned<CPDF_Dictionary> m_pDict;
- CFX_RetainPtr<CPDF_StreamAcc> m_pAcc;
-};
-
-CPDF_FlateEncoder::CPDF_FlateEncoder(CPDF_Stream* pStream, bool bFlateEncode)
- : m_dwSize(0), m_pAcc(pdfium::MakeRetain<CPDF_StreamAcc>(pStream)) {
- m_pAcc->LoadAllData(true);
- bool bHasFilter = pStream && pStream->HasFilter();
- if (bHasFilter && !bFlateEncode) {
- auto pDestAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
- pDestAcc->LoadAllData();
- m_dwSize = pDestAcc->GetSize();
- m_pData = pDestAcc->DetachData();
- m_pDict = ToDictionary(pStream->GetDict()->Clone());
- m_pDict->RemoveFor("Filter");
- return;
- }
- if (bHasFilter || !bFlateEncode) {
- m_pData = const_cast<uint8_t*>(m_pAcc->GetData());
- m_dwSize = m_pAcc->GetSize();
- m_pDict = pStream->GetDict();
- return;
- }
- // TODO(thestig): Move to Init() and check return value.
- uint8_t* buffer = nullptr;
- ::FlateEncode(m_pAcc->GetData(), m_pAcc->GetSize(), &buffer, &m_dwSize);
- m_pData = std::unique_ptr<uint8_t, FxFreeDeleter>(buffer);
- m_pDict = ToDictionary(pStream->GetDict()->Clone());
- m_pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(m_dwSize));
- m_pDict->SetNewFor<CPDF_Name>("Filter", "FlateDecode");
- m_pDict->RemoveFor("DecodeParms");
-}
-
-CPDF_FlateEncoder::CPDF_FlateEncoder(const uint8_t* pBuffer,
- uint32_t size,
- bool bFlateEncode,
- bool bXRefStream)
- : m_dwSize(0) {
- if (!bFlateEncode) {
- m_pData = const_cast<uint8_t*>(pBuffer);
- m_dwSize = size;
- return;
- }
- uint8_t* buffer = nullptr;
- // TODO(thestig): Move to Init() and check return value.
- if (bXRefStream)
- ::PngEncode(pBuffer, size, &buffer, &m_dwSize);
- else
- ::FlateEncode(pBuffer, size, &buffer, &m_dwSize);
- m_pData = std::unique_ptr<uint8_t, FxFreeDeleter>(buffer);
-}
-
-CPDF_FlateEncoder::~CPDF_FlateEncoder() {}
-
-void CPDF_FlateEncoder::CloneDict() {
- if (m_pDict.IsOwned())
- return;
-
- m_pDict = ToDictionary(m_pDict->Clone());
- ASSERT(m_pDict.IsOwned());
-}
-
-class CPDF_Encryptor {
- public:
- CPDF_Encryptor(CPDF_CryptoHandler* pHandler,
- int objnum,
- uint8_t* src_data,
- uint32_t src_size);
- ~CPDF_Encryptor();
-
- uint8_t* m_pData;
- uint32_t m_dwSize;
- bool m_bNewBuf;
-};
-
-CPDF_Encryptor::CPDF_Encryptor(CPDF_CryptoHandler* pHandler,
- int objnum,
- uint8_t* src_data,
- uint32_t src_size)
- : m_pData(nullptr), m_dwSize(0), m_bNewBuf(false) {
- if (src_size == 0)
- return;
-
- if (!pHandler) {
- m_pData = (uint8_t*)src_data;
- m_dwSize = src_size;
- return;
- }
- m_dwSize = pHandler->EncryptGetSize(objnum, 0, src_data, src_size);
- m_pData = FX_Alloc(uint8_t, m_dwSize);
- pHandler->EncryptContent(objnum, 0, src_data, src_size, m_pData, m_dwSize);
- m_bNewBuf = true;
-}
-
-CPDF_Encryptor::~CPDF_Encryptor() {
- if (m_bNewBuf)
- FX_Free(m_pData);
-}
-
} // namespace
-CPDF_ObjectStream::CPDF_ObjectStream() : m_dwObjNum(0), m_index(0) {}
-
-CPDF_ObjectStream::~CPDF_ObjectStream() {}
-
-void CPDF_ObjectStream::Start() {
- m_Items.clear();
- m_Buffer.Clear();
- m_dwObjNum = 0;
- m_index = 0;
-}
-
-void CPDF_ObjectStream::CompressIndirectObject(uint32_t dwObjNum,
- const CPDF_Object* pObj) {
- m_Items.push_back({dwObjNum, m_Buffer.GetLength()});
- m_Buffer << pObj;
-}
-
-void CPDF_ObjectStream::CompressIndirectObject(uint32_t dwObjNum,
- const uint8_t* pBuffer,
- uint32_t dwSize) {
- m_Items.push_back({dwObjNum, m_Buffer.GetLength()});
- m_Buffer.AppendBlock(pBuffer, dwSize);
-}
-
-FX_FILESIZE CPDF_ObjectStream::End(CPDF_Creator* pCreator) {
- ASSERT(pCreator);
- if (m_Items.empty())
- return 0;
-
- CFX_FileBufferArchive* pFile = pCreator->GetFile();
- FX_FILESIZE ObjOffset = pCreator->GetOffset();
- if (!m_dwObjNum)
- m_dwObjNum = pCreator->GetNextObjectNumber();
-
- CFX_ByteTextBuf tempBuffer;
- for (const auto& pair : m_Items)
- tempBuffer << pair.objnum << " " << pair.offset << " ";
-
- int32_t len = pFile->AppendDWord(m_dwObjNum);
- if (len < 0)
- return -1;
-
- pCreator->IncrementOffset(len);
- if ((len = pFile->AppendString(" 0 obj\r\n<</Type /ObjStm /N ")) < 0)
- return -1;
-
- pCreator->IncrementOffset(len);
- uint32_t iCount = pdfium::CollectionSize<uint32_t>(m_Items);
- if ((len = pFile->AppendDWord(iCount)) < 0)
- return -1;
-
- pCreator->IncrementOffset(len);
- if (pFile->AppendString("/First ") < 0)
- return -1;
- if ((len = pFile->AppendDWord((uint32_t)tempBuffer.GetLength())) < 0)
- return -1;
- if (pFile->AppendString("/Length ") < 0)
- return -1;
-
- pCreator->IncrementOffset(len + 15);
-
- tempBuffer << m_Buffer;
- CPDF_FlateEncoder encoder(tempBuffer.GetBuffer(), tempBuffer.GetLength(),
- true, false);
- CPDF_Encryptor encryptor(pCreator->GetCryptoHandler(), m_dwObjNum,
- encoder.m_pData.Get(), encoder.m_dwSize);
- if ((len = pFile->AppendDWord(encryptor.m_dwSize)) < 0)
- return -1;
-
- pCreator->IncrementOffset(len);
- if (pFile->AppendString("/Filter /FlateDecode") < 0)
- return -1;
-
- pCreator->IncrementOffset(20);
- if ((len = pFile->AppendString(">>stream\r\n")) < 0)
- return -1;
- if (pFile->AppendBlock(encryptor.m_pData, encryptor.m_dwSize) < 0)
- return -1;
-
- pCreator->IncrementOffset(len + encryptor.m_dwSize);
- if ((len = pFile->AppendString("\r\nendstream\r\nendobj\r\n")) < 0)
- return -1;
-
- pCreator->IncrementOffset(len);
- return ObjOffset;
-}
-
-CPDF_XRefStream::CPDF_XRefStream()
- : m_PrevOffset(0), m_dwTempObjNum(0), m_iSeg(0) {}
-
-CPDF_XRefStream::~CPDF_XRefStream() {}
-
-bool CPDF_XRefStream::Start() {
- m_IndexArray.clear();
- m_Buffer.Clear();
- m_iSeg = 0;
- return true;
-}
-
-int32_t CPDF_XRefStream::CompressIndirectObject(uint32_t dwObjNum,
- const CPDF_Object* pObj,
- CPDF_Creator* pCreator) {
- if (!pCreator)
- return 0;
-
- m_ObjStream.CompressIndirectObject(dwObjNum, pObj);
- if (pdfium::CollectionSize<int32_t>(m_ObjStream.m_Items) <
- pCreator->GetObjectStreamSize() &&
- m_ObjStream.m_Buffer.GetLength() < kObjectStreamMaxLength) {
- return 1;
- }
- return EndObjectStream(pCreator, true);
-}
-
-int32_t CPDF_XRefStream::CompressIndirectObject(uint32_t dwObjNum,
- const uint8_t* pBuffer,
- uint32_t dwSize,
- CPDF_Creator* pCreator) {
- if (!pCreator)
- return 0;
-
- m_ObjStream.CompressIndirectObject(dwObjNum, pBuffer, dwSize);
- if (pdfium::CollectionSize<int32_t>(m_ObjStream.m_Items) <
- pCreator->GetObjectStreamSize() &&
- m_ObjStream.m_Buffer.GetLength() < kObjectStreamMaxLength) {
- return 1;
- }
- return EndObjectStream(pCreator, true);
-}
-
-int32_t CPDF_XRefStream::EndObjectStream(CPDF_Creator* pCreator, bool bEOF) {
- FX_FILESIZE objOffset = 0;
- if (bEOF) {
- objOffset = m_ObjStream.End(pCreator);
- if (objOffset < 0)
- return -1;
- }
-
- uint32_t& dwObjStmNum = m_ObjStream.m_dwObjNum;
- if (!dwObjStmNum)
- dwObjStmNum = pCreator->GetNextObjectNumber();
-
- int32_t iSize = pdfium::CollectionSize<int32_t>(m_ObjStream.m_Items);
- size_t iSeg = m_IndexArray.size();
- if (!pCreator->IsIncremental()) {
- if (m_dwTempObjNum == 0) {
- AppendIndex0(m_Buffer, true);
- m_dwTempObjNum++;
- }
- uint32_t end_num = m_IndexArray.back().objnum + m_IndexArray.back().count;
- int index = 0;
- for (; m_dwTempObjNum < end_num; m_dwTempObjNum++) {
- if (pCreator->HasObjectNumber(m_dwTempObjNum)) {
- if (index >= iSize ||
- m_dwTempObjNum != m_ObjStream.m_Items[index].objnum) {
- AppendIndex1(m_Buffer, pCreator->GetObjectOffset(m_dwTempObjNum));
- } else {
- AppendIndex2(m_Buffer, dwObjStmNum, index++);
- }
- } else {
- AppendIndex0(m_Buffer, false);
- }
- }
- if (iSize > 0 && bEOF)
- pCreator->SetObjectOffset(dwObjStmNum, objOffset);
-
- m_iSeg = iSeg;
- if (bEOF)
- m_ObjStream.Start();
-
- return 1;
- }
- for (auto it = m_IndexArray.begin() + m_iSeg; it != m_IndexArray.end();
- ++it) {
- for (uint32_t m = it->objnum; m < it->objnum + it->count; ++m) {
- if (m_ObjStream.m_index >= iSize ||
- m != m_ObjStream.m_Items[it - m_IndexArray.begin()].objnum) {
- AppendIndex1(m_Buffer, pCreator->GetObjectOffset(m));
- } else {
- AppendIndex2(m_Buffer, dwObjStmNum, m_ObjStream.m_index++);
- }
- }
- }
- if (iSize > 0 && bEOF) {
- AppendIndex1(m_Buffer, objOffset);
- m_IndexArray.push_back({dwObjStmNum, 1});
- iSeg += 1;
- }
- m_iSeg = iSeg;
- if (bEOF)
- m_ObjStream.Start();
-
- return 1;
-}
-
-bool CPDF_XRefStream::GenerateXRefStream(CPDF_Creator* pCreator, bool bEOF) {
- FX_FILESIZE offset_tmp = pCreator->GetOffset();
- uint32_t objnum = pCreator->GetNextObjectNumber();
- CFX_FileBufferArchive* pFile = pCreator->GetFile();
- if (pCreator->IsIncremental()) {
- AddObjectNumberToIndexArray(objnum);
- } else {
- for (; m_dwTempObjNum < pCreator->GetLastObjectNumber(); m_dwTempObjNum++) {
- if (pCreator->HasObjectNumber(m_dwTempObjNum))
- AppendIndex1(m_Buffer, pCreator->GetObjectOffset(m_dwTempObjNum));
- else
- AppendIndex0(m_Buffer, false);
- }
- }
-
- AppendIndex1(m_Buffer, offset_tmp);
-
- int32_t len = pFile->AppendDWord(objnum);
- if (len < 0)
- return false;
-
- pCreator->IncrementOffset(len);
- if ((len = pFile->AppendString(" 0 obj\r\n<</Type /XRef/W[1 4 2]/Index[")) <
- 0) {
- return false;
- }
- pCreator->IncrementOffset(len);
- if (!pCreator->IsIncremental()) {
- if ((len = pFile->AppendDWord(0)) < 0)
- return false;
- if ((len = pFile->AppendString(" ")) < 0)
- return false;
-
- pCreator->IncrementOffset(len + 1);
- if ((len = pFile->AppendDWord(objnum + 1)) < 0)
- return false;
-
- pCreator->IncrementOffset(len);
- } else {
- for (const auto& pair : m_IndexArray) {
- if ((len = pFile->AppendDWord(pair.objnum)) < 0)
- return false;
- if (pFile->AppendString(" ") < 0)
- return false;
-
- pCreator->IncrementOffset(len + 1);
- if ((len = pFile->AppendDWord(pair.count)) < 0)
- return false;
- if (pFile->AppendString(" ") < 0)
- return false;
-
- pCreator->IncrementOffset(len + 1);
- }
- }
- if (pFile->AppendString("]/Size ") < 0)
- return false;
- if ((len = pFile->AppendDWord(objnum + 1)) < 0)
- return false;
-
- pCreator->IncrementOffset(len + 7);
- if (m_PrevOffset > 0) {
- if (pFile->AppendString("/Prev ") < 0)
- return false;
-
- char offset_buf[20];
- memset(offset_buf, 0, sizeof(offset_buf));
- FXSYS_i64toa(m_PrevOffset, offset_buf, 10);
- int32_t offset_len = (int32_t)FXSYS_strlen(offset_buf);
- if (pFile->AppendBlock(offset_buf, offset_len) < 0)
- return false;
-
- pCreator->IncrementOffset(offset_len + 6);
- }
-
- CPDF_FlateEncoder encoder(m_Buffer.GetBuffer(), m_Buffer.GetLength(), true,
- true);
- if (pFile->AppendString("/Filter /FlateDecode") < 0)
- return false;
-
- pCreator->IncrementOffset(20);
- if ((len = pFile->AppendString("/DecodeParms<</Columns 7/Predictor 12>>")) <
- 0) {
- return false;
- }
-
- pCreator->IncrementOffset(len);
- if (pFile->AppendString("/Length ") < 0)
- return false;
- if ((len = pFile->AppendDWord(encoder.m_dwSize)) < 0)
- return false;
-
- pCreator->IncrementOffset(len + 8);
- if (bEOF) {
- if ((len = WriteTrailer(pCreator->GetDocument(), pFile,
- pCreator->GetIDArray())) < 0) {
- return false;
- }
- pCreator->IncrementOffset(len);
-
- if (CPDF_Dictionary* encryptDict = pCreator->GetEncryptDict()) {
- uint32_t dwEncryptObjNum = encryptDict->GetObjNum();
- if (dwEncryptObjNum == 0)
- dwEncryptObjNum = pCreator->GetEncryptObjectNumber();
- if ((len = WriteEncryptDictObjectReference(dwEncryptObjNum, pFile)) < 0)
- return false;
- pCreator->IncrementOffset(len);
- }
- }
- if ((len = pFile->AppendString(">>stream\r\n")) < 0)
- return false;
-
- pCreator->IncrementOffset(len);
- if (pFile->AppendBlock(encoder.m_pData.Get(), encoder.m_dwSize) < 0)
- return false;
- if ((len = pFile->AppendString("\r\nendstream\r\nendobj\r\n")) < 0)
- return false;
-
- pCreator->IncrementOffset(encoder.m_dwSize + len);
- m_PrevOffset = offset_tmp;
- return true;
-}
-
-bool CPDF_XRefStream::End(CPDF_Creator* pCreator, bool bEOF) {
- if (EndObjectStream(pCreator, bEOF) < 0)
- return false;
- return GenerateXRefStream(pCreator, bEOF);
-}
-
-bool CPDF_XRefStream::EndXRefStream(CPDF_Creator* pCreator) {
- if (!pCreator->IsIncremental()) {
- AppendIndex0(m_Buffer, true);
- for (uint32_t i = 1; i < pCreator->GetLastObjectNumber() + 1; i++) {
- if (pCreator->HasObjectNumber(i))
- AppendIndex1(m_Buffer, pCreator->GetObjectOffset(i));
- else
- AppendIndex0(m_Buffer, false);
- }
- } else {
- for (const auto& pair : m_IndexArray) {
- for (uint32_t j = pair.objnum; j < pair.objnum + pair.count; ++j)
- AppendIndex1(m_Buffer, pCreator->GetObjectOffset(j));
- }
- }
- return GenerateXRefStream(pCreator, false);
-}
-
-void CPDF_XRefStream::AddObjectNumberToIndexArray(uint32_t objnum) {
- if (m_IndexArray.empty()) {
- m_IndexArray.push_back({objnum, 1});
- return;
- }
-
- uint32_t next_objnum = m_IndexArray.back().objnum + m_IndexArray.back().count;
- if (objnum == next_objnum)
- m_IndexArray.back().count += 1;
- else
- m_IndexArray.push_back({objnum, 1});
-}
-
CPDF_Creator::CPDF_Creator(CPDF_Document* pDoc)
: m_pDocument(pDoc),
m_pParser(pDoc->GetParser()),
@@ -689,12 +82,7 @@ CPDF_Creator::~CPDF_Creator() {
bool CPDF_Creator::IsXRefNeedEnd() {
if (!IsIncremental())
return false;
-
- uint32_t iCount = 0;
- for (const auto& pair : m_pXRefStream->m_IndexArray)
- iCount += pair.count;
-
- return iCount >= kXRefStreamMaxSize;
+ return m_pXRefStream->CountIndexArrayItems() >= kXRefStreamMaxSize;
}
int32_t CPDF_Creator::WriteIndirectObjectToStream(const CPDF_Object* pObj) {
@@ -773,15 +161,15 @@ int32_t CPDF_Creator::WriteStream(const CPDF_Object* pStream,
CPDF_CryptoHandler* pCrypto) {
CPDF_FlateEncoder encoder(const_cast<CPDF_Stream*>(pStream->AsStream()),
pStream != m_pMetadata);
- CPDF_Encryptor encryptor(pCrypto, objnum, encoder.m_pData.Get(),
- encoder.m_dwSize);
- if (static_cast<uint32_t>(encoder.m_pDict->GetIntegerFor("Length")) !=
- encryptor.m_dwSize) {
+ CPDF_Encryptor encryptor(pCrypto, objnum, encoder.GetData(),
+ encoder.GetSize());
+ if (static_cast<uint32_t>(encoder.GetDict()->GetIntegerFor("Length")) !=
+ encryptor.GetSize()) {
encoder.CloneDict();
- encoder.m_pDict->SetNewFor<CPDF_Number>(
- "Length", static_cast<int>(encryptor.m_dwSize));
+ encoder.GetDict()->SetNewFor<CPDF_Number>(
+ "Length", static_cast<int>(encryptor.GetSize()));
}
- if (WriteDirectObj(objnum, encoder.m_pDict.Get()) < 0)
+ if (WriteDirectObj(objnum, encoder.GetDict()) < 0)
return -1;
int len = m_File.AppendString("stream\r\n");
@@ -789,10 +177,10 @@ int32_t CPDF_Creator::WriteStream(const CPDF_Object* pStream,
return -1;
m_Offset += len;
- if (m_File.AppendBlock(encryptor.m_pData, encryptor.m_dwSize) < 0)
+ if (m_File.AppendBlock(encryptor.GetData(), encryptor.GetSize()) < 0)
return -1;
- m_Offset += encryptor.m_dwSize;
+ m_Offset += encryptor.GetSize();
if ((len = m_File.AppendString("\r\nendstream")) < 0)
return -1;
@@ -860,8 +248,7 @@ int32_t CPDF_Creator::WriteDirectObj(uint32_t objnum,
CPDF_Encryptor encryptor(m_pCryptoHandler.Get(), objnum,
(uint8_t*)str.c_str(), str.GetLength());
CFX_ByteString content = PDF_EncodeString(
- CFX_ByteString((const char*)encryptor.m_pData, encryptor.m_dwSize),
- bHex);
+ CFX_ByteString(encryptor.GetData(), encryptor.GetSize()), bHex);
int32_t len = m_File.AppendString(content.AsStringC());
if (len < 0)
return -1;
@@ -873,14 +260,14 @@ int32_t CPDF_Creator::WriteDirectObj(uint32_t objnum,
CPDF_FlateEncoder encoder(const_cast<CPDF_Stream*>(pObj->AsStream()),
true);
CPDF_Encryptor encryptor(m_pCryptoHandler.Get(), objnum,
- encoder.m_pData.Get(), encoder.m_dwSize);
- if (static_cast<uint32_t>(encoder.m_pDict->GetIntegerFor("Length")) !=
- encryptor.m_dwSize) {
+ encoder.GetData(), encoder.GetSize());
+ if (static_cast<uint32_t>(encoder.GetDict()->GetIntegerFor("Length")) !=
+ encryptor.GetSize()) {
encoder.CloneDict();
- encoder.m_pDict->SetNewFor<CPDF_Number>(
- "Length", static_cast<int>(encryptor.m_dwSize));
+ encoder.GetDict()->SetNewFor<CPDF_Number>(
+ "Length", static_cast<int>(encryptor.GetSize()));
}
- if (WriteDirectObj(objnum, encoder.m_pDict.Get()) < 0)
+ if (WriteDirectObj(objnum, encoder.GetDict()) < 0)
return -1;
int32_t len = m_File.AppendString("stream\r\n");
@@ -888,10 +275,10 @@ int32_t CPDF_Creator::WriteDirectObj(uint32_t objnum,
return -1;
m_Offset += len;
- if (m_File.AppendBlock(encryptor.m_pData, encryptor.m_dwSize) < 0)
+ if (m_File.AppendBlock(encryptor.GetData(), encryptor.GetSize()) < 0)
return -1;
- m_Offset += encryptor.m_dwSize;
+ m_Offset += encryptor.GetSize();
len = m_File.AppendString("\r\nendstream");
if (len < 0)
return -1;
@@ -1129,10 +516,8 @@ int32_t CPDF_Creator::WriteDoc_Stage1() {
if (m_dwFlags & FPDFCREATE_OBJECTSTREAM) {
m_pXRefStream = pdfium::MakeUnique<CPDF_XRefStream>();
m_pXRefStream->Start();
- if (IsIncremental() && m_pParser) {
- FX_FILESIZE prev = m_pParser->GetLastXRefOffset();
- m_pXRefStream->m_PrevOffset = prev;
- }
+ if (IsIncremental() && m_pParser)
+ m_pXRefStream->SetPreviousOffset(m_pParser->GetLastXRefOffset());
}
m_iStage = 10;
}
@@ -1261,7 +646,7 @@ int32_t CPDF_Creator::WriteDoc_Stage3() {
m_XrefStart = m_Offset;
if (m_dwFlags & FPDFCREATE_OBJECTSTREAM) {
m_pXRefStream->End(this, true);
- m_XrefStart = m_pXRefStream->m_PrevOffset;
+ m_XrefStart = m_pXRefStream->GetPreviousOffset();
m_iStage = 90;
} else if (!IsIncremental() || !m_pParser->IsXRefStream()) {
if (!IsIncremental() || m_pParser->GetLastXRefOffset() == 0) {
@@ -1373,7 +758,8 @@ int32_t CPDF_Creator::WriteDoc_Stage4() {
for (const auto& it : *p) {
const CFX_ByteString& key = it.first;
CPDF_Object* pValue = it.second.get();
- // TODO(ochang): Consolidate with similar check in WriteTrailer.
+ // TODO(ochang): Consolidate with similar check in
+ // CPDF_XRefStream::WriteTrailer.
if (key == "Encrypt" || key == "Size" || key == "Filter" ||
key == "Index" || key == "Length" || key == "Prev" || key == "W" ||
key == "XRefStm" || key == "ID") {
diff --git a/core/fpdfapi/edit/cpdf_encryptor.cpp b/core/fpdfapi/edit/cpdf_encryptor.cpp
new file mode 100644
index 0000000000..858b5b6369
--- /dev/null
+++ b/core/fpdfapi/edit/cpdf_encryptor.cpp
@@ -0,0 +1,32 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fpdfapi/edit/cpdf_encryptor.h"
+#include "core/fpdfapi/parser/cpdf_crypto_handler.h"
+
+CPDF_Encryptor::CPDF_Encryptor(CPDF_CryptoHandler* pHandler,
+ int objnum,
+ uint8_t* src_data,
+ uint32_t src_size)
+ : m_pData(nullptr), m_dwSize(0), m_bNewBuf(false) {
+ if (src_size == 0)
+ return;
+
+ if (!pHandler) {
+ m_pData = (uint8_t*)src_data;
+ m_dwSize = src_size;
+ return;
+ }
+ m_dwSize = pHandler->EncryptGetSize(objnum, 0, src_data, src_size);
+ m_pData = FX_Alloc(uint8_t, m_dwSize);
+ pHandler->EncryptContent(objnum, 0, src_data, src_size, m_pData, m_dwSize);
+ m_bNewBuf = true;
+}
+
+CPDF_Encryptor::~CPDF_Encryptor() {
+ if (m_bNewBuf)
+ FX_Free(m_pData);
+}
diff --git a/core/fpdfapi/edit/cpdf_encryptor.h b/core/fpdfapi/edit/cpdf_encryptor.h
new file mode 100644
index 0000000000..00c9337eb3
--- /dev/null
+++ b/core/fpdfapi/edit/cpdf_encryptor.h
@@ -0,0 +1,31 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef CORE_FPDFAPI_EDIT_CPDF_ENCRYPTOR_H_
+#define CORE_FPDFAPI_EDIT_CPDF_ENCRYPTOR_H_
+
+#include <stdint.h>
+
+class CPDF_CryptoHandler;
+
+class CPDF_Encryptor {
+ public:
+ CPDF_Encryptor(CPDF_CryptoHandler* pHandler,
+ int objnum,
+ uint8_t* src_data,
+ uint32_t src_size);
+ ~CPDF_Encryptor();
+
+ uint32_t GetSize() const { return m_dwSize; }
+ uint8_t* GetData() const { return m_pData; }
+
+ private:
+ uint8_t* m_pData;
+ uint32_t m_dwSize;
+ bool m_bNewBuf;
+};
+
+#endif // CORE_FPDFAPI_EDIT_CPDF_ENCRYPTOR_H_
diff --git a/core/fpdfapi/edit/cpdf_flateencoder.cpp b/core/fpdfapi/edit/cpdf_flateencoder.cpp
new file mode 100644
index 0000000000..55d436f573
--- /dev/null
+++ b/core/fpdfapi/edit/cpdf_flateencoder.cpp
@@ -0,0 +1,77 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fpdfapi/edit/cpdf_flateencoder.h"
+
+#include <memory>
+
+#include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
+#include "core/fpdfapi/parser/fpdf_parser_decode.h"
+
+CPDF_FlateEncoder::CPDF_FlateEncoder(CPDF_Stream* pStream, bool bFlateEncode)
+ : m_dwSize(0), m_pAcc(pdfium::MakeRetain<CPDF_StreamAcc>(pStream)) {
+ m_pAcc->LoadAllData(true);
+
+ bool bHasFilter = pStream && pStream->HasFilter();
+ if (bHasFilter && !bFlateEncode) {
+ auto pDestAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
+ pDestAcc->LoadAllData();
+
+ m_dwSize = pDestAcc->GetSize();
+ m_pData = pDestAcc->DetachData();
+ m_pDict = ToDictionary(pStream->GetDict()->Clone());
+ m_pDict->RemoveFor("Filter");
+ return;
+ }
+ if (bHasFilter || !bFlateEncode) {
+ m_pData = const_cast<uint8_t*>(m_pAcc->GetData());
+ m_dwSize = m_pAcc->GetSize();
+ m_pDict = pStream->GetDict();
+ return;
+ }
+
+ // TODO(thestig): Move to Init() and check return value.
+ uint8_t* buffer = nullptr;
+ ::FlateEncode(m_pAcc->GetData(), m_pAcc->GetSize(), &buffer, &m_dwSize);
+
+ m_pData = std::unique_ptr<uint8_t, FxFreeDeleter>(buffer);
+ m_pDict = ToDictionary(pStream->GetDict()->Clone());
+ m_pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(m_dwSize));
+ m_pDict->SetNewFor<CPDF_Name>("Filter", "FlateDecode");
+ m_pDict->RemoveFor("DecodeParms");
+}
+
+CPDF_FlateEncoder::CPDF_FlateEncoder(const uint8_t* pBuffer,
+ uint32_t size,
+ bool bFlateEncode,
+ bool bXRefStream)
+ : m_dwSize(0) {
+ if (!bFlateEncode) {
+ m_pData = const_cast<uint8_t*>(pBuffer);
+ m_dwSize = size;
+ return;
+ }
+
+ uint8_t* buffer = nullptr;
+ // TODO(thestig): Move to Init() and check return value.
+ if (bXRefStream)
+ ::PngEncode(pBuffer, size, &buffer, &m_dwSize);
+ else
+ ::FlateEncode(pBuffer, size, &buffer, &m_dwSize);
+
+ m_pData = std::unique_ptr<uint8_t, FxFreeDeleter>(buffer);
+}
+
+CPDF_FlateEncoder::~CPDF_FlateEncoder() {}
+
+void CPDF_FlateEncoder::CloneDict() {
+ if (m_pDict.IsOwned())
+ return;
+
+ m_pDict = ToDictionary(m_pDict->Clone());
+ ASSERT(m_pDict.IsOwned());
+}
diff --git a/core/fpdfapi/edit/cpdf_flateencoder.h b/core/fpdfapi/edit/cpdf_flateencoder.h
new file mode 100644
index 0000000000..ac850e2802
--- /dev/null
+++ b/core/fpdfapi/edit/cpdf_flateencoder.h
@@ -0,0 +1,41 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef CORE_FPDFAPI_EDIT_CPDF_FLATEENCODER_H_
+#define CORE_FPDFAPI_EDIT_CPDF_FLATEENCODER_H_
+
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_stream_acc.h"
+#include "core/fxcrt/cfx_maybe_owned.h"
+#include "core/fxcrt/cfx_retain_ptr.h"
+#include "core/fxcrt/fx_memory.h"
+
+class CPDF_Stream;
+
+class CPDF_FlateEncoder {
+ public:
+ CPDF_FlateEncoder(CPDF_Stream* pStream, bool bFlateEncode);
+ CPDF_FlateEncoder(const uint8_t* pBuffer,
+ uint32_t size,
+ bool bFlateEncode,
+ bool bXRefStream);
+ ~CPDF_FlateEncoder();
+
+ void CloneDict();
+
+ uint32_t GetSize() const { return m_dwSize; }
+ uint8_t* GetData() const { return m_pData.Get(); }
+
+ CPDF_Dictionary* GetDict() { return m_pDict.Get(); }
+
+ private:
+ uint32_t m_dwSize;
+ CFX_MaybeOwned<uint8_t, FxFreeDeleter> m_pData;
+ CFX_MaybeOwned<CPDF_Dictionary> m_pDict;
+ CFX_RetainPtr<CPDF_StreamAcc> m_pAcc;
+};
+
+#endif // CORE_FPDFAPI_EDIT_CPDF_FLATEENCODER_H_
diff --git a/core/fpdfapi/edit/cpdf_objectstream.cpp b/core/fpdfapi/edit/cpdf_objectstream.cpp
new file mode 100644
index 0000000000..e3f6e4c8e9
--- /dev/null
+++ b/core/fpdfapi/edit/cpdf_objectstream.cpp
@@ -0,0 +1,109 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fpdfapi/edit/cpdf_objectstream.h"
+
+#include "core/fpdfapi/edit/cpdf_creator.h"
+#include "core/fpdfapi/edit/cpdf_encryptor.h"
+#include "core/fpdfapi/edit/cpdf_flateencoder.h"
+#include "core/fpdfapi/parser/fpdf_parser_utility.h"
+
+namespace {
+
+const int kObjectStreamMaxLength = 256 * 1024;
+
+} // namespace
+
+CPDF_ObjectStream::CPDF_ObjectStream() : m_dwObjNum(0), m_index(0) {}
+
+CPDF_ObjectStream::~CPDF_ObjectStream() {}
+
+bool CPDF_ObjectStream::IsNotFull() const {
+ return m_Buffer.GetLength() < kObjectStreamMaxLength;
+}
+
+void CPDF_ObjectStream::Start() {
+ m_Items.clear();
+ m_Buffer.Clear();
+ m_dwObjNum = 0;
+ m_index = 0;
+}
+
+void CPDF_ObjectStream::CompressIndirectObject(uint32_t dwObjNum,
+ const CPDF_Object* pObj) {
+ m_Items.push_back({dwObjNum, m_Buffer.GetLength()});
+ m_Buffer << pObj;
+}
+
+void CPDF_ObjectStream::CompressIndirectObject(uint32_t dwObjNum,
+ const uint8_t* pBuffer,
+ uint32_t dwSize) {
+ m_Items.push_back({dwObjNum, m_Buffer.GetLength()});
+ m_Buffer.AppendBlock(pBuffer, dwSize);
+}
+
+FX_FILESIZE CPDF_ObjectStream::End(CPDF_Creator* pCreator) {
+ ASSERT(pCreator);
+ if (m_Items.empty())
+ return 0;
+
+ CFX_FileBufferArchive* pFile = pCreator->GetFile();
+ FX_FILESIZE ObjOffset = pCreator->GetOffset();
+ if (!m_dwObjNum)
+ m_dwObjNum = pCreator->GetNextObjectNumber();
+
+ CFX_ByteTextBuf tempBuffer;
+ for (const auto& pair : m_Items)
+ tempBuffer << pair.objnum << " " << pair.offset << " ";
+
+ int32_t len = pFile->AppendDWord(m_dwObjNum);
+ if (len < 0)
+ return -1;
+
+ pCreator->IncrementOffset(len);
+ if ((len = pFile->AppendString(" 0 obj\r\n<</Type /ObjStm /N ")) < 0)
+ return -1;
+
+ pCreator->IncrementOffset(len);
+ uint32_t iCount = pdfium::CollectionSize<uint32_t>(m_Items);
+ if ((len = pFile->AppendDWord(iCount)) < 0)
+ return -1;
+
+ pCreator->IncrementOffset(len);
+ if (pFile->AppendString("/First ") < 0)
+ return -1;
+ if ((len = pFile->AppendDWord((uint32_t)tempBuffer.GetLength())) < 0)
+ return -1;
+ if (pFile->AppendString("/Length ") < 0)
+ return -1;
+
+ pCreator->IncrementOffset(len + 15);
+
+ tempBuffer << m_Buffer;
+ CPDF_FlateEncoder encoder(tempBuffer.GetBuffer(), tempBuffer.GetLength(),
+ true, false);
+ CPDF_Encryptor encryptor(pCreator->GetCryptoHandler(), m_dwObjNum,
+ encoder.GetData(), encoder.GetSize());
+ if ((len = pFile->AppendDWord(encryptor.GetSize())) < 0)
+ return -1;
+
+ pCreator->IncrementOffset(len);
+ if (pFile->AppendString("/Filter /FlateDecode") < 0)
+ return -1;
+
+ pCreator->IncrementOffset(20);
+ if ((len = pFile->AppendString(">>stream\r\n")) < 0)
+ return -1;
+ if (pFile->AppendBlock(encryptor.GetData(), encryptor.GetSize()) < 0)
+ return -1;
+
+ pCreator->IncrementOffset(len + encryptor.GetSize());
+ if ((len = pFile->AppendString("\r\nendstream\r\nendobj\r\n")) < 0)
+ return -1;
+
+ pCreator->IncrementOffset(len);
+ return ObjOffset;
+}
diff --git a/core/fpdfapi/edit/cpdf_objectstream.h b/core/fpdfapi/edit/cpdf_objectstream.h
index 3e5c5a72a9..5ad6ec8085 100644
--- a/core/fpdfapi/edit/cpdf_objectstream.h
+++ b/core/fpdfapi/edit/cpdf_objectstream.h
@@ -10,6 +10,7 @@
#include <vector>
#include "core/fxcrt/fx_basic.h"
+#include "third_party/base/stl_util.h"
class CPDF_Creator;
class CPDF_Object;
@@ -31,6 +32,18 @@ class CPDF_ObjectStream {
const uint8_t* pBuffer,
uint32_t dwSize);
+ bool IsNotFull() const;
+ int32_t ItemCount() const { return pdfium::CollectionSize<int32_t>(m_Items); }
+ void SetObjectNumber(uint32_t num) { m_dwObjNum = num; }
+ uint32_t GetObjectNumber() const { return m_dwObjNum; }
+ int32_t GetIndex() const { return m_index; }
+ void IncrementIndex() { m_index++; }
+
+ uint32_t GetObjectNumberForItem(int index) const {
+ return m_Items[index].objnum;
+ }
+
+ private:
std::vector<Item> m_Items;
CFX_ByteTextBuf m_Buffer;
uint32_t m_dwObjNum;
diff --git a/core/fpdfapi/edit/cpdf_xrefstream.cpp b/core/fpdfapi/edit/cpdf_xrefstream.cpp
new file mode 100644
index 0000000000..9ec27f291c
--- /dev/null
+++ b/core/fpdfapi/edit/cpdf_xrefstream.cpp
@@ -0,0 +1,412 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fpdfapi/edit/cpdf_xrefstream.h"
+
+#include "core/fpdfapi/edit/cpdf_creator.h"
+#include "core/fpdfapi/edit/cpdf_flateencoder.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/parser/cpdf_parser.h"
+#include "core/fpdfapi/parser/fpdf_parser_decode.h"
+
+namespace {
+
+int32_t WriteTrailer(CPDF_Document* pDocument,
+ CFX_FileBufferArchive* pFile,
+ CPDF_Array* pIDArray) {
+ FX_FILESIZE offset = 0;
+ int32_t len = 0;
+ CPDF_Parser* pParser = pDocument->GetParser();
+ if (pParser) {
+ CPDF_Dictionary* p = pParser->GetTrailer();
+ for (const auto& it : *p) {
+ const CFX_ByteString& key = it.first;
+ CPDF_Object* pValue = it.second.get();
+ if (key == "Encrypt" || key == "Size" || key == "Filter" ||
+ key == "Index" || key == "Length" || key == "Prev" || key == "W" ||
+ key == "XRefStm" || key == "Type" || key == "ID") {
+ continue;
+ }
+ if (key == "DecodeParms")
+ continue;
+ if (pFile->AppendString(("/")) < 0)
+ return -1;
+ if ((len = pFile->AppendString(PDF_NameEncode(key).AsStringC())) < 0)
+ return -1;
+
+ offset += len + 1;
+ if (!pValue->IsInline()) {
+ if (pFile->AppendString(" ") < 0)
+ return -1;
+ if ((len = pFile->AppendDWord(pValue->GetObjNum())) < 0)
+ return -1;
+ if (pFile->AppendString(" 0 R ") < 0)
+ return -1;
+
+ offset += len + 6;
+ } else {
+ if (!pValue->WriteTo(pFile, &offset))
+ return -1;
+ }
+ }
+ if (pIDArray) {
+ if (pFile->AppendString(("/ID")) < 0)
+ return -1;
+
+ offset += 3;
+ if (!pIDArray->WriteTo(pFile, &offset))
+ return -1;
+ }
+ return offset;
+ }
+ if (pFile->AppendString("\r\n/Root ") < 0)
+ return -1;
+ if ((len = pFile->AppendDWord(pDocument->GetRoot()->GetObjNum())) < 0)
+ return -1;
+ if (pFile->AppendString(" 0 R\r\n") < 0)
+ return -1;
+
+ offset += len + 14;
+ if (pDocument->GetInfo()) {
+ if (pFile->AppendString("/Info ") < 0)
+ return -1;
+ if ((len = pFile->AppendDWord(pDocument->GetInfo()->GetObjNum())) < 0)
+ return -1;
+ if (pFile->AppendString(" 0 R\r\n") < 0)
+ return -1;
+
+ offset += len + 12;
+ }
+ if (pIDArray) {
+ if (pFile->AppendString(("/ID")) < 0)
+ return -1;
+
+ offset += 3;
+ if (!pIDArray->WriteTo(pFile, &offset))
+ return -1;
+ }
+ return offset;
+}
+
+int32_t WriteEncryptDictObjectReference(uint32_t dwObjNum,
+ CFX_FileBufferArchive* pFile) {
+ ASSERT(pFile);
+
+ FX_FILESIZE offset = 0;
+ int32_t len = 0;
+ if (pFile->AppendString("/Encrypt") < 0)
+ return -1;
+
+ offset += 8;
+ if (pFile->AppendString(" ") < 0)
+ return -1;
+ if ((len = pFile->AppendDWord(dwObjNum)) < 0)
+ return -1;
+ if (pFile->AppendString(" 0 R ") < 0)
+ return -1;
+
+ offset += len + 6;
+ return offset;
+}
+
+void AppendIndex0(CFX_ByteTextBuf& buffer, bool bFirstObject) {
+ buffer.AppendByte(0);
+ buffer.AppendByte(0);
+ buffer.AppendByte(0);
+ buffer.AppendByte(0);
+ buffer.AppendByte(0);
+
+ const uint8_t byte = bFirstObject ? 0xFF : 0;
+ buffer.AppendByte(byte);
+ buffer.AppendByte(byte);
+}
+
+void AppendIndex1(CFX_ByteTextBuf& buffer, FX_FILESIZE offset) {
+ buffer.AppendByte(1);
+ buffer.AppendByte(static_cast<uint8_t>(offset >> 24));
+ buffer.AppendByte(static_cast<uint8_t>(offset >> 16));
+ buffer.AppendByte(static_cast<uint8_t>(offset >> 8));
+ buffer.AppendByte(static_cast<uint8_t>(offset));
+ buffer.AppendByte(0);
+ buffer.AppendByte(0);
+}
+
+void AppendIndex2(CFX_ByteTextBuf& buffer, uint32_t objnum, int32_t index) {
+ buffer.AppendByte(2);
+ buffer.AppendByte(static_cast<uint8_t>(objnum >> 24));
+ buffer.AppendByte(static_cast<uint8_t>(objnum >> 16));
+ buffer.AppendByte(static_cast<uint8_t>(objnum >> 8));
+ buffer.AppendByte(static_cast<uint8_t>(objnum));
+ buffer.AppendByte(static_cast<uint8_t>(index >> 8));
+ buffer.AppendByte(static_cast<uint8_t>(index));
+}
+
+} // namespace
+
+CPDF_XRefStream::CPDF_XRefStream()
+ : m_PrevOffset(0), m_dwTempObjNum(0), m_iSeg(0) {}
+
+CPDF_XRefStream::~CPDF_XRefStream() {}
+
+bool CPDF_XRefStream::Start() {
+ m_IndexArray.clear();
+ m_Buffer.Clear();
+ m_iSeg = 0;
+ return true;
+}
+
+int32_t CPDF_XRefStream::CompressIndirectObject(uint32_t dwObjNum,
+ const CPDF_Object* pObj,
+ CPDF_Creator* pCreator) {
+ ASSERT(pCreator);
+
+ m_ObjStream.CompressIndirectObject(dwObjNum, pObj);
+ if (m_ObjStream.ItemCount() < pCreator->GetObjectStreamSize() &&
+ m_ObjStream.IsNotFull()) {
+ return 1;
+ }
+ return EndObjectStream(pCreator, true);
+}
+
+int32_t CPDF_XRefStream::CompressIndirectObject(uint32_t dwObjNum,
+ const uint8_t* pBuffer,
+ uint32_t dwSize,
+ CPDF_Creator* pCreator) {
+ ASSERT(pCreator);
+
+ m_ObjStream.CompressIndirectObject(dwObjNum, pBuffer, dwSize);
+ if (m_ObjStream.ItemCount() < pCreator->GetObjectStreamSize() &&
+ m_ObjStream.IsNotFull()) {
+ return 1;
+ }
+ return EndObjectStream(pCreator, true);
+}
+
+int32_t CPDF_XRefStream::EndObjectStream(CPDF_Creator* pCreator, bool bEOF) {
+ FX_FILESIZE objOffset = 0;
+ if (bEOF) {
+ objOffset = m_ObjStream.End(pCreator);
+ if (objOffset < 0)
+ return -1;
+ }
+
+ if (!m_ObjStream.GetObjectNumber())
+ m_ObjStream.SetObjectNumber(pCreator->GetNextObjectNumber());
+
+ int32_t iSize = m_ObjStream.ItemCount();
+ size_t iSeg = m_IndexArray.size();
+ if (!pCreator->IsIncremental()) {
+ if (m_dwTempObjNum == 0) {
+ AppendIndex0(m_Buffer, true);
+ m_dwTempObjNum++;
+ }
+ uint32_t end_num = m_IndexArray.back().objnum + m_IndexArray.back().count;
+ int index = 0;
+ for (; m_dwTempObjNum < end_num; m_dwTempObjNum++) {
+ if (pCreator->HasObjectNumber(m_dwTempObjNum)) {
+ if (index >= iSize ||
+ m_dwTempObjNum != m_ObjStream.GetObjectNumberForItem(index)) {
+ AppendIndex1(m_Buffer, pCreator->GetObjectOffset(m_dwTempObjNum));
+ } else {
+ AppendIndex2(m_Buffer, m_ObjStream.GetObjectNumber(), index++);
+ }
+ } else {
+ AppendIndex0(m_Buffer, false);
+ }
+ }
+ if (iSize > 0 && bEOF)
+ pCreator->SetObjectOffset(m_ObjStream.GetObjectNumber(), objOffset);
+
+ m_iSeg = iSeg;
+ if (bEOF)
+ m_ObjStream.Start();
+
+ return 1;
+ }
+ for (auto it = m_IndexArray.begin() + m_iSeg; it != m_IndexArray.end();
+ ++it) {
+ for (uint32_t m = it->objnum; m < it->objnum + it->count; ++m) {
+ if (m_ObjStream.GetIndex() >= iSize ||
+ m != m_ObjStream.GetObjectNumberForItem(it - m_IndexArray.begin())) {
+ AppendIndex1(m_Buffer, pCreator->GetObjectOffset(m));
+ } else {
+ AppendIndex2(m_Buffer, m_ObjStream.GetObjectNumber(),
+ m_ObjStream.GetIndex());
+ m_ObjStream.IncrementIndex();
+ }
+ }
+ }
+ if (iSize > 0 && bEOF) {
+ AppendIndex1(m_Buffer, objOffset);
+ m_IndexArray.push_back({m_ObjStream.GetObjectNumber(), 1});
+ iSeg += 1;
+ }
+ m_iSeg = iSeg;
+ if (bEOF)
+ m_ObjStream.Start();
+
+ return 1;
+}
+
+bool CPDF_XRefStream::GenerateXRefStream(CPDF_Creator* pCreator, bool bEOF) {
+ FX_FILESIZE offset_tmp = pCreator->GetOffset();
+ uint32_t objnum = pCreator->GetNextObjectNumber();
+ CFX_FileBufferArchive* pFile = pCreator->GetFile();
+ if (pCreator->IsIncremental()) {
+ AddObjectNumberToIndexArray(objnum);
+ } else {
+ for (; m_dwTempObjNum < pCreator->GetLastObjectNumber(); m_dwTempObjNum++) {
+ if (pCreator->HasObjectNumber(m_dwTempObjNum))
+ AppendIndex1(m_Buffer, pCreator->GetObjectOffset(m_dwTempObjNum));
+ else
+ AppendIndex0(m_Buffer, false);
+ }
+ }
+
+ AppendIndex1(m_Buffer, offset_tmp);
+
+ int32_t len = pFile->AppendDWord(objnum);
+ if (len < 0)
+ return false;
+
+ pCreator->IncrementOffset(len);
+ if ((len = pFile->AppendString(" 0 obj\r\n<</Type /XRef/W[1 4 2]/Index[")) <
+ 0) {
+ return false;
+ }
+ pCreator->IncrementOffset(len);
+ if (!pCreator->IsIncremental()) {
+ if ((len = pFile->AppendDWord(0)) < 0)
+ return false;
+ if ((len = pFile->AppendString(" ")) < 0)
+ return false;
+
+ pCreator->IncrementOffset(len + 1);
+ if ((len = pFile->AppendDWord(objnum + 1)) < 0)
+ return false;
+
+ pCreator->IncrementOffset(len);
+ } else {
+ for (const auto& pair : m_IndexArray) {
+ if ((len = pFile->AppendDWord(pair.objnum)) < 0)
+ return false;
+ if (pFile->AppendString(" ") < 0)
+ return false;
+
+ pCreator->IncrementOffset(len + 1);
+ if ((len = pFile->AppendDWord(pair.count)) < 0)
+ return false;
+ if (pFile->AppendString(" ") < 0)
+ return false;
+
+ pCreator->IncrementOffset(len + 1);
+ }
+ }
+ if (pFile->AppendString("]/Size ") < 0)
+ return false;
+ if ((len = pFile->AppendDWord(objnum + 1)) < 0)
+ return false;
+
+ pCreator->IncrementOffset(len + 7);
+ if (m_PrevOffset > 0) {
+ if (pFile->AppendString("/Prev ") < 0)
+ return false;
+
+ char offset_buf[20];
+ memset(offset_buf, 0, sizeof(offset_buf));
+ FXSYS_i64toa(m_PrevOffset, offset_buf, 10);
+ int32_t offset_len = (int32_t)FXSYS_strlen(offset_buf);
+ if (pFile->AppendBlock(offset_buf, offset_len) < 0)
+ return false;
+
+ pCreator->IncrementOffset(offset_len + 6);
+ }
+
+ CPDF_FlateEncoder encoder(m_Buffer.GetBuffer(), m_Buffer.GetLength(), true,
+ true);
+ if (pFile->AppendString("/Filter /FlateDecode") < 0)
+ return false;
+
+ pCreator->IncrementOffset(20);
+ if ((len = pFile->AppendString("/DecodeParms<</Columns 7/Predictor 12>>")) <
+ 0) {
+ return false;
+ }
+
+ pCreator->IncrementOffset(len);
+ if (pFile->AppendString("/Length ") < 0)
+ return false;
+ if ((len = pFile->AppendDWord(encoder.GetSize())) < 0)
+ return false;
+
+ pCreator->IncrementOffset(len + 8);
+ if (bEOF) {
+ if ((len = WriteTrailer(pCreator->GetDocument(), pFile,
+ pCreator->GetIDArray())) < 0) {
+ return false;
+ }
+ pCreator->IncrementOffset(len);
+
+ if (CPDF_Dictionary* encryptDict = pCreator->GetEncryptDict()) {
+ uint32_t dwEncryptObjNum = encryptDict->GetObjNum();
+ if (dwEncryptObjNum == 0)
+ dwEncryptObjNum = pCreator->GetEncryptObjectNumber();
+ if ((len = WriteEncryptDictObjectReference(dwEncryptObjNum, pFile)) < 0)
+ return false;
+ pCreator->IncrementOffset(len);
+ }
+ }
+ if ((len = pFile->AppendString(">>stream\r\n")) < 0)
+ return false;
+
+ pCreator->IncrementOffset(len);
+ if (pFile->AppendBlock(encoder.GetData(), encoder.GetSize()) < 0)
+ return false;
+ if ((len = pFile->AppendString("\r\nendstream\r\nendobj\r\n")) < 0)
+ return false;
+
+ pCreator->IncrementOffset(encoder.GetSize() + len);
+ m_PrevOffset = offset_tmp;
+ return true;
+}
+
+bool CPDF_XRefStream::End(CPDF_Creator* pCreator, bool bEOF) {
+ if (EndObjectStream(pCreator, bEOF) < 0)
+ return false;
+ return GenerateXRefStream(pCreator, bEOF);
+}
+
+bool CPDF_XRefStream::EndXRefStream(CPDF_Creator* pCreator) {
+ if (!pCreator->IsIncremental()) {
+ AppendIndex0(m_Buffer, true);
+ for (uint32_t i = 1; i < pCreator->GetLastObjectNumber() + 1; i++) {
+ if (pCreator->HasObjectNumber(i))
+ AppendIndex1(m_Buffer, pCreator->GetObjectOffset(i));
+ else
+ AppendIndex0(m_Buffer, false);
+ }
+ } else {
+ for (const auto& pair : m_IndexArray) {
+ for (uint32_t j = pair.objnum; j < pair.objnum + pair.count; ++j)
+ AppendIndex1(m_Buffer, pCreator->GetObjectOffset(j));
+ }
+ }
+ return GenerateXRefStream(pCreator, false);
+}
+
+void CPDF_XRefStream::AddObjectNumberToIndexArray(uint32_t objnum) {
+ if (m_IndexArray.empty()) {
+ m_IndexArray.push_back({objnum, 1});
+ return;
+ }
+
+ uint32_t next_objnum = m_IndexArray.back().objnum + m_IndexArray.back().count;
+ if (objnum == next_objnum)
+ m_IndexArray.back().count += 1;
+ else
+ m_IndexArray.push_back({objnum, 1});
+}
diff --git a/core/fpdfapi/edit/cpdf_xrefstream.h b/core/fpdfapi/edit/cpdf_xrefstream.h
index cb11261f9f..2ca990732b 100644
--- a/core/fpdfapi/edit/cpdf_xrefstream.h
+++ b/core/fpdfapi/edit/cpdf_xrefstream.h
@@ -9,6 +9,9 @@
#include <vector>
+#include "core/fpdfapi/edit/cpdf_objectstream.h"
+#include "core/fxcrt/fx_basic.h"
+
class CPDF_Creator;
class CPDF_Object;
@@ -34,14 +37,23 @@ class CPDF_XRefStream {
void AddObjectNumberToIndexArray(uint32_t objnum);
bool EndXRefStream(CPDF_Creator* pCreator);
- std::vector<Index> m_IndexArray;
- FX_FILESIZE m_PrevOffset;
- uint32_t m_dwTempObjNum;
+ FX_FILESIZE GetPreviousOffset() const { return m_PrevOffset; }
+ void SetPreviousOffset(FX_FILESIZE offset) { m_PrevOffset = offset; }
- protected:
+ uint32_t CountIndexArrayItems() const {
+ uint32_t size = 0;
+ for (const auto& pair : m_IndexArray)
+ size += pair.count;
+ return size;
+ }
+
+ private:
int32_t EndObjectStream(CPDF_Creator* pCreator, bool bEOF);
bool GenerateXRefStream(CPDF_Creator* pCreator, bool bEOF);
+ std::vector<Index> m_IndexArray;
+ FX_FILESIZE m_PrevOffset;
+ uint32_t m_dwTempObjNum;
size_t m_iSeg;
CPDF_ObjectStream m_ObjStream;
CFX_ByteTextBuf m_Buffer;