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