xref: /aosp_15_r20/external/sandboxed-api/oss-internship-2020/libpng/examples/example2.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 "../tests/libpng.h"  // NOLINT(build/include)
20*ec63e07aSXin Li 
21*ec63e07aSXin Li struct Data {
22*ec63e07aSXin Li   int width;
23*ec63e07aSXin Li   int height;
24*ec63e07aSXin Li   uint8_t color_type;
25*ec63e07aSXin Li   uint8_t bit_depth;
26*ec63e07aSXin Li   int number_of_passes;
27*ec63e07aSXin Li   size_t rowbytes;
28*ec63e07aSXin Li   std::unique_ptr<sapi::v::Array<uint8_t>> row_pointers;
29*ec63e07aSXin Li };
30*ec63e07aSXin Li 
ReadPng(LibPNGApi & api,absl::string_view infile)31*ec63e07aSXin Li absl::StatusOr<Data> ReadPng(LibPNGApi& api, absl::string_view infile) {
32*ec63e07aSXin Li   sapi::v::Fd fd(open(infile.data(), O_RDONLY));
33*ec63e07aSXin Li 
34*ec63e07aSXin Li   if (fd.GetValue() < 0) {
35*ec63e07aSXin Li     return absl::InternalError("Error opening input file");
36*ec63e07aSXin Li   }
37*ec63e07aSXin Li 
38*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR((&api)->sandbox()->TransferToSandboxee(&fd));
39*ec63e07aSXin Li 
40*ec63e07aSXin Li   if (fd.GetRemoteFd() < 0) {
41*ec63e07aSXin Li     return absl::InternalError("Error receiving remote FD");
42*ec63e07aSXin Li   }
43*ec63e07aSXin Li 
44*ec63e07aSXin Li   absl::StatusOr<void*> status_or_file;
45*ec63e07aSXin Li   sapi::v::ConstCStr rb_var("rb");
46*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(status_or_file,
47*ec63e07aSXin Li                         api.png_fdopen(fd.GetRemoteFd(), rb_var.PtrBefore()));
48*ec63e07aSXin Li 
49*ec63e07aSXin Li   sapi::v::RemotePtr file(status_or_file.value());
50*ec63e07aSXin Li   if (!file.GetValue()) {
51*ec63e07aSXin Li     return absl::InternalError(absl::StrCat("Could not open ", infile));
52*ec63e07aSXin Li   }
53*ec63e07aSXin Li 
54*ec63e07aSXin Li   sapi::v::Array<char> header(8);
55*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(
56*ec63e07aSXin Li       api.png_fread(header.PtrBoth(), 1, header.GetSize(), &file));
57*ec63e07aSXin Li 
58*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(int return_value,
59*ec63e07aSXin Li                         api.png_sig_cmp(header.PtrBoth(), 0, header.GetSize()));
60*ec63e07aSXin Li   if (return_value != 0) {
61*ec63e07aSXin Li     return absl::InternalError(absl::StrCat(infile, " is not a PNG file"));
62*ec63e07aSXin Li   }
63*ec63e07aSXin Li 
64*ec63e07aSXin Li   absl::StatusOr<png_structp> status_or_png_structp;
65*ec63e07aSXin Li   sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING);
66*ec63e07aSXin Li   sapi::v::NullPtr null = sapi::v::NullPtr();
67*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(
68*ec63e07aSXin Li       status_or_png_structp,
69*ec63e07aSXin Li       api.png_create_read_struct_wrapper(ver_string_var.PtrBefore(), &null));
70*ec63e07aSXin Li 
71*ec63e07aSXin Li   sapi::v::RemotePtr struct_ptr(status_or_png_structp.value());
72*ec63e07aSXin Li   if (!struct_ptr.GetValue()) {
73*ec63e07aSXin Li     return absl::InternalError("png_create_read_struct_wrapper failed");
74*ec63e07aSXin Li   }
75*ec63e07aSXin Li 
76*ec63e07aSXin Li   absl::StatusOr<png_infop> status_or_png_infop;
77*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(status_or_png_infop,
78*ec63e07aSXin Li                         api.png_create_info_struct(&struct_ptr));
79*ec63e07aSXin Li 
80*ec63e07aSXin Li   sapi::v::RemotePtr info_ptr(status_or_png_infop.value());
81*ec63e07aSXin Li   if (!info_ptr.GetValue()) {
82*ec63e07aSXin Li     return absl::InternalError("png_create_info_struct failed");
83*ec63e07aSXin Li   }
84*ec63e07aSXin Li 
85*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
86*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_init_io_wrapper(&struct_ptr, &file));
87*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_set_sig_bytes(&struct_ptr, header.GetSize()));
88*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_read_info(&struct_ptr, &info_ptr));
89*ec63e07aSXin Li 
90*ec63e07aSXin Li   Data data;
91*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(data.width,
92*ec63e07aSXin Li                         api.png_get_image_width(&struct_ptr, &info_ptr));
93*ec63e07aSXin Li 
94*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(data.height,
95*ec63e07aSXin Li                         api.png_get_image_height(&struct_ptr, &info_ptr));
96*ec63e07aSXin Li 
97*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(data.color_type,
98*ec63e07aSXin Li                         api.png_get_color_type(&struct_ptr, &info_ptr));
99*ec63e07aSXin Li 
100*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(data.bit_depth,
101*ec63e07aSXin Li                         api.png_get_bit_depth(&struct_ptr, &info_ptr));
102*ec63e07aSXin Li 
103*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(data.number_of_passes,
104*ec63e07aSXin Li                         api.png_set_interlace_handling(&struct_ptr));
105*ec63e07aSXin Li 
106*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_read_update_info(&struct_ptr, &info_ptr));
107*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
108*ec63e07aSXin Li 
109*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(data.rowbytes,
110*ec63e07aSXin Li                         api.png_get_rowbytes(&struct_ptr, &info_ptr));
111*ec63e07aSXin Li   data.row_pointers =
112*ec63e07aSXin Li       std::make_unique<sapi::v::Array<uint8_t>>(data.height * data.rowbytes);
113*ec63e07aSXin Li 
114*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_read_image_wrapper(
115*ec63e07aSXin Li       &struct_ptr, data.row_pointers->PtrAfter(), data.height, data.rowbytes));
116*ec63e07aSXin Li 
117*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_fclose(&file));
118*ec63e07aSXin Li   return data;
119*ec63e07aSXin Li }
120*ec63e07aSXin Li 
WritePng(LibPNGApi & api,absl::string_view outfile,Data & data)121*ec63e07aSXin Li absl::Status WritePng(LibPNGApi& api, absl::string_view outfile, Data& data) {
122*ec63e07aSXin Li   sapi::v::Fd fd(open(outfile.data(), O_WRONLY));
123*ec63e07aSXin Li   if (fd.GetValue() < 0) {
124*ec63e07aSXin Li     return absl::InternalError("Error opening output file");
125*ec63e07aSXin Li   }
126*ec63e07aSXin Li 
127*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR((&api)->sandbox()->TransferToSandboxee(&fd));
128*ec63e07aSXin Li   if (fd.GetRemoteFd() < 0) {
129*ec63e07aSXin Li     return absl::InternalError("Error receiving remote FD");
130*ec63e07aSXin Li   }
131*ec63e07aSXin Li 
132*ec63e07aSXin Li   absl::StatusOr<void*> status_or_file;
133*ec63e07aSXin Li   sapi::v::ConstCStr wb_var("wb");
134*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(status_or_file,
135*ec63e07aSXin Li                         api.png_fdopen(fd.GetRemoteFd(), wb_var.PtrBefore()));
136*ec63e07aSXin Li 
137*ec63e07aSXin Li   sapi::v::RemotePtr file(status_or_file.value());
138*ec63e07aSXin Li   if (!file.GetValue()) {
139*ec63e07aSXin Li     return absl::InternalError(absl::StrCat("Could not open ", outfile));
140*ec63e07aSXin Li   }
141*ec63e07aSXin Li 
142*ec63e07aSXin Li   absl::StatusOr<png_structp> status_or_png_structp;
143*ec63e07aSXin Li   sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING);
144*ec63e07aSXin Li   sapi::v::NullPtr null = sapi::v::NullPtr();
145*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(
146*ec63e07aSXin Li       status_or_png_structp,
147*ec63e07aSXin Li       api.png_create_write_struct_wrapper(ver_string_var.PtrBefore(), &null));
148*ec63e07aSXin Li 
149*ec63e07aSXin Li   sapi::v::RemotePtr struct_ptr(status_or_png_structp.value());
150*ec63e07aSXin Li   if (!struct_ptr.GetValue()) {
151*ec63e07aSXin Li     return absl::InternalError("png_create_write_struct_wrapper failed");
152*ec63e07aSXin Li   }
153*ec63e07aSXin Li 
154*ec63e07aSXin Li   absl::StatusOr<png_infop> status_or_png_infop;
155*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(status_or_png_infop,
156*ec63e07aSXin Li                         api.png_create_info_struct(&struct_ptr));
157*ec63e07aSXin Li 
158*ec63e07aSXin Li   sapi::v::RemotePtr info_ptr(status_or_png_infop.value());
159*ec63e07aSXin Li   if (!info_ptr.GetValue()) {
160*ec63e07aSXin Li     return absl::InternalError("png_create_info_struct failed");
161*ec63e07aSXin Li   }
162*ec63e07aSXin Li 
163*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
164*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_init_io_wrapper(&struct_ptr, &file));
165*ec63e07aSXin Li 
166*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
167*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(
168*ec63e07aSXin Li       api.png_set_IHDR(&struct_ptr, &info_ptr, data.width, data.height,
169*ec63e07aSXin Li                        data.bit_depth, data.color_type, PNG_INTERLACE_NONE,
170*ec63e07aSXin Li                        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE));
171*ec63e07aSXin Li 
172*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_write_info(&struct_ptr, &info_ptr));
173*ec63e07aSXin Li 
174*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
175*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_write_image_wrapper(
176*ec63e07aSXin Li       &struct_ptr, data.row_pointers->PtrBefore(), data.height, data.rowbytes));
177*ec63e07aSXin Li 
178*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr));
179*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_write_end(&struct_ptr, &null));
180*ec63e07aSXin Li 
181*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(api.png_fclose(&file));
182*ec63e07aSXin Li   return absl::OkStatus();
183*ec63e07aSXin Li }
184*ec63e07aSXin Li 
LibPNGMain(const std::string & infile,const std::string & outfile)185*ec63e07aSXin Li absl::Status LibPNGMain(const std::string& infile, const std::string& outfile) {
186*ec63e07aSXin Li   LibPNGSapiSandbox sandbox;
187*ec63e07aSXin Li   sandbox.AddFile(infile);
188*ec63e07aSXin Li   sandbox.AddFile(outfile);
189*ec63e07aSXin Li 
190*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(sandbox.Init());
191*ec63e07aSXin Li   LibPNGApi api(&sandbox);
192*ec63e07aSXin Li 
193*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(Data data, ReadPng(api, infile));
194*ec63e07aSXin Li 
195*ec63e07aSXin Li   if (data.color_type != PNG_COLOR_TYPE_RGBA &&
196*ec63e07aSXin Li       data.color_type != PNG_COLOR_TYPE_RGB) {
197*ec63e07aSXin Li     return absl::InternalError(absl::StrCat(
198*ec63e07aSXin Li         infile, " has unexpected color type. Expected RGB or RGBA"));
199*ec63e07aSXin Li   }
200*ec63e07aSXin Li 
201*ec63e07aSXin Li   size_t channel_count = 3;
202*ec63e07aSXin Li   if (data.color_type == PNG_COLOR_TYPE_RGBA) {
203*ec63e07aSXin Li     channel_count = 4;
204*ec63e07aSXin Li   }
205*ec63e07aSXin Li 
206*ec63e07aSXin Li   // RGB to BGR
207*ec63e07aSXin Li   for (size_t i = 0; i != data.height; ++i) {
208*ec63e07aSXin Li     for (size_t j = 0; j != data.width; ++j) {
209*ec63e07aSXin Li       uint8_t r = (*data.row_pointers)[i * data.rowbytes + j * channel_count];
210*ec63e07aSXin Li       uint8_t g =
211*ec63e07aSXin Li           (*data.row_pointers)[i * data.rowbytes + j * channel_count + 1];
212*ec63e07aSXin Li       uint8_t b =
213*ec63e07aSXin Li           (*data.row_pointers)[i * data.rowbytes + j * channel_count + 2];
214*ec63e07aSXin Li       (*data.row_pointers)[i * data.rowbytes + j * channel_count] = b;
215*ec63e07aSXin Li       (*data.row_pointers)[i * data.rowbytes + j * channel_count + 2] = r;
216*ec63e07aSXin Li     }
217*ec63e07aSXin Li   }
218*ec63e07aSXin Li 
219*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(WritePng(api, outfile, data));
220*ec63e07aSXin Li   return absl::OkStatus();
221*ec63e07aSXin Li }
222*ec63e07aSXin Li 
main(int argc,char * argv[])223*ec63e07aSXin Li int main(int argc, char* argv[]) {
224*ec63e07aSXin Li   if (argc != 3) {
225*ec63e07aSXin Li     LOG(ERROR) << "Usage: example5 infile outfile";
226*ec63e07aSXin Li     return EXIT_FAILURE;
227*ec63e07aSXin Li   }
228*ec63e07aSXin Li 
229*ec63e07aSXin Li   auto status = LibPNGMain(argv[1], argv[2]);
230*ec63e07aSXin Li   if (!status.ok()) {
231*ec63e07aSXin Li     LOG(ERROR) << "LibPNGMain failed with error:\n"
232*ec63e07aSXin Li                << status.ToString() << '\n';
233*ec63e07aSXin Li     return EXIT_FAILURE;
234*ec63e07aSXin Li   }
235*ec63e07aSXin Li 
236*ec63e07aSXin Li   return EXIT_SUCCESS;
237*ec63e07aSXin Li }
238