xref: /aosp_15_r20/external/sandboxed-api/oss-internship-2020/libpng/tests/extended_test.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1*ec63e07aSXin Li // Copyright 2020 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li //     https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li 
15*ec63e07aSXin Li #include <fcntl.h>
16*ec63e07aSXin Li #include <unistd.h>
17*ec63e07aSXin Li 
18*ec63e07aSXin Li #include "../sandboxed.h"  // NOLINT(build/include)
19*ec63e07aSXin Li #include "helper.h"        // NOLINT(build/include)
20*ec63e07aSXin Li #include "libpng.h"        // NOLINT(build/include)
21*ec63e07aSXin Li #include "gtest/gtest.h"
22*ec63e07aSXin Li #include "sandboxed_api/util/status_matchers.h"
23*ec63e07aSXin Li 
24*ec63e07aSXin Li namespace {
25*ec63e07aSXin Li 
26*ec63e07aSXin Li using ::sapi::IsOk;
27*ec63e07aSXin Li using ::testing::ContainerEq;
28*ec63e07aSXin Li using ::testing::Eq;
29*ec63e07aSXin Li using ::testing::Ge;
30*ec63e07aSXin Li using ::testing::Gt;
31*ec63e07aSXin Li using ::testing::IsTrue;
32*ec63e07aSXin Li using ::testing::NotNull;
33*ec63e07aSXin Li 
34*ec63e07aSXin Li struct Data {
35*ec63e07aSXin Li   int width;
36*ec63e07aSXin Li   int height;
37*ec63e07aSXin Li   uint8_t color_type;
38*ec63e07aSXin Li   uint8_t bit_depth;
39*ec63e07aSXin Li   int number_of_passes;
40*ec63e07aSXin Li   size_t rowbytes;
41*ec63e07aSXin Li   std::unique_ptr<sapi::v::Array<uint8_t>> row_pointers;
42*ec63e07aSXin Li };
43*ec63e07aSXin Li 
ReadPng(LibPNGApi & api,absl::string_view infile,Data & data)44*ec63e07aSXin Li void ReadPng(LibPNGApi& api, absl::string_view infile, Data& data) {
45*ec63e07aSXin Li   sapi::v::Fd fd(open(infile.data(), O_RDONLY));
46*ec63e07aSXin Li 
47*ec63e07aSXin Li   ASSERT_THAT(fd.GetValue(), Ge(0)) << "Error opening input file";
48*ec63e07aSXin Li   ASSERT_THAT((&api)->sandbox()->TransferToSandboxee(&fd), IsOk());
49*ec63e07aSXin Li 
50*ec63e07aSXin Li   ASSERT_THAT(fd.GetRemoteFd(), Ge(0)) << "Error receiving remote FD";
51*ec63e07aSXin Li 
52*ec63e07aSXin Li   sapi::v::ConstCStr rb_var("rb");
53*ec63e07aSXin Li   absl::StatusOr<void*> status_or_file =
54*ec63e07aSXin Li       api.png_fdopen(fd.GetRemoteFd(), rb_var.PtrBefore());
55*ec63e07aSXin Li   ASSERT_THAT(status_or_file, IsOk());
56*ec63e07aSXin Li 
57*ec63e07aSXin Li   sapi::v::RemotePtr file(status_or_file.value());
58*ec63e07aSXin Li   ASSERT_THAT(file.GetValue(), NotNull()) << "Could not open " << infile;
59*ec63e07aSXin Li 
60*ec63e07aSXin Li   sapi::v::Array<char> header(8);
61*ec63e07aSXin Li   ASSERT_THAT(api.png_fread(header.PtrBoth(), 1, header.GetSize(), &file),
62*ec63e07aSXin Li               IsOk());
63*ec63e07aSXin Li 
64*ec63e07aSXin Li   absl::StatusOr<int> status_or_int =
65*ec63e07aSXin Li       api.png_sig_cmp(header.PtrBoth(), 0, header.GetSize());
66*ec63e07aSXin Li   ASSERT_THAT(status_or_int, IsOk());
67*ec63e07aSXin Li   ASSERT_THAT(status_or_int.value(), Eq(0)) << infile << " is not a PNG file";
68*ec63e07aSXin Li 
69*ec63e07aSXin Li   sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING);
70*ec63e07aSXin Li   sapi::v::NullPtr null = sapi::v::NullPtr();
71*ec63e07aSXin Li   absl::StatusOr<png_structp> status_or_png_structp =
72*ec63e07aSXin Li       api.png_create_read_struct_wrapper(ver_string_var.PtrBefore(), &null);
73*ec63e07aSXin Li 
74*ec63e07aSXin Li   ASSERT_THAT(status_or_png_structp, IsOk());
75*ec63e07aSXin Li   sapi::v::RemotePtr struct_ptr(status_or_png_structp.value());
76*ec63e07aSXin Li   ASSERT_THAT(struct_ptr.GetValue(), NotNull())
77*ec63e07aSXin Li       << "png_create_read_struct_wrapper failed";
78*ec63e07aSXin Li 
79*ec63e07aSXin Li   absl::StatusOr<png_infop> status_or_png_infop =
80*ec63e07aSXin Li       api.png_create_info_struct(&struct_ptr);
81*ec63e07aSXin Li 
82*ec63e07aSXin Li   ASSERT_THAT(status_or_png_infop, IsOk());
83*ec63e07aSXin Li   sapi::v::RemotePtr info_ptr(status_or_png_infop.value());
84*ec63e07aSXin Li   ASSERT_THAT(info_ptr.GetValue(), NotNull())
85*ec63e07aSXin Li       << "png_create_info_struct failed";
86*ec63e07aSXin Li 
87*ec63e07aSXin Li   ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk());
88*ec63e07aSXin Li   ASSERT_THAT(api.png_init_io_wrapper(&struct_ptr, &file), IsOk());
89*ec63e07aSXin Li   ASSERT_THAT(api.png_set_sig_bytes(&struct_ptr, header.GetSize()), IsOk());
90*ec63e07aSXin Li   ASSERT_THAT(api.png_read_info(&struct_ptr, &info_ptr), IsOk());
91*ec63e07aSXin Li 
92*ec63e07aSXin Li   status_or_int = api.png_get_image_width(&struct_ptr, &info_ptr);
93*ec63e07aSXin Li   ASSERT_THAT(status_or_int, IsOk());
94*ec63e07aSXin Li   data.width = status_or_int.value();
95*ec63e07aSXin Li   EXPECT_THAT(data.width, Gt(0));
96*ec63e07aSXin Li 
97*ec63e07aSXin Li   status_or_int = api.png_get_image_height(&struct_ptr, &info_ptr);
98*ec63e07aSXin Li   ASSERT_THAT(status_or_int, IsOk());
99*ec63e07aSXin Li   data.height = status_or_int.value();
100*ec63e07aSXin Li   EXPECT_THAT(data.height, Gt(0));
101*ec63e07aSXin Li 
102*ec63e07aSXin Li   absl::StatusOr<uint8_t> status_or_uchar =
103*ec63e07aSXin Li       api.png_get_color_type(&struct_ptr, &info_ptr);
104*ec63e07aSXin Li   ASSERT_THAT(status_or_uchar, IsOk());
105*ec63e07aSXin Li   data.color_type = status_or_uchar.value();
106*ec63e07aSXin Li 
107*ec63e07aSXin Li   status_or_uchar = api.png_get_bit_depth(&struct_ptr, &info_ptr);
108*ec63e07aSXin Li   ASSERT_THAT(status_or_uchar, IsOk());
109*ec63e07aSXin Li   data.bit_depth = status_or_uchar.value();
110*ec63e07aSXin Li 
111*ec63e07aSXin Li   status_or_int = api.png_set_interlace_handling(&struct_ptr);
112*ec63e07aSXin Li   ASSERT_THAT(status_or_int, IsOk());
113*ec63e07aSXin Li   data.number_of_passes = status_or_int.value();
114*ec63e07aSXin Li 
115*ec63e07aSXin Li   ASSERT_THAT(api.png_read_update_info(&struct_ptr, &info_ptr), IsOk());
116*ec63e07aSXin Li   ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk());
117*ec63e07aSXin Li 
118*ec63e07aSXin Li   absl::StatusOr<uint32_t> status_or_uint =
119*ec63e07aSXin Li       api.png_get_rowbytes(&struct_ptr, &info_ptr);
120*ec63e07aSXin Li   ASSERT_THAT(status_or_uint, IsOk());
121*ec63e07aSXin Li   data.rowbytes = status_or_uint.value();
122*ec63e07aSXin Li   EXPECT_THAT(data.rowbytes, Ge(data.width));
123*ec63e07aSXin Li 
124*ec63e07aSXin Li   data.row_pointers =
125*ec63e07aSXin Li       std::make_unique<sapi::v::Array<uint8_t>>(data.height * data.rowbytes);
126*ec63e07aSXin Li 
127*ec63e07aSXin Li   ASSERT_THAT(
128*ec63e07aSXin Li       api.png_read_image_wrapper(&struct_ptr, data.row_pointers->PtrAfter(),
129*ec63e07aSXin Li                                  data.height, data.rowbytes),
130*ec63e07aSXin Li       IsOk());
131*ec63e07aSXin Li 
132*ec63e07aSXin Li   ASSERT_THAT(api.png_fclose(&file), IsOk());
133*ec63e07aSXin Li }
134*ec63e07aSXin Li 
WritePng(LibPNGApi & api,absl::string_view outfile,Data & data)135*ec63e07aSXin Li void WritePng(LibPNGApi& api, absl::string_view outfile, Data& data) {
136*ec63e07aSXin Li   sapi::v::Fd fd(open(outfile.data(), O_WRONLY));
137*ec63e07aSXin Li 
138*ec63e07aSXin Li   ASSERT_THAT(fd.GetValue(), Ge(0)) << "Error opening output file";
139*ec63e07aSXin Li   ASSERT_THAT((&api)->sandbox()->TransferToSandboxee(&fd), IsOk());
140*ec63e07aSXin Li 
141*ec63e07aSXin Li   ASSERT_THAT(fd.GetRemoteFd(), Ge(0)) << "Error receiving remote FD";
142*ec63e07aSXin Li 
143*ec63e07aSXin Li   sapi::v::ConstCStr wb_var("wb");
144*ec63e07aSXin Li   absl::StatusOr<void*> status_or_file =
145*ec63e07aSXin Li       api.png_fdopen(fd.GetRemoteFd(), wb_var.PtrBefore());
146*ec63e07aSXin Li   ASSERT_THAT(status_or_file, IsOk());
147*ec63e07aSXin Li 
148*ec63e07aSXin Li   sapi::v::RemotePtr file(status_or_file.value());
149*ec63e07aSXin Li   ASSERT_THAT(file.GetValue(), NotNull()) << "Could not open " << outfile;
150*ec63e07aSXin Li 
151*ec63e07aSXin Li   sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING);
152*ec63e07aSXin Li   sapi::v::NullPtr null = sapi::v::NullPtr();
153*ec63e07aSXin Li   absl::StatusOr<png_structp> status_or_png_structp =
154*ec63e07aSXin Li       api.png_create_write_struct_wrapper(ver_string_var.PtrBefore(), &null);
155*ec63e07aSXin Li   ASSERT_THAT(status_or_png_structp, IsOk());
156*ec63e07aSXin Li 
157*ec63e07aSXin Li   sapi::v::RemotePtr struct_ptr(status_or_png_structp.value());
158*ec63e07aSXin Li   ASSERT_THAT(struct_ptr.GetValue(), NotNull())
159*ec63e07aSXin Li       << "png_create_write_struct_wrapper failed";
160*ec63e07aSXin Li 
161*ec63e07aSXin Li   absl::StatusOr<png_infop> status_or_png_infop =
162*ec63e07aSXin Li       api.png_create_info_struct(&struct_ptr);
163*ec63e07aSXin Li   ASSERT_THAT(status_or_png_infop, IsOk());
164*ec63e07aSXin Li 
165*ec63e07aSXin Li   sapi::v::RemotePtr info_ptr(status_or_png_infop.value());
166*ec63e07aSXin Li   ASSERT_THAT(info_ptr.GetValue(), NotNull())
167*ec63e07aSXin Li       << "png_create_info_struct failed";
168*ec63e07aSXin Li 
169*ec63e07aSXin Li   ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk());
170*ec63e07aSXin Li   ASSERT_THAT(api.png_init_io_wrapper(&struct_ptr, &file), IsOk());
171*ec63e07aSXin Li 
172*ec63e07aSXin Li   ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk());
173*ec63e07aSXin Li   ASSERT_THAT(
174*ec63e07aSXin Li       api.png_set_IHDR(&struct_ptr, &info_ptr, data.width, data.height,
175*ec63e07aSXin Li                        data.bit_depth, data.color_type, PNG_INTERLACE_NONE,
176*ec63e07aSXin Li                        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE),
177*ec63e07aSXin Li       IsOk());
178*ec63e07aSXin Li 
179*ec63e07aSXin Li   ASSERT_THAT(api.png_write_info(&struct_ptr, &info_ptr), IsOk());
180*ec63e07aSXin Li 
181*ec63e07aSXin Li   ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk());
182*ec63e07aSXin Li   ASSERT_THAT(
183*ec63e07aSXin Li       api.png_write_image_wrapper(&struct_ptr, data.row_pointers->PtrBefore(),
184*ec63e07aSXin Li                                   data.height, data.rowbytes),
185*ec63e07aSXin Li       IsOk());
186*ec63e07aSXin Li 
187*ec63e07aSXin Li   ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk());
188*ec63e07aSXin Li   ASSERT_THAT(api.png_write_end(&struct_ptr, &null), IsOk());
189*ec63e07aSXin Li 
190*ec63e07aSXin Li   ASSERT_THAT(api.png_fclose(&file), IsOk());
191*ec63e07aSXin Li }
192*ec63e07aSXin Li 
TEST(SandboxTest,ReadModifyWrite)193*ec63e07aSXin Li TEST(SandboxTest, ReadModifyWrite) {
194*ec63e07aSXin Li   std::string infile = GetFilePath("red_ball.png");
195*ec63e07aSXin Li   std::string outfile = GetFilePath("test_output.png");
196*ec63e07aSXin Li 
197*ec63e07aSXin Li   LibPNGSapiSandbox sandbox;
198*ec63e07aSXin Li   ASSERT_THAT(sandbox.Init(), IsOk());
199*ec63e07aSXin Li   LibPNGApi api(&sandbox);
200*ec63e07aSXin Li 
201*ec63e07aSXin Li   Data data;
202*ec63e07aSXin Li   ReadPng(api, infile, data);
203*ec63e07aSXin Li 
204*ec63e07aSXin Li   ASSERT_THAT(data.color_type == PNG_COLOR_TYPE_RGBA ||
205*ec63e07aSXin Li                   data.color_type == PNG_COLOR_TYPE_RGB,
206*ec63e07aSXin Li               IsTrue())
207*ec63e07aSXin Li       << infile << " has unexpected color type. Expected RGB or RGBA";
208*ec63e07aSXin Li 
209*ec63e07aSXin Li   size_t channel_count = 3;
210*ec63e07aSXin Li   if (data.color_type == PNG_COLOR_TYPE_RGBA) {
211*ec63e07aSXin Li     channel_count = 4;
212*ec63e07aSXin Li   }
213*ec63e07aSXin Li 
214*ec63e07aSXin Li   EXPECT_THAT(channel_count * data.width, Eq(data.rowbytes));
215*ec63e07aSXin Li 
216*ec63e07aSXin Li   // RGB to BGR
217*ec63e07aSXin Li   for (size_t i = 0; i != data.height; ++i) {
218*ec63e07aSXin Li     for (size_t j = 0; j != data.width; ++j) {
219*ec63e07aSXin Li       uint8_t r = (*data.row_pointers)[i * data.rowbytes + j * channel_count];
220*ec63e07aSXin Li       uint8_t b =
221*ec63e07aSXin Li           (*data.row_pointers)[i * data.rowbytes + j * channel_count + 2];
222*ec63e07aSXin Li       (*data.row_pointers)[i * data.rowbytes + j * channel_count] = b;
223*ec63e07aSXin Li       (*data.row_pointers)[i * data.rowbytes + j * channel_count + 2] = r;
224*ec63e07aSXin Li     }
225*ec63e07aSXin Li   }
226*ec63e07aSXin Li 
227*ec63e07aSXin Li   WritePng(api, outfile, data);
228*ec63e07aSXin Li 
229*ec63e07aSXin Li   Data result;
230*ec63e07aSXin Li   ReadPng(api, outfile, result);
231*ec63e07aSXin Li 
232*ec63e07aSXin Li   EXPECT_THAT(result.height, Eq(data.height));
233*ec63e07aSXin Li   EXPECT_THAT(result.width, Eq(data.width));
234*ec63e07aSXin Li   EXPECT_THAT(result.color_type, Eq(data.color_type));
235*ec63e07aSXin Li   EXPECT_THAT(result.rowbytes, Eq(data.rowbytes));
236*ec63e07aSXin Li   EXPECT_THAT(result.bit_depth, Eq(data.bit_depth));
237*ec63e07aSXin Li   EXPECT_THAT(result.number_of_passes, Eq(data.number_of_passes));
238*ec63e07aSXin Li   EXPECT_THAT(absl::MakeSpan(result.row_pointers->GetData(),
239*ec63e07aSXin Li                              result.row_pointers->GetSize()),
240*ec63e07aSXin Li               ContainerEq(absl::MakeSpan(data.row_pointers->GetData(),
241*ec63e07aSXin Li                                          data.row_pointers->GetSize())));
242*ec63e07aSXin Li }
243*ec63e07aSXin Li 
244*ec63e07aSXin Li }  // namespace
245