xref: /aosp_15_r20/external/pdfium/samples/helpers/dump.cc (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2018 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 "samples/helpers/dump.h"
6*3ac0a46fSAndroid Build Coastguard Worker 
7*3ac0a46fSAndroid Build Coastguard Worker #include <limits.h>
8*3ac0a46fSAndroid Build Coastguard Worker #include <string.h>
9*3ac0a46fSAndroid Build Coastguard Worker 
10*3ac0a46fSAndroid Build Coastguard Worker #include <algorithm>
11*3ac0a46fSAndroid Build Coastguard Worker #include <functional>
12*3ac0a46fSAndroid Build Coastguard Worker #include <iterator>
13*3ac0a46fSAndroid Build Coastguard Worker #include <string>
14*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
15*3ac0a46fSAndroid Build Coastguard Worker 
16*3ac0a46fSAndroid Build Coastguard Worker #include "public/cpp/fpdf_scopers.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_doc.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_transformpage.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "testing/fx_string_testhelpers.h"
20*3ac0a46fSAndroid Build Coastguard Worker 
21*3ac0a46fSAndroid Build Coastguard Worker using GetBoxInfoFunc =
22*3ac0a46fSAndroid Build Coastguard Worker     std::function<bool(FPDF_PAGE, float*, float*, float*, float*)>;
23*3ac0a46fSAndroid Build Coastguard Worker 
24*3ac0a46fSAndroid Build Coastguard Worker namespace {
25*3ac0a46fSAndroid Build Coastguard Worker 
ConvertToWString(const unsigned short * buf,unsigned long buf_size)26*3ac0a46fSAndroid Build Coastguard Worker std::wstring ConvertToWString(const unsigned short* buf,
27*3ac0a46fSAndroid Build Coastguard Worker                               unsigned long buf_size) {
28*3ac0a46fSAndroid Build Coastguard Worker   std::wstring result;
29*3ac0a46fSAndroid Build Coastguard Worker   result.reserve(buf_size);
30*3ac0a46fSAndroid Build Coastguard Worker   std::copy(buf, buf + buf_size, std::back_inserter(result));
31*3ac0a46fSAndroid Build Coastguard Worker   return result;
32*3ac0a46fSAndroid Build Coastguard Worker }
33*3ac0a46fSAndroid Build Coastguard Worker 
DumpBoxInfo(GetBoxInfoFunc func,const char * box_type,FPDF_PAGE page,int page_idx)34*3ac0a46fSAndroid Build Coastguard Worker void DumpBoxInfo(GetBoxInfoFunc func,
35*3ac0a46fSAndroid Build Coastguard Worker                  const char* box_type,
36*3ac0a46fSAndroid Build Coastguard Worker                  FPDF_PAGE page,
37*3ac0a46fSAndroid Build Coastguard Worker                  int page_idx) {
38*3ac0a46fSAndroid Build Coastguard Worker   FS_RECTF rect;
39*3ac0a46fSAndroid Build Coastguard Worker   bool ret = func(page, &rect.left, &rect.bottom, &rect.right, &rect.top);
40*3ac0a46fSAndroid Build Coastguard Worker   if (!ret) {
41*3ac0a46fSAndroid Build Coastguard Worker     printf("Page %d: No %s.\n", page_idx, box_type);
42*3ac0a46fSAndroid Build Coastguard Worker     return;
43*3ac0a46fSAndroid Build Coastguard Worker   }
44*3ac0a46fSAndroid Build Coastguard Worker   printf("Page %d: %s: %0.2f %0.2f %0.2f %0.2f\n", page_idx, box_type,
45*3ac0a46fSAndroid Build Coastguard Worker          rect.left, rect.bottom, rect.right, rect.top);
46*3ac0a46fSAndroid Build Coastguard Worker }
47*3ac0a46fSAndroid Build Coastguard Worker 
DumpStructureElementAttributes(FPDF_STRUCTELEMENT_ATTR attr,int indent)48*3ac0a46fSAndroid Build Coastguard Worker void DumpStructureElementAttributes(FPDF_STRUCTELEMENT_ATTR attr, int indent) {
49*3ac0a46fSAndroid Build Coastguard Worker   static const size_t kBufSize = 1024;
50*3ac0a46fSAndroid Build Coastguard Worker   int count = FPDF_StructElement_Attr_GetCount(attr);
51*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < count; i++) {
52*3ac0a46fSAndroid Build Coastguard Worker     char name[kBufSize] = {};
53*3ac0a46fSAndroid Build Coastguard Worker     unsigned long len = ULONG_MAX;
54*3ac0a46fSAndroid Build Coastguard Worker     if (!FPDF_StructElement_Attr_GetName(attr, i, name, sizeof(name), &len)) {
55*3ac0a46fSAndroid Build Coastguard Worker       printf("%*s FPDF_StructElement_Attr_GetName failed for %d\n", indent, "",
56*3ac0a46fSAndroid Build Coastguard Worker              i);
57*3ac0a46fSAndroid Build Coastguard Worker       continue;
58*3ac0a46fSAndroid Build Coastguard Worker     }
59*3ac0a46fSAndroid Build Coastguard Worker 
60*3ac0a46fSAndroid Build Coastguard Worker     FPDF_OBJECT_TYPE type = FPDF_StructElement_Attr_GetType(attr, name);
61*3ac0a46fSAndroid Build Coastguard Worker     if (type == FPDF_OBJECT_BOOLEAN) {
62*3ac0a46fSAndroid Build Coastguard Worker       int value;
63*3ac0a46fSAndroid Build Coastguard Worker       if (!FPDF_StructElement_Attr_GetBooleanValue(attr, name, &value)) {
64*3ac0a46fSAndroid Build Coastguard Worker         printf("%*s %s: Failed FPDF_StructElement_Attr_GetBooleanValue\n",
65*3ac0a46fSAndroid Build Coastguard Worker                indent, "", name);
66*3ac0a46fSAndroid Build Coastguard Worker         continue;
67*3ac0a46fSAndroid Build Coastguard Worker       }
68*3ac0a46fSAndroid Build Coastguard Worker       printf("%*s %s: %d\n", indent, "", name, value);
69*3ac0a46fSAndroid Build Coastguard Worker     } else if (type == FPDF_OBJECT_NUMBER) {
70*3ac0a46fSAndroid Build Coastguard Worker       float value;
71*3ac0a46fSAndroid Build Coastguard Worker       if (!FPDF_StructElement_Attr_GetNumberValue(attr, name, &value)) {
72*3ac0a46fSAndroid Build Coastguard Worker         printf("%*s %s: Failed FPDF_StructElement_Attr_GetNumberValue\n",
73*3ac0a46fSAndroid Build Coastguard Worker                indent, "", name);
74*3ac0a46fSAndroid Build Coastguard Worker         continue;
75*3ac0a46fSAndroid Build Coastguard Worker       }
76*3ac0a46fSAndroid Build Coastguard Worker       printf("%*s %s: %f\n", indent, "", name, value);
77*3ac0a46fSAndroid Build Coastguard Worker     } else if (type == FPDF_OBJECT_STRING || type == FPDF_OBJECT_NAME) {
78*3ac0a46fSAndroid Build Coastguard Worker       unsigned short buffer[kBufSize] = {};
79*3ac0a46fSAndroid Build Coastguard Worker       if (!FPDF_StructElement_Attr_GetStringValue(attr, name, buffer,
80*3ac0a46fSAndroid Build Coastguard Worker                                                   sizeof(buffer), &len)) {
81*3ac0a46fSAndroid Build Coastguard Worker         printf("%*s %s: Failed FPDF_StructElement_Attr_GetStringValue\n",
82*3ac0a46fSAndroid Build Coastguard Worker                indent, "", name);
83*3ac0a46fSAndroid Build Coastguard Worker         continue;
84*3ac0a46fSAndroid Build Coastguard Worker       }
85*3ac0a46fSAndroid Build Coastguard Worker       printf("%*s %s: %ls\n", indent, "", name,
86*3ac0a46fSAndroid Build Coastguard Worker              ConvertToWString(buffer, len).c_str());
87*3ac0a46fSAndroid Build Coastguard Worker     } else if (type == FPDF_OBJECT_UNKNOWN) {
88*3ac0a46fSAndroid Build Coastguard Worker       printf("%*s %s: FPDF_OBJECT_UNKNOWN\n", indent, "", name);
89*3ac0a46fSAndroid Build Coastguard Worker     } else {
90*3ac0a46fSAndroid Build Coastguard Worker       printf("%*s %s: NOT_YET_IMPLEMENTED: %d\n", indent, "", name, type);
91*3ac0a46fSAndroid Build Coastguard Worker     }
92*3ac0a46fSAndroid Build Coastguard Worker   }
93*3ac0a46fSAndroid Build Coastguard Worker }
94*3ac0a46fSAndroid Build Coastguard Worker 
95*3ac0a46fSAndroid Build Coastguard Worker }  // namespace
96*3ac0a46fSAndroid Build Coastguard Worker 
DumpChildStructure(FPDF_STRUCTELEMENT child,int indent)97*3ac0a46fSAndroid Build Coastguard Worker void DumpChildStructure(FPDF_STRUCTELEMENT child, int indent) {
98*3ac0a46fSAndroid Build Coastguard Worker   static const size_t kBufSize = 1024;
99*3ac0a46fSAndroid Build Coastguard Worker   unsigned short buf[kBufSize];
100*3ac0a46fSAndroid Build Coastguard Worker   unsigned long len = FPDF_StructElement_GetType(child, buf, kBufSize);
101*3ac0a46fSAndroid Build Coastguard Worker   if (len > 0) {
102*3ac0a46fSAndroid Build Coastguard Worker     printf("%*s S: %ls\n", indent * 2, "", ConvertToWString(buf, len).c_str());
103*3ac0a46fSAndroid Build Coastguard Worker   }
104*3ac0a46fSAndroid Build Coastguard Worker 
105*3ac0a46fSAndroid Build Coastguard Worker   int attr_count = FPDF_StructElement_GetAttributeCount(child);
106*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < attr_count; i++) {
107*3ac0a46fSAndroid Build Coastguard Worker     FPDF_STRUCTELEMENT_ATTR child_attr =
108*3ac0a46fSAndroid Build Coastguard Worker         FPDF_StructElement_GetAttributeAtIndex(child, i);
109*3ac0a46fSAndroid Build Coastguard Worker     if (!child_attr) {
110*3ac0a46fSAndroid Build Coastguard Worker       continue;
111*3ac0a46fSAndroid Build Coastguard Worker     }
112*3ac0a46fSAndroid Build Coastguard Worker     printf("%*s A[%d]:\n", indent * 2, "", i);
113*3ac0a46fSAndroid Build Coastguard Worker     DumpStructureElementAttributes(child_attr, indent * 2 + 2);
114*3ac0a46fSAndroid Build Coastguard Worker   }
115*3ac0a46fSAndroid Build Coastguard Worker 
116*3ac0a46fSAndroid Build Coastguard Worker   memset(buf, 0, sizeof(buf));
117*3ac0a46fSAndroid Build Coastguard Worker   len = FPDF_StructElement_GetActualText(child, buf, kBufSize);
118*3ac0a46fSAndroid Build Coastguard Worker   if (len > 0) {
119*3ac0a46fSAndroid Build Coastguard Worker     printf("%*s ActualText: %ls\n", indent * 2, "",
120*3ac0a46fSAndroid Build Coastguard Worker            ConvertToWString(buf, len).c_str());
121*3ac0a46fSAndroid Build Coastguard Worker   }
122*3ac0a46fSAndroid Build Coastguard Worker 
123*3ac0a46fSAndroid Build Coastguard Worker   memset(buf, 0, sizeof(buf));
124*3ac0a46fSAndroid Build Coastguard Worker   len = FPDF_StructElement_GetAltText(child, buf, kBufSize);
125*3ac0a46fSAndroid Build Coastguard Worker   if (len > 0) {
126*3ac0a46fSAndroid Build Coastguard Worker     printf("%*s AltText: %ls\n", indent * 2, "",
127*3ac0a46fSAndroid Build Coastguard Worker            ConvertToWString(buf, len).c_str());
128*3ac0a46fSAndroid Build Coastguard Worker   }
129*3ac0a46fSAndroid Build Coastguard Worker 
130*3ac0a46fSAndroid Build Coastguard Worker   memset(buf, 0, sizeof(buf));
131*3ac0a46fSAndroid Build Coastguard Worker   len = FPDF_StructElement_GetID(child, buf, kBufSize);
132*3ac0a46fSAndroid Build Coastguard Worker   if (len > 0) {
133*3ac0a46fSAndroid Build Coastguard Worker     printf("%*s ID: %ls\n", indent * 2, "", ConvertToWString(buf, len).c_str());
134*3ac0a46fSAndroid Build Coastguard Worker   }
135*3ac0a46fSAndroid Build Coastguard Worker 
136*3ac0a46fSAndroid Build Coastguard Worker   memset(buf, 0, sizeof(buf));
137*3ac0a46fSAndroid Build Coastguard Worker   len = FPDF_StructElement_GetLang(child, buf, kBufSize);
138*3ac0a46fSAndroid Build Coastguard Worker   if (len > 0) {
139*3ac0a46fSAndroid Build Coastguard Worker     printf("%*s Lang: %ls\n", indent * 2, "",
140*3ac0a46fSAndroid Build Coastguard Worker            ConvertToWString(buf, len).c_str());
141*3ac0a46fSAndroid Build Coastguard Worker   }
142*3ac0a46fSAndroid Build Coastguard Worker 
143*3ac0a46fSAndroid Build Coastguard Worker   int mcid = FPDF_StructElement_GetMarkedContentID(child);
144*3ac0a46fSAndroid Build Coastguard Worker   if (mcid != -1) {
145*3ac0a46fSAndroid Build Coastguard Worker     printf("%*s MCID: %d\n", indent * 2, "", mcid);
146*3ac0a46fSAndroid Build Coastguard Worker   }
147*3ac0a46fSAndroid Build Coastguard Worker 
148*3ac0a46fSAndroid Build Coastguard Worker   FPDF_STRUCTELEMENT parent = FPDF_StructElement_GetParent(child);
149*3ac0a46fSAndroid Build Coastguard Worker   if (parent) {
150*3ac0a46fSAndroid Build Coastguard Worker     memset(buf, 0, sizeof(buf));
151*3ac0a46fSAndroid Build Coastguard Worker     len = FPDF_StructElement_GetID(parent, buf, kBufSize);
152*3ac0a46fSAndroid Build Coastguard Worker     if (len > 0) {
153*3ac0a46fSAndroid Build Coastguard Worker       printf("%*s Parent ID: %ls\n", indent * 2, "",
154*3ac0a46fSAndroid Build Coastguard Worker              ConvertToWString(buf, len).c_str());
155*3ac0a46fSAndroid Build Coastguard Worker     }
156*3ac0a46fSAndroid Build Coastguard Worker   }
157*3ac0a46fSAndroid Build Coastguard Worker 
158*3ac0a46fSAndroid Build Coastguard Worker   memset(buf, 0, sizeof(buf));
159*3ac0a46fSAndroid Build Coastguard Worker   len = FPDF_StructElement_GetTitle(child, buf, kBufSize);
160*3ac0a46fSAndroid Build Coastguard Worker   if (len > 0) {
161*3ac0a46fSAndroid Build Coastguard Worker     printf("%*s Title: %ls\n", indent * 2, "",
162*3ac0a46fSAndroid Build Coastguard Worker            ConvertToWString(buf, len).c_str());
163*3ac0a46fSAndroid Build Coastguard Worker   }
164*3ac0a46fSAndroid Build Coastguard Worker 
165*3ac0a46fSAndroid Build Coastguard Worker   memset(buf, 0, sizeof(buf));
166*3ac0a46fSAndroid Build Coastguard Worker   len = FPDF_StructElement_GetObjType(child, buf, kBufSize);
167*3ac0a46fSAndroid Build Coastguard Worker   if (len > 0) {
168*3ac0a46fSAndroid Build Coastguard Worker     printf("%*s Type: %ls\n", indent * 2, "",
169*3ac0a46fSAndroid Build Coastguard Worker            ConvertToWString(buf, len).c_str());
170*3ac0a46fSAndroid Build Coastguard Worker   }
171*3ac0a46fSAndroid Build Coastguard Worker 
172*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < FPDF_StructElement_CountChildren(child); ++i) {
173*3ac0a46fSAndroid Build Coastguard Worker     FPDF_STRUCTELEMENT sub_child = FPDF_StructElement_GetChildAtIndex(child, i);
174*3ac0a46fSAndroid Build Coastguard Worker     // If the child is not an Element then this will return null. This can
175*3ac0a46fSAndroid Build Coastguard Worker     // happen if the element is things like an object reference or a stream.
176*3ac0a46fSAndroid Build Coastguard Worker     if (!sub_child) {
177*3ac0a46fSAndroid Build Coastguard Worker       continue;
178*3ac0a46fSAndroid Build Coastguard Worker     }
179*3ac0a46fSAndroid Build Coastguard Worker 
180*3ac0a46fSAndroid Build Coastguard Worker     DumpChildStructure(sub_child, indent + 1);
181*3ac0a46fSAndroid Build Coastguard Worker   }
182*3ac0a46fSAndroid Build Coastguard Worker }
183*3ac0a46fSAndroid Build Coastguard Worker 
DumpPageInfo(FPDF_PAGE page,int page_idx)184*3ac0a46fSAndroid Build Coastguard Worker void DumpPageInfo(FPDF_PAGE page, int page_idx) {
185*3ac0a46fSAndroid Build Coastguard Worker   DumpBoxInfo(&FPDFPage_GetMediaBox, "MediaBox", page, page_idx);
186*3ac0a46fSAndroid Build Coastguard Worker   DumpBoxInfo(&FPDFPage_GetCropBox, "CropBox", page, page_idx);
187*3ac0a46fSAndroid Build Coastguard Worker   DumpBoxInfo(&FPDFPage_GetBleedBox, "BleedBox", page, page_idx);
188*3ac0a46fSAndroid Build Coastguard Worker   DumpBoxInfo(&FPDFPage_GetTrimBox, "TrimBox", page, page_idx);
189*3ac0a46fSAndroid Build Coastguard Worker   DumpBoxInfo(&FPDFPage_GetArtBox, "ArtBox", page, page_idx);
190*3ac0a46fSAndroid Build Coastguard Worker }
191*3ac0a46fSAndroid Build Coastguard Worker 
DumpPageStructure(FPDF_PAGE page,int page_idx)192*3ac0a46fSAndroid Build Coastguard Worker void DumpPageStructure(FPDF_PAGE page, int page_idx) {
193*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFStructTree tree(FPDF_StructTree_GetForPage(page));
194*3ac0a46fSAndroid Build Coastguard Worker   if (!tree) {
195*3ac0a46fSAndroid Build Coastguard Worker     fprintf(stderr, "Failed to load struct tree for page %d\n", page_idx);
196*3ac0a46fSAndroid Build Coastguard Worker     return;
197*3ac0a46fSAndroid Build Coastguard Worker   }
198*3ac0a46fSAndroid Build Coastguard Worker 
199*3ac0a46fSAndroid Build Coastguard Worker   printf("Structure Tree for Page %d\n", page_idx);
200*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < FPDF_StructTree_CountChildren(tree.get()); ++i) {
201*3ac0a46fSAndroid Build Coastguard Worker     FPDF_STRUCTELEMENT child = FPDF_StructTree_GetChildAtIndex(tree.get(), i);
202*3ac0a46fSAndroid Build Coastguard Worker     if (!child) {
203*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "Failed to load child %d for page %d\n", i, page_idx);
204*3ac0a46fSAndroid Build Coastguard Worker       continue;
205*3ac0a46fSAndroid Build Coastguard Worker     }
206*3ac0a46fSAndroid Build Coastguard Worker     DumpChildStructure(child, 0);
207*3ac0a46fSAndroid Build Coastguard Worker   }
208*3ac0a46fSAndroid Build Coastguard Worker   printf("\n\n");
209*3ac0a46fSAndroid Build Coastguard Worker }
210*3ac0a46fSAndroid Build Coastguard Worker 
DumpMetaData(FPDF_DOCUMENT doc)211*3ac0a46fSAndroid Build Coastguard Worker void DumpMetaData(FPDF_DOCUMENT doc) {
212*3ac0a46fSAndroid Build Coastguard Worker   static constexpr const char* kMetaTags[] = {
213*3ac0a46fSAndroid Build Coastguard Worker       "Title",   "Author",   "Subject",      "Keywords",
214*3ac0a46fSAndroid Build Coastguard Worker       "Creator", "Producer", "CreationDate", "ModDate"};
215*3ac0a46fSAndroid Build Coastguard Worker   for (const char* meta_tag : kMetaTags) {
216*3ac0a46fSAndroid Build Coastguard Worker     char meta_buffer[4096];
217*3ac0a46fSAndroid Build Coastguard Worker     unsigned long len =
218*3ac0a46fSAndroid Build Coastguard Worker         FPDF_GetMetaText(doc, meta_tag, meta_buffer, sizeof(meta_buffer));
219*3ac0a46fSAndroid Build Coastguard Worker     if (!len) {
220*3ac0a46fSAndroid Build Coastguard Worker       continue;
221*3ac0a46fSAndroid Build Coastguard Worker     }
222*3ac0a46fSAndroid Build Coastguard Worker 
223*3ac0a46fSAndroid Build Coastguard Worker     auto* meta_string = reinterpret_cast<unsigned short*>(meta_buffer);
224*3ac0a46fSAndroid Build Coastguard Worker     printf("%-12s = %ls (%lu bytes)\n", meta_tag,
225*3ac0a46fSAndroid Build Coastguard Worker            GetPlatformWString(meta_string).c_str(), len);
226*3ac0a46fSAndroid Build Coastguard Worker   }
227*3ac0a46fSAndroid Build Coastguard Worker }
228