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