From 673154e65c549cff9a0a0e354150b809749e9f51 Mon Sep 17 00:00:00 2001 From: Alexandra Latysheva Date: Wed, 23 Sep 2020 20:21:33 +0000 Subject: [PATCH] from local repo to fork --- .gitmodules | 3 + oss-internship-2020/libtiff/.gitignore | 2 + oss-internship-2020/libtiff/CMakeLists.txt | 129 +++++++ oss-internship-2020/libtiff/README.md | 22 ++ .../libtiff/example/CMakeLists.txt | 24 ++ .../libtiff/example/main_sandboxed.cc | 279 +++++++++++++++ oss-internship-2020/libtiff/sandboxed.h | 68 ++++ .../libtiff/test/CMakeLists.txt | 37 ++ oss-internship-2020/libtiff/test/check_tag.cc | 63 ++++ oss-internship-2020/libtiff/test/check_tag.h | 24 ++ .../libtiff/test/defer_strile_writing.cc | 322 ++++++++++++++++++ oss-internship-2020/libtiff/test/helper.cc | 51 +++ oss-internship-2020/libtiff/test/helper.h | 35 ++ .../libtiff/test/images/quad-tile.jpg.tiff | Bin 0 -> 27576 bytes oss-internship-2020/libtiff/test/long_tag.cc | 135 ++++++++ .../libtiff/test/raw_decode.cc | 198 +++++++++++ oss-internship-2020/libtiff/test/short_tag.cc | 170 +++++++++ .../libtiff/wrapper/CMakeLists.txt | 29 ++ oss-internship-2020/libtiff/wrapper/func.cc | 163 +++++++++ oss-internship-2020/libtiff/wrapper/func.h | 86 +++++ oss-internship-2020/libtiff/wrapper/libtiff | 1 + 21 files changed, 1841 insertions(+) create mode 100644 oss-internship-2020/libtiff/.gitignore create mode 100644 oss-internship-2020/libtiff/CMakeLists.txt create mode 100644 oss-internship-2020/libtiff/README.md create mode 100644 oss-internship-2020/libtiff/example/CMakeLists.txt create mode 100644 oss-internship-2020/libtiff/example/main_sandboxed.cc create mode 100644 oss-internship-2020/libtiff/sandboxed.h create mode 100644 oss-internship-2020/libtiff/test/CMakeLists.txt create mode 100644 oss-internship-2020/libtiff/test/check_tag.cc create mode 100644 oss-internship-2020/libtiff/test/check_tag.h create mode 100644 oss-internship-2020/libtiff/test/defer_strile_writing.cc create mode 100644 oss-internship-2020/libtiff/test/helper.cc create mode 100644 oss-internship-2020/libtiff/test/helper.h create mode 100644 oss-internship-2020/libtiff/test/images/quad-tile.jpg.tiff create mode 100644 oss-internship-2020/libtiff/test/long_tag.cc create mode 100644 oss-internship-2020/libtiff/test/raw_decode.cc create mode 100644 oss-internship-2020/libtiff/test/short_tag.cc create mode 100644 oss-internship-2020/libtiff/wrapper/CMakeLists.txt create mode 100644 oss-internship-2020/libtiff/wrapper/func.cc create mode 100644 oss-internship-2020/libtiff/wrapper/func.h create mode 160000 oss-internship-2020/libtiff/wrapper/libtiff diff --git a/.gitmodules b/.gitmodules index ad0eddc..3b12082 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "oss-internship-2020/curl/curl_wrapper/curl"] path = oss-internship-2020/curl/curl_wrapper/curl url = https://github.com/curl/curl +[submodule "oss-internship-2020/libtiff/wrapper/libtiff"] + path = oss-internship-2020/libtiff/wrapper/libtiff + url = https://gitlab.com/libtiff/libtiff diff --git a/oss-internship-2020/libtiff/.gitignore b/oss-internship-2020/libtiff/.gitignore new file mode 100644 index 0000000..6f31401 --- /dev/null +++ b/oss-internship-2020/libtiff/.gitignore @@ -0,0 +1,2 @@ +build/ +.vscode/ diff --git a/oss-internship-2020/libtiff/CMakeLists.txt b/oss-internship-2020/libtiff/CMakeLists.txt new file mode 100644 index 0000000..b659fd3 --- /dev/null +++ b/oss-internship-2020/libtiff/CMakeLists.txt @@ -0,0 +1,129 @@ +# 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.10) + +project(sandboxed_libtiff 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 $HOME/sapi_root +# Then configure: +# mkdir -p build && cd build +# cmake .. -G Ninja -DSAPI_ROOT=$HOME/sapi_root + +option(TIFF_SAPI_ENABLE_EXAMPLES "" ON) +option(TIFF_SAPI_ENABLE_TESTS "" ON) + +set(SAPI_ENABLE_EXAMPLES ${TIFF_SAPI_ENABLE_EXAMPLES} CACHE BOOL "" FORCE) +set(SAPI_ENABLE_TESTS ${TIFF_SAPI_ENABLE_TESTS} CACHE BOOL "" FORCE) + +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(tiff_sapi + FUNCTIONS TIFFOpen + TIFFClose + + TIFFGetField1 + TIFFGetField2 + TIFFGetField3 + + TIFFSetFieldUChar1 + TIFFSetFieldUChar2 + TIFFSetFieldUChar3 + TIFFSetFieldSChar1 + TIFFSetFieldSChar2 + TIFFSetFieldSChar3 + TIFFSetFieldU1 + TIFFSetFieldU2 + TIFFSetFieldU3 + TIFFSetFieldS1 + TIFFSetFieldS2 + TIFFSetFieldS3 + TIFFSetFieldUShort1 + TIFFSetFieldUShort2 + TIFFSetFieldUShort3 + TIFFSetFieldSShort1 + TIFFSetFieldSShort2 + TIFFSetFieldSShort3 + TIFFSetFieldULLong1 + TIFFSetFieldULLong2 + TIFFSetFieldULLong3 + TIFFSetFieldSLLong1 + TIFFSetFieldSLLong2 + TIFFSetFieldSLLong3 + TIFFSetFieldFloat1 + TIFFSetFieldFloat2 + TIFFSetFieldFloat3 + TIFFSetFieldDouble1 + TIFFSetFieldDouble2 + TIFFSetFieldDouble3 + + TIFFReadRGBATile + TIFFReadEncodedTile + TIFFReadEncodedStrip + TIFFReadFromUserBuffer + + TIFFTileSize + TIFFSetDirectory + TIFFFreeDirectory + TIFFCreateDirectory + + TIFFForceStrileArrayWriting + TIFFDeferStrileArrayWriting + + TIFFWriteCheck + TIFFWriteScanline + TIFFWriteDirectory + TIFFWriteEncodedTile + TIFFWriteEncodedStrip + + TIFFGetStrileOffsetWithErr + TIFFGetStrileByteCountWithErr + + TIFFCreateEXIFDirectory + TIFFWriteCustomDirectory + # List of functions that we want to include in the + # generated sandboxed API class + INPUTS wrapper/libtiff/libtiff/tiffio.h + wrapper/func.h + # Header files or .cc files that should be parsed + LIBRARY wrapped_tiff # Library dependency from the add_library() above + LIBRARY_NAME Tiff # 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(tiff_sapi INTERFACE + "${PROJECT_BINARY_DIR}" # To find the generated SAPI header +) + +if (TIFF_SAPI_ENABLE_EXAMPLES) + add_subdirectory(example) +endif() + +if (TIFF_SAPI_ENABLE_TESTS) + add_subdirectory(test) +endif() diff --git a/oss-internship-2020/libtiff/README.md b/oss-internship-2020/libtiff/README.md new file mode 100644 index 0000000..4e253db --- /dev/null +++ b/oss-internship-2020/libtiff/README.md @@ -0,0 +1,22 @@ +# sapi-libtiff +Copyright 2020 Google LLC. + +## Start use +You should make sure the libtiff submodule is cloned. + +`git clone --recursive https://github.com/alexelex/sapi-libtiff` + +## Usage + +#### build: +`mkdir -p build && cd build && cmake .. -DSAPI_ROOT=$HOME/sapi_root -DBUILD_SHARED_LIBS=OFF` + +`make -j 8` + +#### to run the sandboxed example: +`./example/sandboxed absolute/path/to/project/dir` + +#### to run tests: +`./test/tests` + +you also can use sandbox flags `sandbox2_danger_danger_permit_all` and `sandbox2_danger_danger_permit_all_and_log` diff --git a/oss-internship-2020/libtiff/example/CMakeLists.txt b/oss-internship-2020/libtiff/example/CMakeLists.txt new file mode 100644 index 0000000..b266071 --- /dev/null +++ b/oss-internship-2020/libtiff/example/CMakeLists.txt @@ -0,0 +1,24 @@ +# 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(sandboxed + main_sandboxed.cc + ../sandboxed.h +) + +target_link_libraries(sandboxed PRIVATE + tiff_sapi + sapi::sapi + sandbox2::temp_file +) diff --git a/oss-internship-2020/libtiff/example/main_sandboxed.cc b/oss-internship-2020/libtiff/example/main_sandboxed.cc new file mode 100644 index 0000000..7d4a370 --- /dev/null +++ b/oss-internship-2020/libtiff/example/main_sandboxed.cc @@ -0,0 +1,279 @@ +// 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 "../sandboxed.h" +#include "sandboxed_api/sandbox2/util/fileops.h" +#include "sandboxed_api/sandbox2/util/path.h" +#include "tiffio.h" + +/* sapi functions: + * TIFFTileSize + * TIFFOpen + * TIFFReadEncodedTile + * TIFFSetField + * TIFFClose + * TIFFReadRGBATile + * TIFFGetField + */ + +static const std::vector cluster_0 = {0, 0, 2, 0, 138, 139}; +static const std::vector cluster_64 = {0, 0, 9, 6, 134, 119}; +static const std::vector cluster_128 = {44, 40, 63, 59, 230, 95}; + +static int check_cluster(int cluster, + const sapi::v::Array &buffer, + const std::vector &expected_cluster) { + unsigned char *target = buffer.GetData() + cluster * 6; + + if (!std::memcmp(target, expected_cluster.data(), 6)) { + return 0; + } + + std::cerr << "Cluster " << cluster << " did not match expected results.\n" + << "Expect: " << expected_cluster[0] << "\t" << expected_cluster[1] + << "\t" << expected_cluster[4] << "\t" << expected_cluster[5] + << "\t" << expected_cluster[2] << "\t" << expected_cluster[3] + << "\n" + << "Got: " << target[0] << "\t" << target[1] << "\t" << target[4] + << "\t" << target[5] << "\t" << target[2] << "\t" << target[3] + << '\n'; + + return 1; +} + +static int check_rgb_pixel(int pixel, int min_red, int max_red, int min_green, + int max_green, int min_blue, int max_blue, + const sapi::v::Array &buffer) { + unsigned char *rgb = buffer.GetData() + 3 * pixel; + + if (rgb[0] >= min_red && rgb[0] <= max_red && rgb[1] >= min_green && + rgb[1] <= max_green && rgb[2] >= min_blue && rgb[2] <= max_blue) { + return 0; + } + + std::cerr << "Pixel " << pixel << " did not match expected results.\n" + << "Got R=" << rgb[0] << " (expected " << min_red << ".." << max_red + << "), G=" << rgb[1] << " (expected " << min_green << ".." + << max_green << "), B=" << rgb[2] << " (expected " << min_blue + << ".." << max_blue << ")\n"; + return 1; +} + +static int check_rgba_pixel(int pixel, int min_red, int max_red, int min_green, + int max_green, int min_blue, int max_blue, + int min_alpha, int max_alpha, + const sapi::v::Array &buffer) { + // RGBA images are upside down - adjust for normal ordering + int adjusted_pixel = pixel % 128 + (127 - (pixel / 128)) * 128; + uint32 rgba = buffer[adjusted_pixel]; + + if (TIFFGetR(rgba) >= (uint32)min_red && TIFFGetR(rgba) <= (uint32)max_red && + TIFFGetG(rgba) >= (uint32)min_green && + TIFFGetG(rgba) <= (uint32)max_green && + TIFFGetB(rgba) >= (uint32)min_blue && + TIFFGetB(rgba) <= (uint32)max_blue && + TIFFGetA(rgba) >= (uint32)min_alpha && + TIFFGetA(rgba) <= (uint32)max_alpha) { + return 0; + } + + std::cerr << "Pixel " << pixel << " did not match expected results.\n" + << "Got R=" << TIFFGetR(rgba) << " (expected " << min_red << ".." + << max_red << "), G=" << TIFFGetG(rgba) << " (expected " + << min_green << ".." << max_green << "), B=" << TIFFGetB(rgba) + << " (expected " << min_blue << ".." << max_blue + << "), A=" << TIFFGetA(rgba) << " (expected " << min_alpha << ".." + << max_alpha << ")\n"; + return 1; +} +std::string GetFilePath(const std::string &dir, const std::string &filename) { + return sandbox2::file::JoinPath(dir, "test", "images", filename); +} + +std::string GetCWD() { + char cwd[PATH_MAX]; + getcwd(cwd, sizeof(cwd)); + return cwd; +} + +std::string GetFilePath(const std::string filename) { + std::string cwd = GetCWD(); + auto find = cwd.rfind("build"); + + std::string project_path; + if (find == std::string::npos) { + std::cerr << "Something went wrong: CWD don't contain build dir. " + << "Please run tests from build dir or send project dir as a " + << "parameter: ./sandboxed /absolute/path/to/project/dir \n"; + project_path = cwd; + } else { + project_path = cwd.substr(0, find); + } + + return sandbox2::file::JoinPath(project_path, "test", "images", filename); +} + +int main(int argc, char **argv) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + + std::string srcfile; + // "test/images/quad-tile.jpg.tiff" + std::string srcfilerel = + "quad-tile.jpg.tiff"; + + if (argc < 2) { + srcfile = GetFilePath(srcfilerel); + } else { + srcfile = GetFilePath(argv[1], srcfilerel); + } + + // without addDir to sandbox. to add dir use + // sandbox(absolute_path_to_dir, srcfile) or + // sandbox(absolute_path_to_dir). file and dir should be exists. + // srcfile must also be absolute_path_to_file + TiffSapiSandbox sandbox("", srcfile); + + // initialize sapi vars after constructing TiffSapiSandbox + sapi::v::UShort h, v; + sapi::StatusOr status_or_tif; + sapi::StatusOr status_or_int; + sapi::StatusOr status_or_long; + + auto status = sandbox.Init(); + if (!status.ok()) { + fprintf(stderr, "Couldn't initialize Sandboxed API: %s\n", status); + } + + TiffApi api(&sandbox); + sapi::v::ConstCStr srcfile_var(srcfile.c_str()); + sapi::v::ConstCStr r_var("r"); + + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore()); + if (!status_or_tif.ok()) { + std::cerr << "Could not open " << srcfile << ", TIFFError\n"; + return 1; + } + + sapi::v::RemotePtr tif(status_or_tif.value()); + if (!tif.GetValue()) { + // tif is NULL + std::cerr << "Could not open " << srcfile << "\n"; + return 1; + } + + status_or_int = api.TIFFGetField2(&tif, TIFFTAG_YCBCRSUBSAMPLING, h.PtrBoth(), + v.PtrBoth()); + if (!status_or_int.ok() || status_or_int.value() == 0 || h.GetValue() != 2 || + v.GetValue() != 2) { + std::cerr << "Could not retrieve subsampling tag\n"; + return 1; + } + + status_or_long = api.TIFFTileSize(&tif); + if (!status_or_int.ok() || status_or_long.value() != 24576) { + std::cerr << "tiles are " << status_or_long.value() << " bytes\n"; + exit(1); + } + tsize_t sz = status_or_long.value(); + + sapi::v::Array buffer_(sz); + status_or_long = api.TIFFReadEncodedTile(&tif, 9, buffer_.PtrBoth(), sz); + if (!status_or_long.ok() || status_or_long.value() != sz) { + std::cerr << "Did not get expected result code from" + << "TIFFReadEncodedTile(): (" << status_or_long.value() + << " instead of " << sz << ")\n"; + return 1; + } + + if (check_cluster(0, buffer_, cluster_0) || + check_cluster(64, buffer_, cluster_64) || + check_cluster(128, buffer_, cluster_128)) { + return 1; + } + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + if (!status_or_int.ok() || !status_or_int.value()) { + std::cerr << "TIFFSetFieldU1 not available\n"; + } + + status_or_long = api.TIFFTileSize(&tif); + if (!status_or_long.ok() || status_or_long.value() != 128 * 128 * 3) { + std::cerr << "tiles are " << status_or_long.value() << " bytes\n"; + return 1; + } + sz = status_or_long.value(); + + sapi::v::Array buffer2_(sz); + + status_or_long = api.TIFFReadEncodedTile(&tif, 9, buffer2_.PtrBoth(), sz); + if (!status_or_long.ok() || status_or_long.value() != sz) { + std::cerr << "Did not get expected result code from " + << "TIFFReadEncodedTile(): (" << status_or_long.value() + << " instead of " << sz << ")\n"; + return 1; + } + + unsigned pixel_status = 0; + pixel_status |= check_rgb_pixel(0, 15, 18, 0, 0, 18, 41, buffer2_); + pixel_status |= check_rgb_pixel(64, 0, 0, 0, 0, 0, 2, buffer2_); + pixel_status |= check_rgb_pixel(512, 5, 6, 34, 36, 182, 196, buffer2_); + + if (!api.TIFFClose(&tif).ok()) { + std::cerr << "TIFFClose error\n"; + } + + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore()); + if (!status_or_tif.ok()) { + std::cerr << "Could not reopen " << srcfile << "\n"; + return 1; + } + + sapi::v::RemotePtr tif2(status_or_tif.value()); + if (!tif2.GetValue()) { // tif is NULL + std::cerr << "Could not reopen " << srcfile << "\n"; + return 1; + } + + sapi::v::Array rgba_buffer_(128 * 128); + + status_or_int = + api.TIFFReadRGBATile(&tif2, 1 * 128, 2 * 128, rgba_buffer_.PtrBoth()); + if (!status_or_int.ok() || !status_or_int.value()) { + fprintf(stderr, "TIFFReadRGBATile() returned failure code.\n"); + return 1; + } + + pixel_status |= + check_rgba_pixel(0, 15, 18, 0, 0, 18, 41, 255, 255, rgba_buffer_); + pixel_status |= + check_rgba_pixel(64, 0, 0, 0, 0, 0, 2, 255, 255, rgba_buffer_); + pixel_status |= + check_rgba_pixel(512, 5, 6, 34, 36, 182, 196, 255, 255, rgba_buffer_); + + if (!api.TIFFClose(&tif2).ok()) { + std::cerr << "TIFFClose erro\n"; + } + + if (pixel_status) { + std::cerr << "pixel_status is true, expected false"; + return 1; + } + + return 0; +} diff --git a/oss-internship-2020/libtiff/sandboxed.h b/oss-internship-2020/libtiff/sandboxed.h new file mode 100644 index 0000000..79f10e1 --- /dev/null +++ b/oss-internship-2020/libtiff/sandboxed.h @@ -0,0 +1,68 @@ +// 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 "sandboxed_api/util/flag.h" +#include "tiff_sapi.sapi.h" + +ABSL_DECLARE_FLAG(string, sandbox2_danger_danger_permit_all); +ABSL_DECLARE_FLAG(string, sandbox2_danger_danger_permit_all_and_log); + +namespace { + +class TiffSapiSandbox : public TiffSandbox { + public: + explicit TiffSapiSandbox(std::string dir = "", std::string file = "") + : dir_(std::move(dir)), file_(std::move(file)) {} + + private: + std::unique_ptr ModifyPolicy( + sandbox2::PolicyBuilder*) override { + auto builder = std::make_unique(); + (*builder) + .AllowRead() + .AllowStaticStartup() + .AllowWrite() + .AllowOpen() + .AllowExit() + .AllowStat() + .AllowSystemMalloc() + .AllowSyscalls({ + __NR_futex, + __NR_close, + __NR_lseek, + __NR_gettid, + __NR_sysinfo, + __NR_mmap, + __NR_munmap, + }); + + if (!dir_.empty()) { + builder->AddDirectory(dir_, /*is_ro=*/false); + } + + if (!file_.empty()) { + builder->AddFile(file_, /*is_ro=*/false); + } + + return builder.get()->BuildOrDie(); + } + + std::string dir_, file_; +}; + +} // namespace \ No newline at end of file diff --git a/oss-internship-2020/libtiff/test/CMakeLists.txt b/oss-internship-2020/libtiff/test/CMakeLists.txt new file mode 100644 index 0000000..b36e65a --- /dev/null +++ b/oss-internship-2020/libtiff/test/CMakeLists.txt @@ -0,0 +1,37 @@ +# 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) + +add_executable(tests + check_tag.h + check_tag.cc + defer_strile_writing.cc + long_tag.cc + raw_decode.cc + short_tag.cc + helper.h + helper.cc +) + +target_link_libraries(tests PRIVATE + tiff_sapi + sapi::sapi + sandbox2::temp_file + gtest + gmock + gtest_main +) + +gtest_discover_tests(tests) diff --git a/oss-internship-2020/libtiff/test/check_tag.cc b/oss-internship-2020/libtiff/test/check_tag.cc new file mode 100644 index 0000000..72240e5 --- /dev/null +++ b/oss-internship-2020/libtiff/test/check_tag.cc @@ -0,0 +1,63 @@ +// 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 "check_tag.h" + +/* sapi functions: + * TIFFGetField + */ + +void CheckShortField(TiffApi& api, sapi::v::RemotePtr& tif, const ttag_t field, + const unsigned short value) { + sapi::v::UShort tmp(123); + sapi::StatusOr status_or_int; + + status_or_int = api.TIFFGetField1(&tif, field, tmp.PtrBoth()); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFGetField1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Problem fetching tag " << field; + EXPECT_THAT(tmp.GetValue(), Eq(value)) + << "Wrong SHORT value fetched for tag " << field; +} + +void CheckShortPairedField(TiffApi& api, sapi::v::RemotePtr& tif, + const ttag_t field, + const std::array& values) { + sapi::v::UShort tmp0(123); + sapi::v::UShort tmp1(456); + sapi::StatusOr status_or_int; + + status_or_int = + api.TIFFGetField2(&tif, field, tmp0.PtrBoth(), tmp1.PtrBoth()); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFGetField2 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Problem fetching tag " << field; + EXPECT_THAT(tmp0.GetValue(), Eq(values[0])) + << "Wrong SHORT PAIR[0] fetched for tag " << field; + EXPECT_THAT(tmp1.GetValue(), Eq(values[1])) + << "Wrong SHORT PAIR[1] fetched for tag " << field; +} + +void CheckLongField(TiffApi& api, sapi::v::RemotePtr& tif, const ttag_t field, + const unsigned value) { + sapi::v::UInt tmp(123); + sapi::StatusOr status_or_int; + + status_or_int = api.TIFFGetField1(&tif, field, tmp.PtrBoth()); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFGetField1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Problem fetching tag " << field; + EXPECT_THAT(tmp.GetValue(), Eq(value)) + << "Wrong LONG value fetched for tag " << field; +} diff --git a/oss-internship-2020/libtiff/test/check_tag.h b/oss-internship-2020/libtiff/test/check_tag.h new file mode 100644 index 0000000..fd48e39 --- /dev/null +++ b/oss-internship-2020/libtiff/test/check_tag.h @@ -0,0 +1,24 @@ +// 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" +#include "tiffio.h" + +void CheckShortField(TiffApi&, sapi::v::RemotePtr& tif, const ttag_t field, + const unsigned short value); +void CheckShortPairedField(TiffApi& api, sapi::v::RemotePtr& tif, + const ttag_t field, + const std::array& values); +void CheckLongField(TiffApi&, sapi::v::RemotePtr& tif, const ttag_t field, + const unsigned value); diff --git a/oss-internship-2020/libtiff/test/defer_strile_writing.cc b/oss-internship-2020/libtiff/test/defer_strile_writing.cc new file mode 100644 index 0000000..3b6af21 --- /dev/null +++ b/oss-internship-2020/libtiff/test/defer_strile_writing.cc @@ -0,0 +1,322 @@ +// 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" +#include "tiffio.h" + +/* sapi functions: + * TIFFOpen + * TIFFClose + * TIFFGetField + * TIFFSetField + * TIFFWriteCheck + * TIFFSetDirectory + * TIFFFreeDirectory + * TIFFWriteScanline + * TIFFWriteDirectory + * TIFFCreateDirectory + * TIFFReadEncodedTile + * TIFFReadEncodedStrip + * TIFFWriteEncodedTile + * TIFFWriteEncodedStrip + * TIFFDeferStrileArrayWriting + * TIFFForceStrileArrayWriting + */ + +#define TBS 256 // kTileBufferSize +static const unsigned short kWidth = 1; +static const unsigned short kBps = 8; +static const unsigned short kRowsPerStrip = 1; +static const unsigned short kSamplePerPixel = 1; + +void test_writing(const char* mode, int tiled, int height) { + sapi::StatusOr status_or_path = + sandbox2::CreateNamedTempFileAndClose("defer_strile_writing.tif"); + ASSERT_THAT(status_or_path, IsOk()) << "Could not create temp file"; + + std::string srcfile = sandbox2::file::JoinPath( + sandbox2::file_util::fileops::GetCWD(), status_or_path.value()); + + sapi::StatusOr status_or_int; + sapi::StatusOr status_or_long; + sapi::StatusOr status_or_tif; + + TiffSapiSandbox sandbox("", srcfile); + ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API"; + + TiffApi api(&sandbox); + sapi::v::ConstCStr srcfile_var(srcfile.c_str()); + sapi::v::ConstCStr mode_var(mode); + + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), mode_var.PtrBefore()); + ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile; + + sapi::v::RemotePtr tif(status_or_tif.value()); + ASSERT_THAT(tif.GetValue(), NotNull()) + << "Can't create test TIFF file " << srcfile; + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set CompressionNone tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGEWIDTH, kWidth); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageWidth tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGELENGTH, height); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageLenght tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_BITSPERSAMPLE, kBps); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set BitsPerSample tag"; + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_SAMPLESPERPIXEL, kSamplePerPixel); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set SamplesPerPixel tag"; + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set PlanarConfiguration tag"; + + if (tiled) { + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_TILEWIDTH, 16); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set TileWidth tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_TILELENGTH, 16); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set TileLenght tag"; + } else { + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_ROWSPERSTRIP, kRowsPerStrip); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set RowsPerStrip tag"; + } + + status_or_int = api.TIFFDeferStrileArrayWriting(&tif); + ASSERT_THAT(status_or_int, IsOk()) + << "TIFFDeferStrileArrayWriting fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFDeferStrileArrayWriting return unexpected value"; + + sapi::v::ConstCStr test_var("test"); + status_or_int = api.TIFFWriteCheck(&tif, tiled, test_var.PtrBefore()); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteCheck fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFWriteCheck return unexpected value " + << "void test(" << mode << ", " << tiled << ", " << height << ")"; + + status_or_int = api.TIFFWriteDirectory(&tif); + ASSERT_THAT(status_or_int, IsOk()) + << "TIFFDeferStrileArrayWriting fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFDeferStrileArrayWriting return unexpected value"; + + /* Create other directory */ + ASSERT_THAT(api.TIFFFreeDirectory(&tif), IsOk()) + << "TIFFFreeDirectory fatal error"; + ASSERT_THAT(api.TIFFCreateDirectory(&tif), IsOk()) + << "TIFFCreateDirectory fatal error"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set SubFileType tag"; + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set CompressionNone tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGEWIDTH, kWidth); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageWidth tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGELENGTH, 1); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageLenght tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_BITSPERSAMPLE, kBps); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set BitsPerSample tag"; + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_SAMPLESPERPIXEL, kSamplePerPixel); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set SamplesPerPixel tag"; + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set PlanarConfiguration tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_ROWSPERSTRIP, kRowsPerStrip); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set RowsPerStrip tag"; + + status_or_int = api.TIFFDeferStrileArrayWriting(&tif); + ASSERT_THAT(status_or_int, IsOk()) + << "TIFFDeferStrileArrayWriting fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFDeferStrileArrayWriting return unexpected value"; + + status_or_int = api.TIFFWriteCheck(&tif, 0, test_var.PtrBefore()); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteCheck fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFWriteCheck return unexpected value"; + + status_or_int = api.TIFFWriteDirectory(&tif); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteDirectory fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFWriteDirectory return unexpected value"; + + /* Force writing of strile arrays */ + status_or_int = api.TIFFSetDirectory(&tif, 0); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetDirectory fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFSetDirectory return unexpected value"; + + status_or_int = api.TIFFForceStrileArrayWriting(&tif); + ASSERT_THAT(status_or_int, IsOk()) + << "TIFFForceStrileArrayWriting fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFForceStrileArrayWriting return unexpected value"; + + status_or_int = api.TIFFSetDirectory(&tif, 1); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetDirectory fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFSetDirectory return unexpected value"; + + status_or_int = api.TIFFForceStrileArrayWriting(&tif); + ASSERT_THAT(status_or_int, IsOk()) + << "TIFFForceStrileArrayWriting fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFForceStrileArrayWriting return unexpected value"; + + /* Now write data on frist directory */ + status_or_int = api.TIFFSetDirectory(&tif, 0); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetDirectory fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFSetDirectory return unexpected value"; + + if (tiled) { + for (int i = 0; i < (height + 15) / 16; ++i) { + std::array tilebuffer; + tilebuffer.fill(i); + sapi::v::Array tilebuffer_(tilebuffer.data(), TBS); + + status_or_int = + api.TIFFWriteEncodedTile(&tif, i, tilebuffer_.PtrBoth(), TBS); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteEncodedTile fatal error"; + EXPECT_THAT(status_or_int.value(), Eq(TBS)) + << "line " << i << ": expected 256, got " << status_or_int.value(); + } + } else { + for (int i = 0; i < height; ++i) { + sapi::v::UChar c(i); + status_or_long = api.TIFFWriteEncodedStrip(&tif, i, c.PtrBoth(), 1); + ASSERT_THAT(status_or_long, IsOk()) + << "TIFFWriteEncodedStrip fatal error"; + EXPECT_THAT(status_or_int.value(), Eq(1)) + << "line " << i << ": expected 1, got " << status_or_int.value(); + + if (i == 1 && height > 100000) { + i = height - 2; + } + } + } + + ASSERT_THAT(api.TIFFClose(&tif), IsOk()) << "TIFFClose fatal error"; + + sapi::v::ConstCStr r_var("r"); + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore()); + ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile; + + sapi::v::RemotePtr tif2(status_or_tif.value()); + ASSERT_THAT(tif2.GetValue(), NotNull()) << "can't open " << srcfile; + + if (tiled) { + for (int i = 0; i < (height + 15) / 16; ++i) { + for (int retry = 0; retry < 2; ++retry) { + std::array tilebuffer; + unsigned char expected_c = (unsigned char)i; + tilebuffer.fill(0); + + sapi::v::Array tilebuffer_(tilebuffer.data(), TBS); + status_or_long = + api.TIFFReadEncodedTile(&tif2, i, tilebuffer_.PtrBoth(), TBS); + ASSERT_THAT(status_or_long, IsOk()) + << "TIFFReadEncodedTile fatal error"; + EXPECT_THAT(status_or_long.value(), Eq(TBS)) + << "line " << i << ": expected 256, got " << status_or_long.value(); + + bool cmp = tilebuffer[0] != expected_c || tilebuffer[255] != expected_c; + + EXPECT_THAT(tilebuffer[0], Eq(expected_c)) + << "unexpected value at tile " << i << ": expected " << expected_c + << ", got " << tilebuffer[0]; + + EXPECT_THAT(tilebuffer[255], Eq(expected_c)) + << "unexpected value at tile " << i << ": expected " << expected_c + << ", got " << tilebuffer[255]; + if (cmp) { + ASSERT_THAT(api.TIFFClose(&tif2), IsOk()) << "TIFFClose fatal error"; + } + } + } + } else { + for (int i = 0; i < height; ++i) { + for (int retry = 0; retry < 2; ++retry) { + sapi::v::UChar c(0); + unsigned char expected_c = (unsigned char)i; + + status_or_long = api.TIFFReadEncodedStrip(&tif2, i, c.PtrBoth(), 1); + ASSERT_THAT(status_or_long, IsOk()) + << "TIFFReadEncodedStrip fatal error"; + EXPECT_THAT(status_or_long.value(), Eq(1)) + << "line " << i << ": expected 1, got " << status_or_long.value(); + EXPECT_THAT(c.GetValue(), Eq(expected_c)) + << "unexpected value at line " << i << ": expected " << expected_c + << ", got " << c.GetValue(); + + if (c.GetValue() != expected_c) { + ASSERT_THAT(api.TIFFClose(&tif2), IsOk()) << "TIFFClose fatal error"; + } + } + } + } + + ASSERT_THAT(api.TIFFClose(&tif2), IsOk()) << "TIFFClose fatal error"; + + unlink(srcfile.c_str()); +} + +TEST(SandboxTest, DeferStrileWriting) { + for (int tiled = 0; tiled <= 1; ++tiled) { + test_writing("w", tiled, 1); + test_writing("w", tiled, 10); + test_writing("w8", tiled, 1); + test_writing("wD", tiled, 1); + } +} diff --git a/oss-internship-2020/libtiff/test/helper.cc b/oss-internship-2020/libtiff/test/helper.cc new file mode 100644 index 0000000..4a9c380 --- /dev/null +++ b/oss-internship-2020/libtiff/test/helper.cc @@ -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. + +#include "helper.h" + +#include + +std::string inDir; + +std::string GetCWD() { + char cwd[PATH_MAX]; + getcwd(cwd, sizeof(cwd)); + return cwd; +} + +std::string GetImagesDir() { + std::string cwd = GetCWD(); + auto find = cwd.rfind("/build"); + if (find == std::string::npos) { + std::cerr << "Something went wrong: CWD don't contain build dir. " + << "Please run tests from build dir, path might be incorrect\n"; + + return cwd + "/test/images"; + } + + return cwd.substr(0, find) + "/test/images"; +} + +std::string GetFilePath(const std::string& filename) { + if (inDir.empty()) { + inDir = GetImagesDir(); + } + return sandbox2::file::JoinPath(inDir, filename); +} + +std::string GetOutPath() { return GetImagesDir() + '/' + kOutDir; } + +std::string GetNewFilePath(const std::string& filename) { + return GetOutPath() + '/' + filename; +} \ No newline at end of file diff --git a/oss-internship-2020/libtiff/test/helper.h b/oss-internship-2020/libtiff/test/helper.h new file mode 100644 index 0000000..20dd7ec --- /dev/null +++ b/oss-internship-2020/libtiff/test/helper.h @@ -0,0 +1,35 @@ +// 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" +#include "gtest/gtest.h" +#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" + +const std::string kOutDir = "output"; + +using ::sapi::IsOk; +using ::testing::Eq; +using ::testing::IsFalse; +using ::testing::IsTrue; +using ::testing::Ne; +using ::testing::NotNull; + +std::string GetOutPath(); +std::string GetFilePath(const std::string& filename); +std::string GetNewFilePath(const std::string& filename); \ No newline at end of file diff --git a/oss-internship-2020/libtiff/test/images/quad-tile.jpg.tiff b/oss-internship-2020/libtiff/test/images/quad-tile.jpg.tiff new file mode 100644 index 0000000000000000000000000000000000000000..99b0bc2e741153d305862a2ec45bfd53f1718849 GIT binary patch literal 27576 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 hhvh;1M;!LG{@>y-4)_Gc`S +#include + +#include "check_tag.h" +#include "tiffio.h" + +/* sapi functions: + * TIFFWriteScanline + * TIFFOpen + * TIFFClose + * TIFFGetField (from check_tag.c) + * TIFFSetField + */ + +struct long_tag { + ttag_t tag; + short count; + unsigned value; +}; + +const std::vector long_tags = { + {TIFFTAG_SUBFILETYPE, 1, + FILETYPE_REDUCEDIMAGE | FILETYPE_PAGE | FILETYPE_MASK}}; +#define SPP 3 // kSamplePerPixel +static const unsigned kWidth = 1; +static const unsigned kLength = 1; +static const unsigned kBps = 8; +static const unsigned kRowsPerStrip = 1; + +TEST(SandboxTest, LongTag) { + sapi::StatusOr status_or_path = + sandbox2::CreateNamedTempFileAndClose("long_test.tif"); + ASSERT_THAT(status_or_path, IsOk()) << "Could not create temp file"; + + std::string srcfile = sandbox2::file::JoinPath( + sandbox2::file_util::fileops::GetCWD(), status_or_path.value()); + + TiffSapiSandbox sandbox("", srcfile); + ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API"; + + std::array buffer = {0, 127, 255}; + sapi::v::Array buffer_(buffer.data(), SPP); + + sapi::StatusOr status_or_int; + sapi::StatusOr status_or_tif; + + TiffApi api(&sandbox); + sapi::v::ConstCStr srcfile_var(srcfile.c_str()); + sapi::v::ConstCStr w_var("w"); + + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), w_var.PtrBefore()); + ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile; + + sapi::v::RemotePtr tif(status_or_tif.value()); + ASSERT_THAT(tif.GetValue(), NotNull()) + << "Can't create test TIFF file " << srcfile; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGEWIDTH, kWidth); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageWidth tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_IMAGELENGTH, kLength); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageLength tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_BITSPERSAMPLE, kBps); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set BitsPerSample tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_SAMPLESPERPIXEL, SPP); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set SamplesPerPixel tag"; + + status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_ROWSPERSTRIP, kRowsPerStrip); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set RowsPerStrip tag"; + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set PlanarConfiguration tag"; + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set PhotometricInterpretation tag"; + + for (auto& tag : long_tags) { + status_or_int = api.TIFFSetFieldU1(&tif, tag.tag, tag.value); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set tag " << tag.tag; + } + + status_or_int = api.TIFFWriteScanline(&tif, buffer_.PtrBoth(), 0, 0); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteScanline fatal error"; + ASSERT_THAT(status_or_int.value(), Ne(-1)) << "Can't write image data"; + + ASSERT_THAT(api.TIFFClose(&tif), IsOk()) << "TIFFClose fatal error"; + + sapi::v::ConstCStr r_var("r"); + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore()); + ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile; + + sapi::v::RemotePtr tif2(status_or_tif.value()); + ASSERT_THAT(tif2.GetValue(), NotNull()) + << "Can't create test TIFF file " << srcfile; + + CheckLongField(api, tif2, TIFFTAG_IMAGEWIDTH, kWidth); + CheckLongField(api, tif2, TIFFTAG_IMAGELENGTH, kLength); + CheckLongField(api, tif2, TIFFTAG_ROWSPERSTRIP, kRowsPerStrip); + + for (auto& tag : long_tags) { + CheckLongField(api, tif2, tag.tag, tag.value); + } + + ASSERT_THAT(api.TIFFClose(&tif2), IsOk()) << "TIFFClose fatal error"; + unlink(srcfile.c_str()); +} \ No newline at end of file diff --git a/oss-internship-2020/libtiff/test/raw_decode.cc b/oss-internship-2020/libtiff/test/raw_decode.cc new file mode 100644 index 0000000..c26685e --- /dev/null +++ b/oss-internship-2020/libtiff/test/raw_decode.cc @@ -0,0 +1,198 @@ +// 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 "gtest/gtest.h" +#include "helper.h" +#include "tiffio.h" + +/* sapi functions: + * TIFFOpen + * TIFFClose + * TIFFGetField + * TIFFSetField + * TIFFTileSize + * TIFFReadRGBATile + * TIFFReadEncodedTile + */ + +static const std::vector cluster_0 = {0, 0, 2, 0, 138, 139}; +static const std::vector cluster_64 = {0, 0, 9, 6, 134, 119}; +static const std::vector cluster_128 = {44, 40, 63, 59, 230, 95}; + +static int check_cluster(int cluster, + const sapi::v::Array &buffer, + const std::vector &expected_cluster) { + unsigned char *target = buffer.GetData() + cluster * 6; + + bool comp = !(std::memcmp(target, expected_cluster.data(), 6) == 0); + + EXPECT_THAT(comp, IsFalse()) + << "Cluster " << cluster << " did not match expected results.\n" + << "Expect: " << expected_cluster[0] << "\t" << expected_cluster[1] + << "\t" << expected_cluster[4] << "\t" << expected_cluster[5] << "\t" + << expected_cluster[2] << "\t" << expected_cluster[3] << "\n" + << "Got: " << target[0] << "\t" << target[1] << "\t" << target[4] << "\t" + << target[5] << "\t" << target[2] << "\t" << target[3]; + + return comp; +} + +static int check_rgb_pixel(int pixel, int min_red, int max_red, int min_green, + int max_green, int min_blue, int max_blue, + const sapi::v::Array &buffer) { + unsigned char *rgb = buffer.GetData() + 3 * pixel; + + bool comp = + !(rgb[0] >= min_red && rgb[0] <= max_red && rgb[1] >= min_green && + rgb[1] <= max_green && rgb[2] >= min_blue && rgb[2] <= max_blue); + + EXPECT_THAT(comp, IsFalse()) + << "Pixel " << pixel << " did not match expected results.\n" + << "Got R=" << rgb[0] << " (expected " << min_red << ".." << max_red + << "), G=" << rgb[1] << " (expected " << min_green << ".." << max_green + << "), B=" << rgb[2] << " (expected " << min_blue << ".." << max_blue + << ")"; + return comp; +} + +static int check_rgba_pixel(int pixel, int min_red, int max_red, int min_green, + int max_green, int min_blue, int max_blue, + int min_alpha, int max_alpha, + const sapi::v::Array &buffer) { + /* RGBA images are upside down - adjust for normal ordering */ + int adjusted_pixel = pixel % 128 + (127 - (pixel / 128)) * 128; + unsigned rgba = buffer[adjusted_pixel]; + + bool comp = !(TIFFGetR(rgba) >= (unsigned)min_red && + TIFFGetR(rgba) <= (unsigned)max_red && + TIFFGetG(rgba) >= (unsigned)min_green && + TIFFGetG(rgba) <= (unsigned)max_green && + TIFFGetB(rgba) >= (unsigned)min_blue && + TIFFGetB(rgba) <= (unsigned)max_blue && + TIFFGetA(rgba) >= (unsigned)min_alpha && + TIFFGetA(rgba) <= (unsigned)max_alpha); + + EXPECT_THAT(comp, IsFalse()) + << "Pixel " << pixel << " did not match expected results.\n" + << "Got R=" << TIFFGetR(rgba) << " (expected " << min_red << ".." + << max_red << "), G=" << TIFFGetG(rgba) << " (expected " << min_green + << ".." << max_green << "), B=" << TIFFGetB(rgba) << " (expected " + << min_blue << ".." << max_blue << "), A=" << TIFFGetA(rgba) + << " (expected " << min_alpha << ".." << max_alpha << ")"; + return comp; +} + +TEST(SandboxTest, RawDecode) { + std::string srcfile = GetFilePath("quad-tile.jpg.tiff"); + + TiffSapiSandbox sandbox("", srcfile); + ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API"; + + tsize_t sz; + unsigned int pixel_status = 0; + sapi::v::UShort h, v; + sapi::StatusOr status_or_tif; + sapi::StatusOr status_or_int; + sapi::StatusOr status_or_long; + + TiffApi api(&sandbox); + sapi::v::ConstCStr srcfile_var(srcfile.c_str()); + sapi::v::ConstCStr r_var("r"); + + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore()); + ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile; + + sapi::v::RemotePtr tif(status_or_tif.value()); + ASSERT_THAT(tif.GetValue(), NotNull()) + << "Could not open " << srcfile << ", TIFFOpen return NULL"; + + status_or_int = api.TIFFGetField2(&tif, TIFFTAG_YCBCRSUBSAMPLING, h.PtrBoth(), + v.PtrBoth()); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFGetField2 fatal error"; + EXPECT_THAT( + status_or_int.value() == 0 || h.GetValue() != 2 || v.GetValue() != 2, + IsFalse()) + << "Could not retrieve subsampling tag"; + + status_or_long = api.TIFFTileSize(&tif); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFTileSize fatal error"; + EXPECT_THAT(status_or_long.value(), Eq(24576)) + << "tiles are " << status_or_long.value() << " bytes"; + sz = status_or_long.value(); + + sapi::v::Array buffer_(sz); + status_or_long = api.TIFFReadEncodedTile(&tif, 9, buffer_.PtrBoth(), sz); + ASSERT_THAT(status_or_long, IsOk()) << "TIFFReadEncodedTile fatal error"; + EXPECT_THAT(status_or_long.value(), Eq(sz)) + << "Did not get expected result code from TIFFReadEncodedTile()(" + << (int)status_or_long.value() << " instead of " << (int)sz << ")"; + + ASSERT_FALSE(check_cluster(0, buffer_, cluster_0) || + check_cluster(64, buffer_, cluster_64) || + check_cluster(128, buffer_, cluster_128)) + << "Clusters did not match expected results"; + + status_or_int = + api.TIFFSetFieldU1(&tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFSetFieldU1 not available"; + + status_or_long = api.TIFFTileSize(&tif); + ASSERT_THAT(status_or_long, IsOk()) << "TIFFTileSize fatal error"; + EXPECT_THAT(status_or_long.value(), Eq(128 * 128 * 3)) + << "tiles are " << status_or_long.value() << " bytes"; + sz = status_or_long.value(); + + sapi::v::Array buffer2_(sz); + status_or_long = api.TIFFReadEncodedTile(&tif, 9, buffer2_.PtrBoth(), sz); + ASSERT_THAT(status_or_long, IsOk()) << "TIFFReadEncodedTile fatal error"; + EXPECT_THAT(status_or_long.value(), Eq(sz)) + << "Did not get expected result code from TIFFReadEncodedTile()(" + << status_or_long.value() << " instead of " << sz; + + pixel_status |= check_rgb_pixel(0, 15, 18, 0, 0, 18, 41, buffer2_); + pixel_status |= check_rgb_pixel(64, 0, 0, 0, 0, 0, 2, buffer2_); + pixel_status |= check_rgb_pixel(512, 5, 6, 34, 36, 182, 196, buffer2_); + + ASSERT_THAT(api.TIFFClose(&tif), IsOk()) << "TIFFClose fatal error"; + + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore()); + ASSERT_THAT(status_or_tif, IsOk()) << "TIFFOpen fatal error"; + + sapi::v::RemotePtr tif2(status_or_tif.value()); + ASSERT_THAT(tif2.GetValue(), NotNull()) + << "Could not open " << srcfile << ", TIFFOpen return NULL"; + + sapi::v::Array rgba_buffer_(128 * 128); + + status_or_int = + api.TIFFReadRGBATile(&tif2, 1 * 128, 2 * 128, rgba_buffer_.PtrBoth()); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFReadRGBATile fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "TIFFReadRGBATile() returned failure code"; + + pixel_status |= + check_rgba_pixel(0, 15, 18, 0, 0, 18, 41, 255, 255, rgba_buffer_); + pixel_status |= + check_rgba_pixel(64, 0, 0, 0, 0, 0, 2, 255, 255, rgba_buffer_); + pixel_status |= + check_rgba_pixel(512, 5, 6, 34, 36, 182, 196, 255, 255, rgba_buffer_); + + EXPECT_THAT(api.TIFFClose(&tif2), IsOk()) << "TIFFClose fatal error"; + + EXPECT_THAT(pixel_status, IsFalse()) << "wrong encoding"; +} \ No newline at end of file diff --git a/oss-internship-2020/libtiff/test/short_tag.cc b/oss-internship-2020/libtiff/test/short_tag.cc new file mode 100644 index 0000000..1b02d02 --- /dev/null +++ b/oss-internship-2020/libtiff/test/short_tag.cc @@ -0,0 +1,170 @@ +// 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 "check_tag.h" +#include "tiffio.h" + +/* sapi functions: + * TIFFWriteScanline + * TIFFOpen + * TIFFClose + * TIFFGetField (from check_tag.c) + * TIFFSetField + */ + +#define SPP 3 // kSamplePerPixel +static const unsigned short kWidth = 1; +static const unsigned short kLength = 1; +static const unsigned short kBps = 8; +static const unsigned short kPhotometric = PHOTOMETRIC_RGB; +static const unsigned short kRowsPerStrip = 1; +static const unsigned short kPlanarConfig = PLANARCONFIG_CONTIG; + +struct single_tag { + const ttag_t tag; + const unsigned short value; +}; + +struct paired_tag { + const ttag_t tag; + const std::array values; +}; + +static const std::vector short_single_tags = { + {TIFFTAG_COMPRESSION, COMPRESSION_NONE}, + {TIFFTAG_FILLORDER, FILLORDER_MSB2LSB}, + {TIFFTAG_ORIENTATION, ORIENTATION_BOTRIGHT}, + {TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH}, + {TIFFTAG_MINSAMPLEVALUE, 23}, + {TIFFTAG_MAXSAMPLEVALUE, 241}, + {TIFFTAG_INKSET, INKSET_MULTIINK}, + {TIFFTAG_NUMBEROFINKS, SPP}, + {TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT}}; + +static const std::vector short_paired_tags = { + {TIFFTAG_PAGENUMBER, {1, 1}}, + {TIFFTAG_HALFTONEHINTS, {0, 255}}, + {TIFFTAG_DOTRANGE, {8, 16}}, + {TIFFTAG_YCBCRSUBSAMPLING, {2, 1}}}; + +TEST(SandboxTest, ShortTag) { + sapi::StatusOr status_or_path = + sandbox2::CreateNamedTempFileAndClose("short_test.tif"); + ASSERT_THAT(status_or_path, IsOk()) << "Could not create temp file"; + + std::string srcfile = sandbox2::file::JoinPath( + sandbox2::file_util::fileops::GetCWD(), status_or_path.value()); + + TiffSapiSandbox sandbox("", srcfile); + ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API"; + + std::array buffer = {0, 127, 255}; + sapi::v::Array buffer_(buffer.data(), SPP); + + sapi::StatusOr status_or_int; + sapi::StatusOr status_or_tif; + + TiffApi api(&sandbox); + sapi::v::ConstCStr srcfile_var(srcfile.c_str()); + sapi::v::ConstCStr w_var("w"); + + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), w_var.PtrBefore()); + ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile; + + sapi::v::RemotePtr tif(status_or_tif.value()); + ASSERT_THAT(tif.GetValue(), NotNull()) + << "Can't create test TIFF file " << srcfile; + + status_or_int = api.TIFFSetFieldUShort1(&tif, TIFFTAG_IMAGEWIDTH, kWidth); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImagekWidth tag"; + + status_or_int = api.TIFFSetFieldUShort1(&tif, TIFFTAG_IMAGELENGTH, kLength); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set ImageLength tag"; + + status_or_int = api.TIFFSetFieldUShort1(&tif, TIFFTAG_BITSPERSAMPLE, kBps); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set BitsPerSample tag"; + + status_or_int = api.TIFFSetFieldUShort1(&tif, TIFFTAG_SAMPLESPERPIXEL, SPP); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set SamplesPerPixel tag"; + + status_or_int = + api.TIFFSetFieldUShort1(&tif, TIFFTAG_ROWSPERSTRIP, kRowsPerStrip); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set RowsPerStrip tag"; + + status_or_int = + api.TIFFSetFieldUShort1(&tif, TIFFTAG_PLANARCONFIG, kPlanarConfig); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set PlanarConfiguration tag"; + + status_or_int = + api.TIFFSetFieldUShort1(&tif, TIFFTAG_PHOTOMETRIC, kPhotometric); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) + << "Can't set PhotometricInterpretation tag"; + + for (auto& tag : short_single_tags) { + status_or_int = api.TIFFSetFieldUShort1(&tif, tag.tag, tag.value); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort1 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set tag " << tag.tag; + } + + for (auto& tag : short_paired_tags) { + status_or_int = + api.TIFFSetFieldUShort2(&tif, tag.tag, tag.values[0], tag.values[1]); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldUShort2 fatal error"; + EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set tag " << tag.tag; + } + + status_or_int = api.TIFFWriteScanline(&tif, buffer_.PtrBoth(), 0, 0); + ASSERT_THAT(status_or_int, IsOk()) << "TIFFWriteScanline fatal error"; + ASSERT_THAT(status_or_int.value(), Ne(-1)) << "Can't write image data"; + + ASSERT_THAT(api.TIFFClose(&tif), IsOk()) << "TIFFClose fatal error"; + + sapi::v::ConstCStr r_var("r"); + status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore()); + ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile; + + sapi::v::RemotePtr tif2(status_or_tif.value()); + ASSERT_THAT(tif2.GetValue(), NotNull()) + << "Can't create test TIFF file " << srcfile; + + CheckLongField(api, tif2, TIFFTAG_IMAGEWIDTH, kWidth); + CheckLongField(api, tif2, TIFFTAG_IMAGELENGTH, kLength); + CheckShortField(api, tif2, TIFFTAG_BITSPERSAMPLE, kBps); + CheckShortField(api, tif2, TIFFTAG_PHOTOMETRIC, kPhotometric); + CheckShortField(api, tif2, TIFFTAG_SAMPLESPERPIXEL, SPP); + CheckLongField(api, tif2, TIFFTAG_ROWSPERSTRIP, kRowsPerStrip); + CheckShortField(api, tif2, TIFFTAG_PLANARCONFIG, kPlanarConfig); + + for (auto& tag : short_single_tags) { + CheckShortField(api, tif2, tag.tag, tag.value); + } + + for (auto& tag : short_paired_tags) { + CheckShortPairedField(api, tif2, tag.tag, tag.values); + } + + ASSERT_THAT(api.TIFFClose(&tif2), IsOk()) << "TIFFClose fatal error"; +} diff --git a/oss-internship-2020/libtiff/wrapper/CMakeLists.txt b/oss-internship-2020/libtiff/wrapper/CMakeLists.txt new file mode 100644 index 0000000..0be8ee7 --- /dev/null +++ b/oss-internship-2020/libtiff/wrapper/CMakeLists.txt @@ -0,0 +1,29 @@ +# 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(wrapped_tiff OBJECT + func.h + func.cc +) +set_target_properties(wrapped_tiff + PROPERTIES LINKER_LANGUAGE C +) + +add_subdirectory(libtiff) + +target_link_libraries(wrapped_tiff + sandbox2::temp_file + sapi::sapi + tiff +) \ No newline at end of file diff --git a/oss-internship-2020/libtiff/wrapper/func.cc b/oss-internship-2020/libtiff/wrapper/func.cc new file mode 100644 index 0000000..0015671 --- /dev/null +++ b/oss-internship-2020/libtiff/wrapper/func.cc @@ -0,0 +1,163 @@ +// 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 "func.h" + +int TIFFGetField1(TIFF* tif, unsigned tag, void* param) { + return TIFFGetField(tif, tag, param); +} + +int TIFFGetField2(TIFF* tif, unsigned tag, void* param1, void* param2) { + return TIFFGetField(tif, tag, param1, param2); +} + +int TIFFGetField3(TIFF* tif, unsigned tag, void* param1, void* param2, + void* param3) { + return TIFFGetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldUChar1(TIFF* tif, unsigned tag, unsigned char param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldUChar2(TIFF* tif, unsigned tag, unsigned char param1, + unsigned char param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldUChar3(TIFF* tif, unsigned tag, unsigned char param1, + unsigned char param2, unsigned char param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldSChar1(TIFF* tif, unsigned tag, signed char param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldSChar2(TIFF* tif, unsigned tag, signed char param1, + signed char param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldSChar3(TIFF* tif, unsigned tag, signed char param1, + signed char param2, signed char param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldU1(TIFF* tif, unsigned tag, unsigned param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldU2(TIFF* tif, unsigned tag, unsigned param1, unsigned param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldU3(TIFF* tif, unsigned tag, unsigned param1, unsigned param2, + unsigned param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldS1(TIFF* tif, unsigned tag, int param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldS2(TIFF* tif, unsigned tag, int param1, int param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldS3(TIFF* tif, unsigned tag, int param1, int param2, + int param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldUShort1(TIFF* tif, unsigned tag, unsigned short param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldUShort2(TIFF* tif, unsigned tag, unsigned short param1, + unsigned short param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldUShort3(TIFF* tif, unsigned tag, unsigned short param1, + unsigned short param2, unsigned short param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldSShort1(TIFF* tif, unsigned tag, short param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldSShort2(TIFF* tif, unsigned tag, short param1, short param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldSShort3(TIFF* tif, unsigned tag, short param1, short param2, + short param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldULLong1(TIFF* tif, unsigned tag, unsigned long long param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldULLong2(TIFF* tif, unsigned tag, unsigned long long param1, + unsigned long long param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldULLong3(TIFF* tif, unsigned tag, unsigned long long param1, + unsigned long long param2, unsigned long long param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldSLLong1(TIFF* tif, unsigned tag, long long param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldSLLong2(TIFF* tif, unsigned tag, long long param1, + long long param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldSLLong3(TIFF* tif, unsigned tag, long long param1, + long long param2, long long param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldFloat1(TIFF* tif, unsigned tag, float param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldFloat2(TIFF* tif, unsigned tag, float param1, float param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldFloat3(TIFF* tif, unsigned tag, float param1, float param2, + float param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} + +int TIFFSetFieldDouble1(TIFF* tif, unsigned tag, double param) { + return TIFFSetField(tif, tag, param); +} + +int TIFFSetFieldDouble2(TIFF* tif, unsigned tag, double param1, double param2) { + return TIFFSetField(tif, tag, param1, param2); +} + +int TIFFSetFieldDouble3(TIFF* tif, unsigned tag, double param1, double param2, + double param3) { + return TIFFSetField(tif, tag, param1, param2, param3); +} diff --git a/oss-internship-2020/libtiff/wrapper/func.h b/oss-internship-2020/libtiff/wrapper/func.h new file mode 100644 index 0000000..4d841dc --- /dev/null +++ b/oss-internship-2020/libtiff/wrapper/func.h @@ -0,0 +1,86 @@ +// 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. + +#ifndef LIBTIFF_WRAPPER_FUNC_H +#define LIBTIFF_WRAPPER_FUNC_H + +#include "tiffio.h" + +/* s - signed + * u - unsigned + * wrapper for variadic functions TIFFGetField and TIFFSetField + */ + +extern "C" { +int TIFFGetField1(TIFF* tif, unsigned tag, void* param); +int TIFFGetField2(TIFF* tif, unsigned tag, void* param1, void* param2); +int TIFFGetField3(TIFF* tif, unsigned tag, void* param1, void* param2, + void* param3); + +int TIFFSetFieldUChar1(TIFF* tif, unsigned tag, unsigned char param); +int TIFFSetFieldUChar2(TIFF* tif, unsigned tag, unsigned char param1, + unsigned char param2); +int TIFFSetFieldUChar3(TIFF* tif, unsigned tag, unsigned char param1, + unsigned char param2, unsigned char param3); + +int TIFFSetFieldSChar1(TIFF* tif, unsigned tag, signed char param); +int TIFFSetFieldSChar2(TIFF* tif, unsigned tag, signed char param1, + signed char param2); +int TIFFSetFieldSChar3(TIFF* tif, unsigned tag, signed char param1, + signed char param2, signed char param3); + +int TIFFSetFieldU1(TIFF* tif, unsigned tag, unsigned param); +int TIFFSetFieldU2(TIFF* tif, unsigned tag, unsigned param1, unsigned param2); +int TIFFSetFieldU3(TIFF* tif, unsigned tag, unsigned param1, unsigned param2, + unsigned param3); + +int TIFFSetFieldS1(TIFF* tif, unsigned tag, int param); +int TIFFSetFieldS2(TIFF* tif, unsigned tag, int param1, int param2); +int TIFFSetFieldS3(TIFF* tif, unsigned tag, int param1, int param2, int param3); + +int TIFFSetFieldUShort1(TIFF* tif, unsigned tag, unsigned short param); +int TIFFSetFieldUShort2(TIFF* tif, unsigned tag, unsigned short param1, + unsigned short param2); +int TIFFSetFieldUShort3(TIFF* tif, unsigned tag, unsigned short param1, + unsigned short param2, unsigned short param3); + +int TIFFSetFieldSShort1(TIFF* tif, unsigned tag, short param); +int TIFFSetFieldSShort2(TIFF* tif, unsigned tag, short param1, short param2); +int TIFFSetFieldSShort3(TIFF* tif, unsigned tag, short param1, short param2, + short param3); + +int TIFFSetFieldULLong1(TIFF* tif, unsigned tag, unsigned long long param); +int TIFFSetFieldULLong2(TIFF* tif, unsigned tag, unsigned long long param1, + unsigned long long param2); +int TIFFSetFieldULLong3(TIFF* tif, unsigned tag, unsigned long long param1, + unsigned long long param2, unsigned long long param3); + +int TIFFSetFieldSLLong1(TIFF* tif, unsigned tag, long long param); +int TIFFSetFieldSLLong2(TIFF* tif, unsigned tag, long long param1, + long long param2); +int TIFFSetFieldSLLong3(TIFF* tif, unsigned tag, long long param1, + long long param2, long long param3); + +int TIFFSetFieldFloat1(TIFF* tif, unsigned tag, float param); +int TIFFSetFieldFloat2(TIFF* tif, unsigned tag, float param1, float param2); +int TIFFSetFieldFloat3(TIFF* tif, unsigned tag, float param1, float param2, + float param3); + +int TIFFSetFieldDouble1(TIFF* tif, unsigned tag, double param); +int TIFFSetFieldDouble2(TIFF* tif, unsigned tag, double param1, double param2); +int TIFFSetFieldDouble3(TIFF* tif, unsigned tag, double param1, double param2, + double param3); +} + +#endif diff --git a/oss-internship-2020/libtiff/wrapper/libtiff b/oss-internship-2020/libtiff/wrapper/libtiff new file mode 160000 index 0000000..c8f0a16 --- /dev/null +++ b/oss-internship-2020/libtiff/wrapper/libtiff @@ -0,0 +1 @@ +Subproject commit c8f0a16f4ad10cd5d595bd5614104e2ecf52ee92