• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <limits>
6 #include <string>
7 
8 #include "core/fpdfapi/parser/cpdf_parser.h"
9 #include "core/fpdfapi/parser/cpdf_syntax_parser.h"
10 #include "core/fxcrt/cfx_retain_ptr.h"
11 #include "core/fxcrt/fx_ext.h"
12 #include "core/fxcrt/fx_stream.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "testing/utils/path_service.h"
15 
16 // Provide a way to read test data from a buffer instead of a file.
17 class CFX_TestBufferRead : public IFX_SeekableReadStream {
18  public:
Create(const unsigned char * buffer_in,size_t buf_size)19   static CFX_RetainPtr<CFX_TestBufferRead> Create(
20       const unsigned char* buffer_in,
21       size_t buf_size) {
22     return CFX_RetainPtr<CFX_TestBufferRead>(
23         new CFX_TestBufferRead(buffer_in, buf_size));
24   }
25 
26   // IFX_SeekableReadStream:
ReadBlock(void * buffer,FX_FILESIZE offset,size_t size)27   bool ReadBlock(void* buffer, FX_FILESIZE offset, size_t size) override {
28     if (offset < 0 || offset + size > total_size_)
29       return false;
30 
31     memcpy(buffer, buffer_ + offset, size);
32     return true;
33   }
34 
GetSize()35   FX_FILESIZE GetSize() override { return (FX_FILESIZE)total_size_; };
36 
37  protected:
CFX_TestBufferRead(const unsigned char * buffer_in,size_t buf_size)38   CFX_TestBufferRead(const unsigned char* buffer_in, size_t buf_size)
39       : buffer_(buffer_in), total_size_(buf_size) {}
40 
41   const unsigned char* buffer_;
42   size_t total_size_;
43 };
44 
45 // A wrapper class to help test member functions of CPDF_Parser.
46 class CPDF_TestParser : public CPDF_Parser {
47  public:
CPDF_TestParser()48   CPDF_TestParser() {}
~CPDF_TestParser()49   ~CPDF_TestParser() {}
50 
51   // Setup reading from a file and initial states.
InitTestFromFile(const FX_CHAR * path)52   bool InitTestFromFile(const FX_CHAR* path) {
53     CFX_RetainPtr<IFX_SeekableReadStream> pFileAccess =
54         IFX_SeekableReadStream::CreateFromFilename(path);
55     if (!pFileAccess)
56       return false;
57 
58     // For the test file, the header is set at the beginning.
59     m_pSyntax->InitParser(pFileAccess, 0);
60     return true;
61   }
62 
63   // Setup reading from a buffer and initial states.
InitTestFromBuffer(const unsigned char * buffer,size_t len)64   bool InitTestFromBuffer(const unsigned char* buffer, size_t len) {
65     CFX_RetainPtr<CFX_TestBufferRead> buffer_reader =
66         CFX_TestBufferRead::Create(buffer, len);
67 
68     // For the test file, the header is set at the beginning.
69     m_pSyntax->InitParser(buffer_reader, 0);
70     return true;
71   }
72 
73  private:
74   // Add test cases here as private friend so that protected members in
75   // CPDF_Parser can be accessed by test cases.
76   // Need to access RebuildCrossRef.
77   FRIEND_TEST(cpdf_parser, RebuildCrossRefCorrectly);
78   FRIEND_TEST(cpdf_parser, RebuildCrossRefFailed);
79   // Need to access LoadCrossRefV4.
80   FRIEND_TEST(cpdf_parser, LoadCrossRefV4);
81 };
82 
TEST(cpdf_parser,RebuildCrossRefCorrectly)83 TEST(cpdf_parser, RebuildCrossRefCorrectly) {
84   CPDF_TestParser parser;
85   std::string test_file;
86   ASSERT_TRUE(PathService::GetTestFilePath("parser_rebuildxref_correct.pdf",
87                                            &test_file));
88   ASSERT_TRUE(parser.InitTestFromFile(test_file.c_str())) << test_file;
89 
90   ASSERT_TRUE(parser.RebuildCrossRef());
91   const FX_FILESIZE offsets[] = {0, 15, 61, 154, 296, 374, 450};
92   const uint16_t versions[] = {0, 0, 2, 4, 6, 8, 0};
93   for (size_t i = 0; i < FX_ArraySize(offsets); ++i)
94     EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos);
95   for (size_t i = 0; i < FX_ArraySize(versions); ++i)
96     EXPECT_EQ(versions[i], parser.m_ObjectInfo[i].gennum);
97 }
98 
TEST(cpdf_parser,RebuildCrossRefFailed)99 TEST(cpdf_parser, RebuildCrossRefFailed) {
100   CPDF_TestParser parser;
101   std::string test_file;
102   ASSERT_TRUE(PathService::GetTestFilePath(
103       "parser_rebuildxref_error_notrailer.pdf", &test_file));
104   ASSERT_TRUE(parser.InitTestFromFile(test_file.c_str())) << test_file;
105 
106   ASSERT_FALSE(parser.RebuildCrossRef());
107 }
108 
TEST(cpdf_parser,LoadCrossRefV4)109 TEST(cpdf_parser, LoadCrossRefV4) {
110   {
111     const unsigned char xref_table[] =
112         "xref \n"
113         "0 6 \n"
114         "0000000003 65535 f \n"
115         "0000000017 00000 n \n"
116         "0000000081 00000 n \n"
117         "0000000000 00007 f \n"
118         "0000000331 00000 n \n"
119         "0000000409 00000 n \n"
120         "trail";  // Needed to end cross ref table reading.
121     CPDF_TestParser parser;
122     ASSERT_TRUE(
123         parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table)));
124 
125     ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, false));
126     const FX_FILESIZE offsets[] = {0, 17, 81, 0, 331, 409};
127     const uint8_t types[] = {0, 1, 1, 0, 1, 1};
128     for (size_t i = 0; i < FX_ArraySize(offsets); ++i) {
129       EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos);
130       EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type);
131     }
132   }
133   {
134     const unsigned char xref_table[] =
135         "xref \n"
136         "0 1 \n"
137         "0000000000 65535 f \n"
138         "3 1 \n"
139         "0000025325 00000 n \n"
140         "8 2 \n"
141         "0000025518 00002 n \n"
142         "0000025635 00000 n \n"
143         "12 1 \n"
144         "0000025777 00000 n \n"
145         "trail";  // Needed to end cross ref table reading.
146     CPDF_TestParser parser;
147     ASSERT_TRUE(
148         parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table)));
149 
150     ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, false));
151     const FX_FILESIZE offsets[] = {0, 0,     0,     25325, 0, 0,    0,
152                                    0, 25518, 25635, 0,     0, 25777};
153     const uint8_t types[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1};
154     for (size_t i = 0; i < FX_ArraySize(offsets); ++i) {
155       EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos);
156       EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type);
157     }
158   }
159   {
160     const unsigned char xref_table[] =
161         "xref \n"
162         "0 1 \n"
163         "0000000000 65535 f \n"
164         "3 1 \n"
165         "0000025325 00000 n \n"
166         "8 2 \n"
167         "0000000000 65535 f \n"
168         "0000025635 00000 n \n"
169         "12 1 \n"
170         "0000025777 00000 n \n"
171         "trail";  // Needed to end cross ref table reading.
172     CPDF_TestParser parser;
173     ASSERT_TRUE(
174         parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table)));
175 
176     ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, false));
177     const FX_FILESIZE offsets[] = {0, 0, 0,     25325, 0, 0,    0,
178                                    0, 0, 25635, 0,     0, 25777};
179     const uint8_t types[] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1};
180     for (size_t i = 0; i < FX_ArraySize(offsets); ++i) {
181       EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos);
182       EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type);
183     }
184   }
185   {
186     const unsigned char xref_table[] =
187         "xref \n"
188         "0 7 \n"
189         "0000000002 65535 f \n"
190         "0000000023 00000 n \n"
191         "0000000003 65535 f \n"
192         "0000000004 65535 f \n"
193         "0000000000 65535 f \n"
194         "0000000045 00000 n \n"
195         "0000000179 00000 n \n"
196         "trail";  // Needed to end cross ref table reading.
197     CPDF_TestParser parser;
198     ASSERT_TRUE(
199         parser.InitTestFromBuffer(xref_table, FX_ArraySize(xref_table)));
200 
201     ASSERT_TRUE(parser.LoadCrossRefV4(0, 0, false));
202     const FX_FILESIZE offsets[] = {0, 23, 0, 0, 0, 45, 179};
203     const uint8_t types[] = {0, 1, 0, 0, 0, 1, 1};
204     for (size_t i = 0; i < FX_ArraySize(offsets); ++i) {
205       EXPECT_EQ(offsets[i], parser.m_ObjectInfo[i].pos);
206       EXPECT_EQ(types[i], parser.m_ObjectInfo[i].type);
207     }
208   }
209 }
210