1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2017 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_attachment.h"
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include <limits.h>
8*3ac0a46fSAndroid Build Coastguard Worker
9*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
10*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
11*3ac0a46fSAndroid Build Coastguard Worker
12*3ac0a46fSAndroid Build Coastguard Worker #include "constants/stream_dict_common.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "core/fdrm/fx_crypt.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_array.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_dictionary.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_document.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_name.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_number.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_reference.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_stream.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_string.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/fpdf_parser_decode.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfdoc/cpdf_filespec.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfdoc/cpdf_nametree.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/cfx_datetime.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/data_vector.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_extension.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_memory_wrappers.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_helpers.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/numerics/safe_conversions.h"
31*3ac0a46fSAndroid Build Coastguard Worker
32*3ac0a46fSAndroid Build Coastguard Worker namespace {
33*3ac0a46fSAndroid Build Coastguard Worker
34*3ac0a46fSAndroid Build Coastguard Worker constexpr char kChecksumKey[] = "CheckSum";
35*3ac0a46fSAndroid Build Coastguard Worker
CFXByteStringHexDecode(const ByteString & bsHex)36*3ac0a46fSAndroid Build Coastguard Worker ByteString CFXByteStringHexDecode(const ByteString& bsHex) {
37*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<uint8_t, FxFreeDeleter> result;
38*3ac0a46fSAndroid Build Coastguard Worker uint32_t size = 0;
39*3ac0a46fSAndroid Build Coastguard Worker HexDecode(bsHex.raw_span(), &result, &size);
40*3ac0a46fSAndroid Build Coastguard Worker return ByteString(result.get(), size);
41*3ac0a46fSAndroid Build Coastguard Worker }
42*3ac0a46fSAndroid Build Coastguard Worker
GenerateMD5Base16(const void * contents,const unsigned long len)43*3ac0a46fSAndroid Build Coastguard Worker ByteString GenerateMD5Base16(const void* contents, const unsigned long len) {
44*3ac0a46fSAndroid Build Coastguard Worker uint8_t digest[16];
45*3ac0a46fSAndroid Build Coastguard Worker CRYPT_MD5Generate({static_cast<const uint8_t*>(contents), len}, digest);
46*3ac0a46fSAndroid Build Coastguard Worker char buf[32];
47*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < 16; ++i)
48*3ac0a46fSAndroid Build Coastguard Worker FXSYS_IntToTwoHexChars(digest[i], &buf[i * 2]);
49*3ac0a46fSAndroid Build Coastguard Worker
50*3ac0a46fSAndroid Build Coastguard Worker return ByteString(buf, 32);
51*3ac0a46fSAndroid Build Coastguard Worker }
52*3ac0a46fSAndroid Build Coastguard Worker
53*3ac0a46fSAndroid Build Coastguard Worker } // namespace
54*3ac0a46fSAndroid Build Coastguard Worker
55*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document)56*3ac0a46fSAndroid Build Coastguard Worker FPDFDoc_GetAttachmentCount(FPDF_DOCUMENT document) {
57*3ac0a46fSAndroid Build Coastguard Worker CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
58*3ac0a46fSAndroid Build Coastguard Worker if (!pDoc)
59*3ac0a46fSAndroid Build Coastguard Worker return 0;
60*3ac0a46fSAndroid Build Coastguard Worker
61*3ac0a46fSAndroid Build Coastguard Worker auto name_tree = CPDF_NameTree::Create(pDoc, "EmbeddedFiles");
62*3ac0a46fSAndroid Build Coastguard Worker return name_tree ? pdfium::base::checked_cast<int>(name_tree->GetCount()) : 0;
63*3ac0a46fSAndroid Build Coastguard Worker }
64*3ac0a46fSAndroid Build Coastguard Worker
65*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV
FPDFDoc_AddAttachment(FPDF_DOCUMENT document,FPDF_WIDESTRING name)66*3ac0a46fSAndroid Build Coastguard Worker FPDFDoc_AddAttachment(FPDF_DOCUMENT document, FPDF_WIDESTRING name) {
67*3ac0a46fSAndroid Build Coastguard Worker CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
68*3ac0a46fSAndroid Build Coastguard Worker if (!pDoc)
69*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
70*3ac0a46fSAndroid Build Coastguard Worker
71*3ac0a46fSAndroid Build Coastguard Worker WideString wsName = WideStringFromFPDFWideString(name);
72*3ac0a46fSAndroid Build Coastguard Worker if (wsName.IsEmpty())
73*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
74*3ac0a46fSAndroid Build Coastguard Worker
75*3ac0a46fSAndroid Build Coastguard Worker auto name_tree =
76*3ac0a46fSAndroid Build Coastguard Worker CPDF_NameTree::CreateWithRootNameArray(pDoc, "EmbeddedFiles");
77*3ac0a46fSAndroid Build Coastguard Worker if (!name_tree)
78*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
79*3ac0a46fSAndroid Build Coastguard Worker
80*3ac0a46fSAndroid Build Coastguard Worker // Set up the basic entries in the filespec dictionary.
81*3ac0a46fSAndroid Build Coastguard Worker auto pFile = pDoc->NewIndirect<CPDF_Dictionary>();
82*3ac0a46fSAndroid Build Coastguard Worker pFile->SetNewFor<CPDF_Name>("Type", "Filespec");
83*3ac0a46fSAndroid Build Coastguard Worker pFile->SetNewFor<CPDF_String>("UF", wsName.AsStringView());
84*3ac0a46fSAndroid Build Coastguard Worker pFile->SetNewFor<CPDF_String>(pdfium::stream::kF, wsName.AsStringView());
85*3ac0a46fSAndroid Build Coastguard Worker
86*3ac0a46fSAndroid Build Coastguard Worker // Add the new attachment name and filespec into the document's EmbeddedFiles.
87*3ac0a46fSAndroid Build Coastguard Worker if (!name_tree->AddValueAndName(pFile->MakeReference(pDoc), wsName))
88*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
89*3ac0a46fSAndroid Build Coastguard Worker
90*3ac0a46fSAndroid Build Coastguard Worker // Unretained reference in public API. NOLINTNEXTLINE
91*3ac0a46fSAndroid Build Coastguard Worker return FPDFAttachmentFromCPDFObject(pFile);
92*3ac0a46fSAndroid Build Coastguard Worker }
93*3ac0a46fSAndroid Build Coastguard Worker
94*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_ATTACHMENT FPDF_CALLCONV
FPDFDoc_GetAttachment(FPDF_DOCUMENT document,int index)95*3ac0a46fSAndroid Build Coastguard Worker FPDFDoc_GetAttachment(FPDF_DOCUMENT document, int index) {
96*3ac0a46fSAndroid Build Coastguard Worker CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
97*3ac0a46fSAndroid Build Coastguard Worker if (!pDoc || index < 0)
98*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
99*3ac0a46fSAndroid Build Coastguard Worker
100*3ac0a46fSAndroid Build Coastguard Worker auto name_tree = CPDF_NameTree::Create(pDoc, "EmbeddedFiles");
101*3ac0a46fSAndroid Build Coastguard Worker if (!name_tree || static_cast<size_t>(index) >= name_tree->GetCount())
102*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
103*3ac0a46fSAndroid Build Coastguard Worker
104*3ac0a46fSAndroid Build Coastguard Worker WideString csName;
105*3ac0a46fSAndroid Build Coastguard Worker
106*3ac0a46fSAndroid Build Coastguard Worker // Unretained reference in public API. NOLINTNEXTLINE
107*3ac0a46fSAndroid Build Coastguard Worker return FPDFAttachmentFromCPDFObject(
108*3ac0a46fSAndroid Build Coastguard Worker name_tree->LookupValueAndName(index, &csName));
109*3ac0a46fSAndroid Build Coastguard Worker }
110*3ac0a46fSAndroid Build Coastguard Worker
111*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFDoc_DeleteAttachment(FPDF_DOCUMENT document,int index)112*3ac0a46fSAndroid Build Coastguard Worker FPDFDoc_DeleteAttachment(FPDF_DOCUMENT document, int index) {
113*3ac0a46fSAndroid Build Coastguard Worker CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
114*3ac0a46fSAndroid Build Coastguard Worker if (!pDoc || index < 0)
115*3ac0a46fSAndroid Build Coastguard Worker return false;
116*3ac0a46fSAndroid Build Coastguard Worker
117*3ac0a46fSAndroid Build Coastguard Worker auto name_tree = CPDF_NameTree::Create(pDoc, "EmbeddedFiles");
118*3ac0a46fSAndroid Build Coastguard Worker if (!name_tree || static_cast<size_t>(index) >= name_tree->GetCount())
119*3ac0a46fSAndroid Build Coastguard Worker return false;
120*3ac0a46fSAndroid Build Coastguard Worker
121*3ac0a46fSAndroid Build Coastguard Worker return name_tree->DeleteValueAndName(index);
122*3ac0a46fSAndroid Build Coastguard Worker }
123*3ac0a46fSAndroid Build Coastguard Worker
124*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFAttachment_GetName(FPDF_ATTACHMENT attachment,FPDF_WCHAR * buffer,unsigned long buflen)125*3ac0a46fSAndroid Build Coastguard Worker FPDFAttachment_GetName(FPDF_ATTACHMENT attachment,
126*3ac0a46fSAndroid Build Coastguard Worker FPDF_WCHAR* buffer,
127*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
128*3ac0a46fSAndroid Build Coastguard Worker CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
129*3ac0a46fSAndroid Build Coastguard Worker if (!pFile)
130*3ac0a46fSAndroid Build Coastguard Worker return 0;
131*3ac0a46fSAndroid Build Coastguard Worker
132*3ac0a46fSAndroid Build Coastguard Worker CPDF_FileSpec spec(pdfium::WrapRetain(pFile));
133*3ac0a46fSAndroid Build Coastguard Worker return Utf16EncodeMaybeCopyAndReturnLength(spec.GetFileName(), buffer,
134*3ac0a46fSAndroid Build Coastguard Worker buflen);
135*3ac0a46fSAndroid Build Coastguard Worker }
136*3ac0a46fSAndroid Build Coastguard Worker
137*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAttachment_HasKey(FPDF_ATTACHMENT attachment,FPDF_BYTESTRING key)138*3ac0a46fSAndroid Build Coastguard Worker FPDFAttachment_HasKey(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key) {
139*3ac0a46fSAndroid Build Coastguard Worker CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
140*3ac0a46fSAndroid Build Coastguard Worker if (!pFile)
141*3ac0a46fSAndroid Build Coastguard Worker return 0;
142*3ac0a46fSAndroid Build Coastguard Worker
143*3ac0a46fSAndroid Build Coastguard Worker CPDF_FileSpec spec(pdfium::WrapRetain(pFile));
144*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Dictionary> pParamsDict = spec.GetParamsDict();
145*3ac0a46fSAndroid Build Coastguard Worker return pParamsDict ? pParamsDict->KeyExist(key) : 0;
146*3ac0a46fSAndroid Build Coastguard Worker }
147*3ac0a46fSAndroid Build Coastguard Worker
148*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment,FPDF_BYTESTRING key)149*3ac0a46fSAndroid Build Coastguard Worker FPDFAttachment_GetValueType(FPDF_ATTACHMENT attachment, FPDF_BYTESTRING key) {
150*3ac0a46fSAndroid Build Coastguard Worker if (!FPDFAttachment_HasKey(attachment, key))
151*3ac0a46fSAndroid Build Coastguard Worker return FPDF_OBJECT_UNKNOWN;
152*3ac0a46fSAndroid Build Coastguard Worker
153*3ac0a46fSAndroid Build Coastguard Worker CPDF_FileSpec spec(
154*3ac0a46fSAndroid Build Coastguard Worker pdfium::WrapRetain(CPDFObjectFromFPDFAttachment(attachment)));
155*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> pObj = spec.GetParamsDict()->GetObjectFor(key);
156*3ac0a46fSAndroid Build Coastguard Worker return pObj ? pObj->GetType() : FPDF_OBJECT_UNKNOWN;
157*3ac0a46fSAndroid Build Coastguard Worker }
158*3ac0a46fSAndroid Build Coastguard Worker
159*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment,FPDF_BYTESTRING key,FPDF_WIDESTRING value)160*3ac0a46fSAndroid Build Coastguard Worker FPDFAttachment_SetStringValue(FPDF_ATTACHMENT attachment,
161*3ac0a46fSAndroid Build Coastguard Worker FPDF_BYTESTRING key,
162*3ac0a46fSAndroid Build Coastguard Worker FPDF_WIDESTRING value) {
163*3ac0a46fSAndroid Build Coastguard Worker CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
164*3ac0a46fSAndroid Build Coastguard Worker if (!pFile)
165*3ac0a46fSAndroid Build Coastguard Worker return false;
166*3ac0a46fSAndroid Build Coastguard Worker
167*3ac0a46fSAndroid Build Coastguard Worker CPDF_FileSpec spec(pdfium::WrapRetain(pFile));
168*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Dictionary> pParamsDict = spec.GetMutableParamsDict();
169*3ac0a46fSAndroid Build Coastguard Worker if (!pParamsDict)
170*3ac0a46fSAndroid Build Coastguard Worker return false;
171*3ac0a46fSAndroid Build Coastguard Worker
172*3ac0a46fSAndroid Build Coastguard Worker ByteString bsKey = key;
173*3ac0a46fSAndroid Build Coastguard Worker ByteString bsValue = ByteStringFromFPDFWideString(value);
174*3ac0a46fSAndroid Build Coastguard Worker bool bEncodedAsHex = bsKey == kChecksumKey;
175*3ac0a46fSAndroid Build Coastguard Worker if (bEncodedAsHex)
176*3ac0a46fSAndroid Build Coastguard Worker bsValue = CFXByteStringHexDecode(bsValue);
177*3ac0a46fSAndroid Build Coastguard Worker
178*3ac0a46fSAndroid Build Coastguard Worker pParamsDict->SetNewFor<CPDF_String>(bsKey, bsValue, bEncodedAsHex);
179*3ac0a46fSAndroid Build Coastguard Worker return true;
180*3ac0a46fSAndroid Build Coastguard Worker }
181*3ac0a46fSAndroid Build Coastguard Worker
182*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,FPDF_BYTESTRING key,FPDF_WCHAR * buffer,unsigned long buflen)183*3ac0a46fSAndroid Build Coastguard Worker FPDFAttachment_GetStringValue(FPDF_ATTACHMENT attachment,
184*3ac0a46fSAndroid Build Coastguard Worker FPDF_BYTESTRING key,
185*3ac0a46fSAndroid Build Coastguard Worker FPDF_WCHAR* buffer,
186*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
187*3ac0a46fSAndroid Build Coastguard Worker CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
188*3ac0a46fSAndroid Build Coastguard Worker if (!pFile)
189*3ac0a46fSAndroid Build Coastguard Worker return 0;
190*3ac0a46fSAndroid Build Coastguard Worker
191*3ac0a46fSAndroid Build Coastguard Worker CPDF_FileSpec spec(pdfium::WrapRetain(pFile));
192*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Dictionary> pParamsDict = spec.GetParamsDict();
193*3ac0a46fSAndroid Build Coastguard Worker if (!pParamsDict)
194*3ac0a46fSAndroid Build Coastguard Worker return 0;
195*3ac0a46fSAndroid Build Coastguard Worker
196*3ac0a46fSAndroid Build Coastguard Worker ByteString bsKey = key;
197*3ac0a46fSAndroid Build Coastguard Worker WideString value = pParamsDict->GetUnicodeTextFor(bsKey);
198*3ac0a46fSAndroid Build Coastguard Worker if (bsKey == kChecksumKey && !value.IsEmpty()) {
199*3ac0a46fSAndroid Build Coastguard Worker const CPDF_String* stringValue =
200*3ac0a46fSAndroid Build Coastguard Worker pParamsDict->GetObjectFor(bsKey)->AsString();
201*3ac0a46fSAndroid Build Coastguard Worker if (stringValue->IsHex()) {
202*3ac0a46fSAndroid Build Coastguard Worker ByteString encoded =
203*3ac0a46fSAndroid Build Coastguard Worker PDF_HexEncodeString(stringValue->GetString().AsStringView());
204*3ac0a46fSAndroid Build Coastguard Worker value = pdfium::MakeRetain<CPDF_String>(nullptr, encoded, false)
205*3ac0a46fSAndroid Build Coastguard Worker ->GetUnicodeText();
206*3ac0a46fSAndroid Build Coastguard Worker }
207*3ac0a46fSAndroid Build Coastguard Worker }
208*3ac0a46fSAndroid Build Coastguard Worker
209*3ac0a46fSAndroid Build Coastguard Worker return Utf16EncodeMaybeCopyAndReturnLength(value, buffer, buflen);
210*3ac0a46fSAndroid Build Coastguard Worker }
211*3ac0a46fSAndroid Build Coastguard Worker
212*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAttachment_SetFile(FPDF_ATTACHMENT attachment,FPDF_DOCUMENT document,const void * contents,unsigned long len)213*3ac0a46fSAndroid Build Coastguard Worker FPDFAttachment_SetFile(FPDF_ATTACHMENT attachment,
214*3ac0a46fSAndroid Build Coastguard Worker FPDF_DOCUMENT document,
215*3ac0a46fSAndroid Build Coastguard Worker const void* contents,
216*3ac0a46fSAndroid Build Coastguard Worker unsigned long len) {
217*3ac0a46fSAndroid Build Coastguard Worker CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
218*3ac0a46fSAndroid Build Coastguard Worker CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
219*3ac0a46fSAndroid Build Coastguard Worker if (!pFile || !pFile->IsDictionary() || !pDoc || len > INT_MAX)
220*3ac0a46fSAndroid Build Coastguard Worker return false;
221*3ac0a46fSAndroid Build Coastguard Worker
222*3ac0a46fSAndroid Build Coastguard Worker // An empty content must have a zero length.
223*3ac0a46fSAndroid Build Coastguard Worker if (!contents && len != 0)
224*3ac0a46fSAndroid Build Coastguard Worker return false;
225*3ac0a46fSAndroid Build Coastguard Worker
226*3ac0a46fSAndroid Build Coastguard Worker // Create a dictionary for the new embedded file stream.
227*3ac0a46fSAndroid Build Coastguard Worker auto pFileStreamDict = pdfium::MakeRetain<CPDF_Dictionary>();
228*3ac0a46fSAndroid Build Coastguard Worker auto pParamsDict = pFileStreamDict->SetNewFor<CPDF_Dictionary>("Params");
229*3ac0a46fSAndroid Build Coastguard Worker
230*3ac0a46fSAndroid Build Coastguard Worker // Set the size of the new file in the dictionary.
231*3ac0a46fSAndroid Build Coastguard Worker pFileStreamDict->SetNewFor<CPDF_Number>(pdfium::stream::kDL,
232*3ac0a46fSAndroid Build Coastguard Worker static_cast<int>(len));
233*3ac0a46fSAndroid Build Coastguard Worker pParamsDict->SetNewFor<CPDF_Number>("Size", static_cast<int>(len));
234*3ac0a46fSAndroid Build Coastguard Worker
235*3ac0a46fSAndroid Build Coastguard Worker // Set the creation date of the new attachment in the dictionary.
236*3ac0a46fSAndroid Build Coastguard Worker CFX_DateTime dateTime = CFX_DateTime::Now();
237*3ac0a46fSAndroid Build Coastguard Worker pParamsDict->SetNewFor<CPDF_String>(
238*3ac0a46fSAndroid Build Coastguard Worker "CreationDate",
239*3ac0a46fSAndroid Build Coastguard Worker ByteString::Format("D:%d%02d%02d%02d%02d%02d", dateTime.GetYear(),
240*3ac0a46fSAndroid Build Coastguard Worker dateTime.GetMonth(), dateTime.GetDay(),
241*3ac0a46fSAndroid Build Coastguard Worker dateTime.GetHour(), dateTime.GetMinute(),
242*3ac0a46fSAndroid Build Coastguard Worker dateTime.GetSecond()),
243*3ac0a46fSAndroid Build Coastguard Worker false);
244*3ac0a46fSAndroid Build Coastguard Worker
245*3ac0a46fSAndroid Build Coastguard Worker // Set the checksum of the new attachment in the dictionary.
246*3ac0a46fSAndroid Build Coastguard Worker pParamsDict->SetNewFor<CPDF_String>(
247*3ac0a46fSAndroid Build Coastguard Worker kChecksumKey, CFXByteStringHexDecode(GenerateMD5Base16(contents, len)),
248*3ac0a46fSAndroid Build Coastguard Worker true);
249*3ac0a46fSAndroid Build Coastguard Worker
250*3ac0a46fSAndroid Build Coastguard Worker // Create the file stream and have the filespec dictionary link to it.
251*3ac0a46fSAndroid Build Coastguard Worker const uint8_t* contents_as_bytes = static_cast<const uint8_t*>(contents);
252*3ac0a46fSAndroid Build Coastguard Worker auto pFileStream = pDoc->NewIndirect<CPDF_Stream>(
253*3ac0a46fSAndroid Build Coastguard Worker DataVector<uint8_t>(contents_as_bytes, contents_as_bytes + len),
254*3ac0a46fSAndroid Build Coastguard Worker std::move(pFileStreamDict));
255*3ac0a46fSAndroid Build Coastguard Worker auto pEFDict = pFile->AsMutableDictionary()->SetNewFor<CPDF_Dictionary>("EF");
256*3ac0a46fSAndroid Build Coastguard Worker pEFDict->SetNewFor<CPDF_Reference>("F", pDoc, pFileStream->GetObjNum());
257*3ac0a46fSAndroid Build Coastguard Worker return true;
258*3ac0a46fSAndroid Build Coastguard Worker }
259*3ac0a46fSAndroid Build Coastguard Worker
260*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,void * buffer,unsigned long buflen,unsigned long * out_buflen)261*3ac0a46fSAndroid Build Coastguard Worker FPDFAttachment_GetFile(FPDF_ATTACHMENT attachment,
262*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
263*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen,
264*3ac0a46fSAndroid Build Coastguard Worker unsigned long* out_buflen) {
265*3ac0a46fSAndroid Build Coastguard Worker if (!out_buflen)
266*3ac0a46fSAndroid Build Coastguard Worker return false;
267*3ac0a46fSAndroid Build Coastguard Worker
268*3ac0a46fSAndroid Build Coastguard Worker CPDF_Object* pFile = CPDFObjectFromFPDFAttachment(attachment);
269*3ac0a46fSAndroid Build Coastguard Worker if (!pFile)
270*3ac0a46fSAndroid Build Coastguard Worker return false;
271*3ac0a46fSAndroid Build Coastguard Worker
272*3ac0a46fSAndroid Build Coastguard Worker CPDF_FileSpec spec(pdfium::WrapRetain(pFile));
273*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Stream> pFileStream = spec.GetFileStream();
274*3ac0a46fSAndroid Build Coastguard Worker if (!pFileStream)
275*3ac0a46fSAndroid Build Coastguard Worker return false;
276*3ac0a46fSAndroid Build Coastguard Worker
277*3ac0a46fSAndroid Build Coastguard Worker *out_buflen = DecodeStreamMaybeCopyAndReturnLength(
278*3ac0a46fSAndroid Build Coastguard Worker std::move(pFileStream),
279*3ac0a46fSAndroid Build Coastguard Worker {static_cast<uint8_t*>(buffer), static_cast<size_t>(buflen)});
280*3ac0a46fSAndroid Build Coastguard Worker return true;
281*3ac0a46fSAndroid Build Coastguard Worker }
282