diff --git a/oss-internship-2020/libpng/CMakeLists.txt b/oss-internship-2020/libpng/CMakeLists.txt new file mode 100644 index 0000000..5d8e01f --- /dev/null +++ b/oss-internship-2020/libpng/CMakeLists.txt @@ -0,0 +1,112 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.12) + +project(sandboxed_libpng CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +# Set this on the command-line +set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree") +# To obtain a full SAPI_ROOT check out its source separately: +# git clone https://github.com/google/sandboxed-api.git /path/to/sapi_root +# Then configure: +# mkdir -p build && cd build +# cmake .. -G Ninja -DSAPI_ROOT=/path/to/sapi_root + +option(LIBPNG_SAPI_ENABLE_EXAMPLES "" OFF) +option(LIBPNG_SAPI_ENABLE_TESTS "" OFF) + +set(SAPI_ENABLE_EXAMPLES ${LIBPNG_SAPI_ENABLE_EXAMPLES} CACHE BOOL "" FORCE) +set(SAPI_ENABLE_TESTS ${LIBPNG_SAPI_ENABLE_TESTS} CACHE BOOL "" FORCE) + +set (CMAKE_FIND_LIBRARY_SUFFIXES .a $ {CMAKE_FIND_LIBRARY_SUFFIXES}) +find_package(PNG REQUIRED) +list(GET PNG_INCLUDE_DIRS 0 PNG_INCLUDE_DIR) + +add_subdirectory(wrapper) + +add_subdirectory( + "${SAPI_ROOT}" + "${CMAKE_BINARY_DIR}/sandboxed-api-build" + # Omit this to have the full Sandboxed API in IDE + EXCLUDE_FROM_ALL +) + +add_sapi_library(libpng_sapi + # List of functions that we want to include in the + # generated sandboxed API class + + FUNCTIONS png_image_free + png_image_finish_read + png_image_write_to_file + png_image_begin_read_from_file + + png_get_rowbytes + png_get_bit_depth + png_get_color_type + png_get_image_width + png_get_image_height + + png_set_IHDR + png_set_sig_bytes + png_set_interlace_handling + + png_read_info + png_read_image_wrapper + png_read_update_info + + png_write_end + png_write_info + png_write_image_wrapper + + png_create_info_struct + png_create_read_struct_wrapper + png_create_write_struct_wrapper + + png_init_io_wrapper + + png_sig_cmp + + png_fread + png_fdopen + png_rewind + png_fclose + + png_setjmp + + INPUTS "${PNG_INCLUDE_DIR}/png.h" + wrapper/func.h + # Header files or .cc files that should be parsed + LIBRARY wrapper + # Library dependency from the add_library() above + LIBRARY_NAME LibPNG # Name prefix for the generated header. Will be + # suffixed with "Api" and "Sandbox" as needed. + NAMESPACE "" # Optional C++ namespace to wrap the generated code +) + +target_include_directories(libpng_sapi INTERFACE + "${PROJECT_BINARY_DIR}" # To find the generated SAPI header +) + +if (LIBPNG_SAPI_ENABLE_EXAMPLES) + add_subdirectory(examples) +endif() + +if (LIBPNG_SAPI_ENABLE_TESTS) + add_subdirectory(tests) +endif() + diff --git a/oss-internship-2020/libpng/README.md b/oss-internship-2020/libpng/README.md new file mode 100644 index 0000000..e69de29 diff --git a/oss-internship-2020/libpng/examples/CMakeLists.txt b/oss-internship-2020/libpng/examples/CMakeLists.txt new file mode 100644 index 0000000..1206e87 --- /dev/null +++ b/oss-internship-2020/libpng/examples/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_executable(pngtopng + example1.cc + ../tests/libpng.h + ../sandboxed.h +) + +find_package(PNG REQUIRED) + +target_link_libraries(pngtopng PRIVATE + sapi::sapi + sandbox2::temp_file + libpng_sapi + "${PNG_LIBRARY}" +) + +target_include_directories(pngtopng INTERFACE + "${PNG_INCLUDE_DIR}" +) + + +add_executable(rgbtobgr + example2.cc + ../tests/libpng.h + ../sandboxed.h +) + +target_link_libraries(rgbtobgr PRIVATE + sapi::sapi + sandbox2::temp_file + libpng_sapi + "${PNG_LIBRARY}" +) + +target_include_directories(rgbtobgr INTERFACE + "${PNG_INCLUDE_DIR}" +) + diff --git a/oss-internship-2020/libpng/examples/example1.cc b/oss-internship-2020/libpng/examples/example1.cc new file mode 100644 index 0000000..49b7ff5 --- /dev/null +++ b/oss-internship-2020/libpng/examples/example1.cc @@ -0,0 +1,90 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "../sandboxed.h" // NOLINT(build/include) +#include "../tests/libpng.h" // NOLINT(build/include) +#include "sandboxed_api/vars.h" + +absl::Status LibPNGMain(const std::string& infile, const std::string& outfile) { + LibPNGSapiSandbox sandbox; + sandbox.AddFile(infile); + sandbox.AddFile(outfile); + + SAPI_RETURN_IF_ERROR(sandbox.Init()); + LibPNGApi api(&sandbox); + + sapi::v::Struct image; + sapi::v::ConstCStr infile_var(infile.c_str()); + sapi::v::ConstCStr outfile_var(outfile.c_str()); + + image.mutable_data()->version = PNG_IMAGE_VERSION; + + SAPI_ASSIGN_OR_RETURN( + int result, api.png_image_begin_read_from_file(image.PtrBoth(), + infile_var.PtrBefore())); + if (!result) { + return absl::InternalError( + absl::StrCat("begin read error: ", image.mutable_data()->message)); + } + + image.mutable_data()->format = PNG_FORMAT_RGBA; + + auto buffer = malloc(PNG_IMAGE_SIZE(*image.mutable_data())); + if (!buffer) { + SAPI_RETURN_IF_ERROR(api.png_image_free(image.PtrBoth())); + return absl::OkStatus(); + } + + free(buffer); + sapi::v::Array buffer_(PNG_IMAGE_SIZE(*image.mutable_data())); + + SAPI_ASSIGN_OR_RETURN( + result, api.png_image_finish_read( + image.PtrBoth(), sapi::v::NullPtr().PtrBoth(), + buffer_.PtrBoth(), 0, sapi::v::NullPtr().PtrBoth())); + if (!result) { + return absl::InternalError( + absl::StrCat("finish read error: ", image.mutable_data()->message)); + } + + SAPI_ASSIGN_OR_RETURN( + result, api.png_image_write_to_file( + image.PtrBoth(), outfile_var.PtrBefore(), 0, + buffer_.PtrBoth(), 0, sapi::v::NullPtr().PtrBoth())); + if (!result) { + return absl::InternalError( + absl::StrCat("write error: ", image.mutable_data()->message)); + } + + return absl::OkStatus(); +} + +int main(int argc, const char** argv) { + if (argc != 3) { + LOG(ERROR) << "usage: example input-file output-file"; + return EXIT_FAILURE; + } + + auto status = LibPNGMain(argv[1], argv[2]); + if (!status.ok()) { + LOG(ERROR) << "LibPNGMain failed with error:\n" + << status.ToString() << '\n'; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/oss-internship-2020/libpng/examples/example2.cc b/oss-internship-2020/libpng/examples/example2.cc new file mode 100644 index 0000000..b791f69 --- /dev/null +++ b/oss-internship-2020/libpng/examples/example2.cc @@ -0,0 +1,239 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "../sandboxed.h" // NOLINT(build/include) +#include "../tests/libpng.h" // NOLINT(build/include) + +struct Data { + Data() {} + + int width; + int height; + uint8_t color_type; + uint8_t bit_depth; + int number_of_passes; + size_t rowbytes; + std::unique_ptr> row_pointers; +}; + +absl::Status ReadPng(LibPNGApi& api, LibPNGSapiSandbox& sandbox, + absl::string_view infile, Data& d) { + sapi::v::Fd fd(open(infile.data(), O_RDONLY)); + + if (fd.GetValue() < 0) { + return absl::InternalError("Error opening input file"); + } + + SAPI_RETURN_IF_ERROR(sandbox.TransferToSandboxee(&fd)); + if (fd.GetRemoteFd() < 0) { + return absl::InternalError("Error receiving remote FD"); + } + + absl::StatusOr status_or_file; + sapi::v::ConstCStr rb_var("rb"); + SAPI_ASSIGN_OR_RETURN(status_or_file, + api.png_fdopen(fd.GetRemoteFd(), rb_var.PtrBefore())); + + sapi::v::RemotePtr file(status_or_file.value()); + if (!file.GetValue()) { + return absl::InternalError(absl::StrCat("Could not open ", infile)); + } + + sapi::v::Array header(8); + SAPI_RETURN_IF_ERROR( + api.png_fread(header.PtrBoth(), 1, header.GetSize(), &file)); + + SAPI_ASSIGN_OR_RETURN(int return_value, + api.png_sig_cmp(header.PtrBoth(), 0, header.GetSize())); + if (return_value != 0) { + return absl::InternalError(absl::StrCat(infile, " is not a PNG file")); + } + + absl::StatusOr status_or_png_structp; + sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING); + SAPI_ASSIGN_OR_RETURN( + status_or_png_structp, + api.png_create_read_struct_wrapper(ver_string_var.PtrBefore(), + sapi::v::NullPtr().PtrBoth())); + + sapi::v::RemotePtr struct_ptr(status_or_png_structp.value()); + if (!struct_ptr.GetValue()) { + return absl::InternalError("png_create_read_struct_wrapper failed"); + } + + absl::StatusOr status_or_png_infop; + SAPI_ASSIGN_OR_RETURN(status_or_png_infop, + api.png_create_info_struct(&struct_ptr)); + + sapi::v::RemotePtr info_ptr(status_or_png_infop.value()); + if (!info_ptr.GetValue()) { + return absl::InternalError("png_create_info_struct failed"); + } + + SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr)); + SAPI_RETURN_IF_ERROR(api.png_init_io_wrapper(&struct_ptr, &file)); + SAPI_RETURN_IF_ERROR(api.png_set_sig_bytes(&struct_ptr, header.GetSize())); + SAPI_RETURN_IF_ERROR(api.png_read_info(&struct_ptr, &info_ptr)); + + SAPI_ASSIGN_OR_RETURN(d.width, + api.png_get_image_width(&struct_ptr, &info_ptr)); + + SAPI_ASSIGN_OR_RETURN(d.height, + api.png_get_image_height(&struct_ptr, &info_ptr)); + + SAPI_ASSIGN_OR_RETURN(d.color_type, + api.png_get_color_type(&struct_ptr, &info_ptr)); + + SAPI_ASSIGN_OR_RETURN(d.bit_depth, + api.png_get_bit_depth(&struct_ptr, &info_ptr)); + + SAPI_ASSIGN_OR_RETURN(d.number_of_passes, + api.png_set_interlace_handling(&struct_ptr)); + + SAPI_RETURN_IF_ERROR(api.png_read_update_info(&struct_ptr, &info_ptr)); + SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr)); + + SAPI_ASSIGN_OR_RETURN(d.rowbytes, + api.png_get_rowbytes(&struct_ptr, &info_ptr)); + d.row_pointers = + std::make_unique>(d.height * d.rowbytes); + + SAPI_RETURN_IF_ERROR(api.png_read_image_wrapper( + &struct_ptr, d.row_pointers->PtrAfter(), d.height, d.rowbytes)); + + SAPI_RETURN_IF_ERROR(api.png_fclose(&file)); + return absl::OkStatus(); +} + +absl::Status WritePng(LibPNGApi& api, LibPNGSapiSandbox& sandbox, + absl::string_view outfile, Data& d) { + sapi::v::Fd fd(open(outfile.data(), O_WRONLY)); + if (fd.GetValue() < 0) { + return absl::InternalError("Error opening output file"); + } + + SAPI_RETURN_IF_ERROR(sandbox.TransferToSandboxee(&fd)); + if (fd.GetRemoteFd() < 0) { + return absl::InternalError("Error receiving remote FD"); + } + + absl::StatusOr status_or_file; + sapi::v::ConstCStr wb_var("wb"); + SAPI_ASSIGN_OR_RETURN(status_or_file, + api.png_fdopen(fd.GetRemoteFd(), wb_var.PtrBefore())); + + sapi::v::RemotePtr file(status_or_file.value()); + if (!file.GetValue()) { + return absl::InternalError(absl::StrCat("Could not open ", outfile)); + } + + absl::StatusOr status_or_png_structp; + sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING); + SAPI_ASSIGN_OR_RETURN( + status_or_png_structp, + api.png_create_write_struct_wrapper(ver_string_var.PtrBefore(), + sapi::v::NullPtr().PtrBoth())); + + sapi::v::RemotePtr struct_ptr(status_or_png_structp.value()); + if (!struct_ptr.GetValue()) { + return absl::InternalError("png_create_write_struct_wrapper failed"); + } + + absl::StatusOr status_or_png_infop; + SAPI_ASSIGN_OR_RETURN(status_or_png_infop, + api.png_create_info_struct(&struct_ptr)); + + sapi::v::RemotePtr info_ptr(status_or_png_infop.value()); + if (!info_ptr.GetValue()) { + return absl::InternalError("png_create_info_struct failed"); + } + + SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr)); + SAPI_RETURN_IF_ERROR(api.png_init_io_wrapper(&struct_ptr, &file)); + + SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr)); + SAPI_RETURN_IF_ERROR(api.png_set_IHDR( + &struct_ptr, &info_ptr, d.width, d.height, d.bit_depth, d.color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE)); + + SAPI_RETURN_IF_ERROR(api.png_write_info(&struct_ptr, &info_ptr)); + + SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr)); + SAPI_RETURN_IF_ERROR(api.png_write_image_wrapper( + &struct_ptr, d.row_pointers->PtrBefore(), d.height, d.rowbytes)); + + auto null = sapi::v::NullPtr(); + SAPI_RETURN_IF_ERROR(api.png_setjmp(&struct_ptr)); + SAPI_RETURN_IF_ERROR(api.png_write_end(&struct_ptr, &null)); + + SAPI_RETURN_IF_ERROR(api.png_fclose(&file)); + return absl::OkStatus(); +} + +absl::Status LibPNGMain(const std::string& infile, const std::string& outfile) { + LibPNGSapiSandbox sandbox; + sandbox.AddFile(infile); + sandbox.AddFile(outfile); + + SAPI_RETURN_IF_ERROR(sandbox.Init()); + LibPNGApi api(&sandbox); + + Data d; + SAPI_RETURN_IF_ERROR(ReadPng(api, sandbox, infile, d)); + + if (d.color_type != PNG_COLOR_TYPE_RGBA && + d.color_type != PNG_COLOR_TYPE_RGB) { + return absl::InternalError(absl::StrCat( + infile, " has unexpected color type. Expected RGB or RGBA")); + } + + size_t channel_count = 3; + if (d.color_type == PNG_COLOR_TYPE_RGBA) { + channel_count = 4; + } + + // RGB to BGR + for (size_t i = 0; i != d.height; ++i) { + for (size_t j = 0; j != d.width; ++j) { + uint8_t r = (*d.row_pointers)[i * d.rowbytes + j * channel_count]; + uint8_t g = (*d.row_pointers)[i * d.rowbytes + j * channel_count + 1]; + uint8_t b = (*d.row_pointers)[i * d.rowbytes + j * channel_count + 2]; + (*d.row_pointers)[i * d.rowbytes + j * channel_count] = b; + (*d.row_pointers)[i * d.rowbytes + j * channel_count + 2] = r; + } + } + + SAPI_RETURN_IF_ERROR(WritePng(api, sandbox, outfile, d)); + return absl::OkStatus(); +} + +int main(int argc, const char** argv) { + if (argc != 3) { + LOG(ERROR) << "Usage: example5 infile outfile"; + return EXIT_FAILURE; + } + + auto status = LibPNGMain(argv[1], argv[2]); + if (!status.ok()) { + LOG(ERROR) << "LibPNGMain failed with error:\n" + << status.ToString() << '\n'; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/oss-internship-2020/libpng/images/pngtest.png b/oss-internship-2020/libpng/images/pngtest.png new file mode 100644 index 0000000..66df0c4 Binary files /dev/null and b/oss-internship-2020/libpng/images/pngtest.png differ diff --git a/oss-internship-2020/libpng/images/pngtopng_pngtest.png b/oss-internship-2020/libpng/images/pngtopng_pngtest.png new file mode 100644 index 0000000..86e065f Binary files /dev/null and b/oss-internship-2020/libpng/images/pngtopng_pngtest.png differ diff --git a/oss-internship-2020/libpng/images/red_ball.png b/oss-internship-2020/libpng/images/red_ball.png new file mode 100644 index 0000000..ed3586d Binary files /dev/null and b/oss-internship-2020/libpng/images/red_ball.png differ diff --git a/oss-internship-2020/libpng/images/rgbtobgr_red_ball.png b/oss-internship-2020/libpng/images/rgbtobgr_red_ball.png new file mode 100644 index 0000000..eeb216f Binary files /dev/null and b/oss-internship-2020/libpng/images/rgbtobgr_red_ball.png differ diff --git a/oss-internship-2020/libpng/images/test_output.png b/oss-internship-2020/libpng/images/test_output.png new file mode 100644 index 0000000..a7bb30d Binary files /dev/null and b/oss-internship-2020/libpng/images/test_output.png differ diff --git a/oss-internship-2020/libpng/sandboxed.h b/oss-internship-2020/libpng/sandboxed.h new file mode 100644 index 0000000..12e8585 --- /dev/null +++ b/oss-internship-2020/libpng/sandboxed.h @@ -0,0 +1,64 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include + +#include "libpng_sapi.sapi.h" + +namespace { + +class LibPNGSapiSandbox : public LibPNGSandbox { + public: + void AddFile(const std::string& file) { files_.push_back(file); } + + private: + std::unique_ptr ModifyPolicy( + sandbox2::PolicyBuilder*) override { + auto builder = std::make_unique(); + (*builder) + .AllowRead() + .AllowStaticStartup() + .AllowWrite() + .AllowOpen() + .AllowExit() + .AllowStat() + .AllowMmap() + .AllowSystemMalloc() + .AllowSyscalls({ + __NR_futex, + __NR_close, + __NR_lseek, + __NR_gettid, + __NR_sysinfo, + __NR_munmap, + __NR_recvmsg, + __NR_fcntl, + }); + + for (const auto& file : files_) { + builder->AddFile(file, /*is_ro=*/false); + } + + return builder.get()->BuildOrDie(); + } + + std::vector files_; +}; + +} // namespace + diff --git a/oss-internship-2020/libpng/tests/CMakeLists.txt b/oss-internship-2020/libpng/tests/CMakeLists.txt new file mode 100644 index 0000000..0cb2645 --- /dev/null +++ b/oss-internship-2020/libpng/tests/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +include(GoogleTest) +enable_testing() + +add_executable(tests + basic_test.cc + extended_test.cc + helper.h + helper.cc + libpng.h +) + +target_link_libraries(tests PRIVATE + gmock + gtest + gtest_main + sandbox2::temp_file + sapi::sapi + libpng_sapi +) + +gtest_discover_tests(tests) + diff --git a/oss-internship-2020/libpng/tests/basic_test.cc b/oss-internship-2020/libpng/tests/basic_test.cc new file mode 100644 index 0000000..cc22561 --- /dev/null +++ b/oss-internship-2020/libpng/tests/basic_test.cc @@ -0,0 +1,91 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "../sandboxed.h" // NOLINT(build/include) +#include "gtest/gtest.h" +#include "helper.h" // NOLINT(build/include) +#include "libpng.h" // NOLINT(build/include) +#include "sandboxed_api/sandbox2/util/fileops.h" +#include "sandboxed_api/sandbox2/util/path.h" +#include "sandboxed_api/sandbox2/util/temp_file.h" +#include "sandboxed_api/util/status_matchers.h" + +namespace { + +using ::sapi::IsOk; +using ::testing::Eq; +using ::testing::IsTrue; + +TEST(SandboxTest, ReadWrite) { + std::string infile = GetTestFilePath("pngtest.png"); + + absl::StatusOr status_or_path = + sandbox2::CreateNamedTempFileAndClose("output.png"); + ASSERT_THAT(status_or_path, IsOk()) << "Could not create temp output file"; + + std::string outfile = sandbox2::file::JoinPath( + sandbox2::file_util::fileops::GetCWD(), status_or_path.value()); + + LibPNGSapiSandbox sandbox; + sandbox.AddFile(infile); + sandbox.AddFile(outfile); + + ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API"; + + LibPNGApi api(&sandbox); + + sapi::v::Struct image; + sapi::v::ConstCStr infile_var(infile.c_str()); + sapi::v::ConstCStr outfile_var(outfile.c_str()); + + image.mutable_data()->version = PNG_IMAGE_VERSION; + + absl::StatusOr status_or_int = api.png_image_begin_read_from_file( + image.PtrBoth(), infile_var.PtrBefore()); + ASSERT_THAT(status_or_int, IsOk()) + << "png_image_begin_read_from_file fatal error"; + ASSERT_THAT(status_or_int.value(), IsTrue()) + << "png_image_begin_read_from_file failed: " + << image.mutable_data()->message; + + image.mutable_data()->format = PNG_FORMAT_RGBA; + ASSERT_THAT(image.mutable_data()->version, Eq(PNG_IMAGE_VERSION)) + << "image version changed"; + + sapi::v::Array buffer_(PNG_IMAGE_SIZE(*image.mutable_data())); + status_or_int = api.png_image_finish_read( + image.PtrBoth(), sapi::v::NullPtr().PtrBoth(), buffer_.PtrBoth(), 0, + sapi::v::NullPtr().PtrBoth()); + ASSERT_THAT(status_or_int, IsOk()) << "png_image_finish_read fatal error"; + ASSERT_THAT(status_or_int.value(), IsTrue()) + << "png_image_finish_read failed: " << image.mutable_data()->message; + ASSERT_THAT(image.mutable_data()->version, Eq(PNG_IMAGE_VERSION)) + << "image version changed"; + ASSERT_THAT(image.mutable_data()->format, Eq(PNG_FORMAT_RGBA)) + << "image format changed"; + + status_or_int = api.png_image_write_to_file( + image.PtrBoth(), outfile_var.PtrBefore(), 0, buffer_.PtrBoth(), 0, + sapi::v::NullPtr().PtrBoth()); + ASSERT_THAT(status_or_int, IsOk()) << "png_image_write_to_file fatal error"; + ASSERT_THAT(status_or_int.value(), IsTrue()) + << "png_image_finish_read failed: " << image.mutable_data()->message; + ASSERT_THAT(image.mutable_data()->version, Eq(PNG_IMAGE_VERSION)) + << "image version changed"; + ASSERT_THAT(image.mutable_data()->format, Eq(PNG_FORMAT_RGBA)) + << "image format changed"; +} + +} // namespace + diff --git a/oss-internship-2020/libpng/tests/extended_test.cc b/oss-internship-2020/libpng/tests/extended_test.cc new file mode 100644 index 0000000..78c04ab --- /dev/null +++ b/oss-internship-2020/libpng/tests/extended_test.cc @@ -0,0 +1,248 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "../sandboxed.h" // NOLINT(build/include) +#include "gtest/gtest.h" +#include "helper.h" // NOLINT(build/include) +#include "libpng.h" // NOLINT(build/include) +#include "sandboxed_api/util/status_matchers.h" + +namespace { + +using ::sapi::IsOk; +using ::testing::ContainerEq; +using ::testing::Eq; +using ::testing::Ge; +using ::testing::Gt; +using ::testing::IsTrue; +using ::testing::NotNull; + +struct Data { + Data() {} + + int width; + int height; + uint8_t color_type; + uint8_t bit_depth; + int number_of_passes; + size_t rowbytes; + std::unique_ptr> row_pointers; +}; + +void ReadPng(LibPNGApi& api, LibPNGSapiSandbox& sandbox, + absl::string_view infile, Data& data) { + sapi::v::Fd fd(open(infile.data(), O_RDONLY)); + + ASSERT_THAT(fd.GetValue(), Ge(0)) << "Error opening input file"; + ASSERT_THAT(sandbox.TransferToSandboxee(&fd), IsOk()); + ASSERT_THAT(fd.GetRemoteFd(), Ge(0)) << "Error receiving remote FD"; + + sapi::v::ConstCStr rb_var("rb"); + absl::StatusOr status_or_file = + api.png_fdopen(fd.GetRemoteFd(), rb_var.PtrBefore()); + ASSERT_THAT(status_or_file, IsOk()); + + sapi::v::RemotePtr file(status_or_file.value()); + ASSERT_THAT(file.GetValue(), NotNull()) << "Could not open " << infile; + + sapi::v::Array header(8); + ASSERT_THAT(api.png_fread(header.PtrBoth(), 1, header.GetSize(), &file), + IsOk()); + + absl::StatusOr status_or_int = + api.png_sig_cmp(header.PtrBoth(), 0, header.GetSize()); + ASSERT_THAT(status_or_int, IsOk()); + ASSERT_THAT(status_or_int.value(), Eq(0)) << infile << " is not a PNG file"; + + sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING); + absl::StatusOr status_or_png_structp = + api.png_create_read_struct_wrapper(ver_string_var.PtrBefore(), + sapi::v::NullPtr().PtrBoth()); + + ASSERT_THAT(status_or_png_structp, IsOk()); + sapi::v::RemotePtr struct_ptr(status_or_png_structp.value()); + ASSERT_THAT(struct_ptr.GetValue(), NotNull()) + << "png_create_read_struct_wrapper failed"; + + absl::StatusOr status_or_png_infop = + api.png_create_info_struct(&struct_ptr); + + ASSERT_THAT(status_or_png_infop, IsOk()); + sapi::v::RemotePtr info_ptr(status_or_png_infop.value()); + ASSERT_THAT(info_ptr.GetValue(), NotNull()) + << "png_create_info_struct failed"; + + ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk()); + ASSERT_THAT(api.png_init_io_wrapper(&struct_ptr, &file), IsOk()); + ASSERT_THAT(api.png_set_sig_bytes(&struct_ptr, header.GetSize()), IsOk()); + ASSERT_THAT(api.png_read_info(&struct_ptr, &info_ptr), IsOk()); + + status_or_int = api.png_get_image_width(&struct_ptr, &info_ptr); + ASSERT_THAT(status_or_int, IsOk()); + data.width = status_or_int.value(); + EXPECT_THAT(data.width, Gt(0)); + + status_or_int = api.png_get_image_height(&struct_ptr, &info_ptr); + ASSERT_THAT(status_or_int, IsOk()); + data.height = status_or_int.value(); + EXPECT_THAT(data.height, Gt(0)); + + absl::StatusOr status_or_uchar = + api.png_get_color_type(&struct_ptr, &info_ptr); + ASSERT_THAT(status_or_uchar, IsOk()); + data.color_type = status_or_uchar.value(); + + status_or_uchar = api.png_get_bit_depth(&struct_ptr, &info_ptr); + ASSERT_THAT(status_or_uchar, IsOk()); + data.bit_depth = status_or_uchar.value(); + + status_or_int = api.png_set_interlace_handling(&struct_ptr); + ASSERT_THAT(status_or_int, IsOk()); + data.number_of_passes = status_or_int.value(); + + ASSERT_THAT(api.png_read_update_info(&struct_ptr, &info_ptr), IsOk()); + ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk()); + + absl::StatusOr status_or_uint = + api.png_get_rowbytes(&struct_ptr, &info_ptr); + ASSERT_THAT(status_or_uint, IsOk()); + data.rowbytes = status_or_uint.value(); + EXPECT_THAT(data.rowbytes, Ge(data.width)); + + data.row_pointers = + std::make_unique>(data.height * data.rowbytes); + + ASSERT_THAT( + api.png_read_image_wrapper(&struct_ptr, data.row_pointers->PtrAfter(), + data.height, data.rowbytes), + IsOk()); + + ASSERT_THAT(api.png_fclose(&file), IsOk()); +} + +void WritePng(LibPNGApi& api, LibPNGSapiSandbox& sandbox, + absl::string_view outfile, Data& data) { + sapi::v::Fd fd(open(outfile.data(), O_WRONLY)); + + ASSERT_THAT(fd.GetValue(), Ge(0)) << "Error opening output file"; + ASSERT_THAT(sandbox.TransferToSandboxee(&fd), IsOk()); + ASSERT_THAT(fd.GetRemoteFd(), Ge(0)) << "Error receiving remote FD"; + + sapi::v::ConstCStr wb_var("wb"); + absl::StatusOr status_or_file = + api.png_fdopen(fd.GetRemoteFd(), wb_var.PtrBefore()); + ASSERT_THAT(status_or_file, IsOk()); + + sapi::v::RemotePtr file(status_or_file.value()); + ASSERT_THAT(file.GetValue(), NotNull()) << "Could not open " << outfile; + + sapi::v::ConstCStr ver_string_var(PNG_LIBPNG_VER_STRING); + absl::StatusOr status_or_png_structp = + api.png_create_write_struct_wrapper(ver_string_var.PtrBefore(), + sapi::v::NullPtr().PtrBoth()); + ASSERT_THAT(status_or_png_structp, IsOk()); + + sapi::v::RemotePtr struct_ptr(status_or_png_structp.value()); + ASSERT_THAT(struct_ptr.GetValue(), NotNull()) + << "png_create_write_struct_wrapper failed"; + + absl::StatusOr status_or_png_infop = + api.png_create_info_struct(&struct_ptr); + ASSERT_THAT(status_or_png_infop, IsOk()); + + sapi::v::RemotePtr info_ptr(status_or_png_infop.value()); + ASSERT_THAT(info_ptr.GetValue(), NotNull()) + << "png_create_info_struct failed"; + + ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk()); + ASSERT_THAT(api.png_init_io_wrapper(&struct_ptr, &file), IsOk()); + + ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk()); + ASSERT_THAT( + api.png_set_IHDR(&struct_ptr, &info_ptr, data.width, data.height, + data.bit_depth, data.color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE), + IsOk()); + + ASSERT_THAT(api.png_write_info(&struct_ptr, &info_ptr), IsOk()); + + ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk()); + ASSERT_THAT( + api.png_write_image_wrapper(&struct_ptr, data.row_pointers->PtrBefore(), + data.height, data.rowbytes), + IsOk()); + + auto null = sapi::v::NullPtr(); + ASSERT_THAT(api.png_setjmp(&struct_ptr), IsOk()); + ASSERT_THAT(api.png_write_end(&struct_ptr, &null), IsOk()); + + ASSERT_THAT(api.png_fclose(&file), IsOk()); +} + +TEST(SandboxTest, ReadModifyWrite) { + std::string infile = GetTestFilePath("red_ball.png"); + std::string outfile = GetTestFilePath("test_output.png"); + + LibPNGSapiSandbox sandbox; + ASSERT_THAT(sandbox.Init(), IsOk()); + LibPNGApi api(&sandbox); + + Data data; + ReadPng(api, sandbox, infile, data); + + ASSERT_THAT(data.color_type == PNG_COLOR_TYPE_RGBA || + data.color_type == PNG_COLOR_TYPE_RGB, + IsTrue()) + << infile << " has unexpected color type. Expected RGB or RGBA"; + + size_t channel_count = 3; + if (data.color_type == PNG_COLOR_TYPE_RGBA) { + channel_count = 4; + } + + EXPECT_THAT(channel_count * data.width, Eq(data.rowbytes)); + + // RGB to BGR + for (size_t i = 0; i != data.height; ++i) { + for (size_t j = 0; j != data.width; ++j) { + uint8_t r = (*data.row_pointers)[i * data.rowbytes + j * channel_count]; + uint8_t b = + (*data.row_pointers)[i * data.rowbytes + j * channel_count + 2]; + (*data.row_pointers)[i * data.rowbytes + j * channel_count] = b; + (*data.row_pointers)[i * data.rowbytes + j * channel_count + 2] = r; + } + } + + WritePng(api, sandbox, outfile, data); + + Data result; + ReadPng(api, sandbox, outfile, result); + + EXPECT_THAT(result.height, Eq(data.height)); + EXPECT_THAT(result.width, Eq(data.width)); + EXPECT_THAT(result.color_type, Eq(data.color_type)); + EXPECT_THAT(result.rowbytes, Eq(data.rowbytes)); + EXPECT_THAT(result.bit_depth, Eq(data.bit_depth)); + EXPECT_THAT(result.number_of_passes, Eq(data.number_of_passes)); + EXPECT_THAT(absl::MakeSpan(result.row_pointers->GetData(), + result.row_pointers->GetSize()), + ContainerEq(absl::MakeSpan(data.row_pointers->GetData(), + data.row_pointers->GetSize()))); +} + +} // namespace + diff --git a/oss-internship-2020/libpng/tests/helper.cc b/oss-internship-2020/libpng/tests/helper.cc new file mode 100644 index 0000000..b349c6b --- /dev/null +++ b/oss-internship-2020/libpng/tests/helper.cc @@ -0,0 +1,40 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "helper.h" // NOLINT(build/include) +#include "../sandboxed.h" // NOLINT(build/include) +#include "sandboxed_api/sandbox2/util/fileops.h" +#include "sandboxed_api/sandbox2/util/path.h" + +std::string GetImagesFolder() { + std::string cwd = sandbox2::file_util::fileops::GetCWD(); + auto find = cwd.rfind("/build"); + if (find == std::string::npos) { + LOG(ERROR) << "Something went wrong: CWD don't contain build dir. " + << "Please run tests from build dir, path might be incorrect\n"; + + return sandbox2::file::JoinPath(cwd, "images"); + } + + return sandbox2::file::JoinPath(cwd.substr(0, find), "images"); +} + +std::string GetTestFilePath(const std::string& filename) { + static std::string* images_folder_path = nullptr; + if (!images_folder_path) { + images_folder_path = new std::string(GetImagesFolder()); + } + return sandbox2::file::JoinPath(*images_folder_path, filename); +} + diff --git a/oss-internship-2020/libpng/tests/helper.h b/oss-internship-2020/libpng/tests/helper.h new file mode 100644 index 0000000..9590f61 --- /dev/null +++ b/oss-internship-2020/libpng/tests/helper.h @@ -0,0 +1,18 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +std::string GetTestFilePath(const std::string& filename); + diff --git a/oss-internship-2020/libpng/tests/libpng.h b/oss-internship-2020/libpng/tests/libpng.h new file mode 100644 index 0000000..6727eb5 --- /dev/null +++ b/oss-internship-2020/libpng/tests/libpng.h @@ -0,0 +1,92 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Defines from libpng library. The problem is that the build throws the error +// "Duplicate functions" if #include was added. + +#define PNG_FORMAT_FLAG_ALPHA 0x01U +#define PNG_FORMAT_FLAG_COLOR 0x02U +#define PNG_FORMAT_FLAG_LINEAR 0x04U +#define PNG_FORMAT_FLAG_COLORMAP 0x08U + +#ifdef PNG_FORMAT_BGR_SUPPORTED +#define PNG_FORMAT_FLAG_BGR 0x10U +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +#define PNG_FORMAT_FLAG_AFIRST 0x20U +#endif + +#define PNG_FORMAT_FLAG_ASSOCIATED_ALPHA 0x40U + +#define PNG_FORMAT_GRAY 0 +#define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA +#define PNG_FORMAT_AG (PNG_FORMAT_GA | PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR +#define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_BGR) +#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB | PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA | PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR | PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA | PNG_FORMAT_FLAG_AFIRST) + +#define PNG_IMAGE_VERSION 1 + +#define PNG_IMAGE_PIXEL_(test, fmt) \ + (((fmt)&PNG_FORMAT_FLAG_COLORMAP) ? 1 : test(fmt)) + +#define PNG_IMAGE_SAMPLE_CHANNELS(fmt) \ + (((fmt) & (PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_ALPHA)) + 1) + +#define PNG_IMAGE_PIXEL_CHANNELS(fmt) \ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS, fmt) + +#define PNG_IMAGE_ROW_STRIDE(image) \ + (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width) + +#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt) \ + ((((fmt)&PNG_FORMAT_FLAG_LINEAR) >> 2) + 1) + +#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt) \ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE, fmt) + +#define PNG_IMAGE_BUFFER_SIZE(image, row_stride) \ + (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format) * (image).height * \ + (row_stride)) + +#define PNG_IMAGE_SIZE(image) \ + PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image)) + +typedef uint8_t *png_bytep; + +#if UINT_MAX == 65535 +typedef unsigned int png_uint_16; +#elif USHRT_MAX == 65535 +typedef unsigned short png_uint_16; +#else +#error "libpng requires an unsigned 16-bit type" +#endif + +#define PNG_LIBPNG_VER_STRING "1.6.38.git" + +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA + +#define PNG_FILTER_TYPE_BASE 0 +#define PNG_COMPRESSION_TYPE_BASE 0 +#define PNG_INTERLACE_NONE 0 + diff --git a/oss-internship-2020/libpng/wrapper/CMakeLists.txt b/oss-internship-2020/libpng/wrapper/CMakeLists.txt new file mode 100644 index 0000000..aba420a --- /dev/null +++ b/oss-internship-2020/libpng/wrapper/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_library(wrapper OBJECT + func.h + func.cc +) + +set_target_properties(wrapper + PROPERTIES LINKER_LANGUAGE C +) + +target_link_libraries(wrapper + sandbox2::temp_file + sapi::sapi + PNG::PNG +) diff --git a/oss-internship-2020/libpng/wrapper/func.cc b/oss-internship-2020/libpng/wrapper/func.cc new file mode 100644 index 0000000..c8630b6 --- /dev/null +++ b/oss-internship-2020/libpng/wrapper/func.cc @@ -0,0 +1,57 @@ +#include "func.h" // NOLINT(build/include) + +#include + +void png_setjmp(png_structrp ptr) { setjmp(png_jmpbuf(ptr)); } + +void* png_fdopen(int fd, const char* mode) { + FILE* f = fdopen(fd, mode); + return static_cast(f); +} + +void png_rewind(void* f) { rewind(static_cast(f)); } + +void png_fread(void* buffer, size_t size, size_t count, void* stream) { + fread(buffer, size, count, static_cast(stream)); +} + +void png_fclose(void* f) { fclose(static_cast(f)); } + +void png_init_io_wrapper(png_structrp png_ptr, void* f) { + png_init_io(png_ptr, static_cast(f)); +} + +png_structp png_create_read_struct_wrapper(png_const_charp user_png_ver, + png_voidp error_ptr) { + return png_create_read_struct(user_png_ver, error_ptr, NULL, NULL); +} + +png_structp png_create_write_struct_wrapper(png_const_charp user_png_ver, + png_voidp error_ptr) { + return png_create_write_struct(user_png_ver, error_ptr, NULL, NULL); +} + +void png_read_image_wrapper(png_structrp png_ptr, png_bytep image, + size_t height, size_t rowbytes) { + png_bytep* ptrs = (png_bytep*)malloc(height * sizeof(png_bytep)); + for (size_t i = 0; i != height; ++i) { + ptrs[i] = image + (i * rowbytes); + } + png_read_image(png_ptr, ptrs); + free(ptrs); +} + +void png_write_image_wrapper(png_structrp png_ptr, png_bytep image, + size_t height, size_t rowbytes) { + png_bytep* ptrs = (png_bytep*)malloc(height * sizeof(png_bytep)); + for (size_t i = 0; i != height; ++i) { + ptrs[i] = image + (i * rowbytes); + } + png_write_image(png_ptr, ptrs); + free(ptrs); +} + +void png_write_end_wrapper(png_structrp png_ptr) { + png_write_end(png_ptr, NULL); +} + diff --git a/oss-internship-2020/libpng/wrapper/func.h b/oss-internship-2020/libpng/wrapper/func.h new file mode 100644 index 0000000..2233f74 --- /dev/null +++ b/oss-internship-2020/libpng/wrapper/func.h @@ -0,0 +1,24 @@ +#ifndef LIBPNG_WRAPPER_FUNC_H +#define LIBPNG_WRAPPER_FUNC_H + +#include "png.h" + +extern "C" { +void* png_fdopen(int fd, const char* mode); +void png_rewind(void* f); +void png_fread(void* buffer, size_t size, size_t count, void* stream); +void png_fclose(void* f); +void png_setjmp(png_structrp ptr); +png_structp png_create_read_struct_wrapper(png_const_charp user_png_ver, + png_voidp error_ptr); +png_structp png_create_write_struct_wrapper(png_const_charp user_png_ver, + png_voidp error_ptr); +void png_init_io_wrapper(png_structrp png_ptr, void* f); +void png_read_image_wrapper(png_structrp png_ptr, png_bytep image, + size_t height, size_t rowbytes); +void png_write_image_wrapper(png_structrp png_ptr, png_bytep image, + size_t height, size_t rowbytes); +void png_write_end_wrapper(png_structrp png_ptr); +} +#endif +