diff options
Diffstat (limited to 'core/fpdfapi')
-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.cpp | 32 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_encryptor.h | 31 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_flateencoder.cpp | 77 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_flateencoder.h | 41 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_objectstream.cpp | 109 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_objectstream.h | 13 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_xrefstream.cpp | 412 | ||||
-rw-r--r-- | core/fpdfapi/edit/cpdf_xrefstream.h | 20 |
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; |