Merge pull request #100 from oshogbo:zopfli

PiperOrigin-RevId: 426911996
Change-Id: Ib257a94b6f5cbe932766d2c25c21ad082e0369a4
This commit is contained in:
Copybara-Service 2022-02-07 07:30:51 -08:00
commit d76a0e959e
14 changed files with 2445 additions and 12 deletions

View File

@ -14,7 +14,9 @@
# Append to this list whenever a new sandboxed library is added to `contrib/`.
set(SAPI_CONTRIB_SANDBOXES
hunspell
jsonnet
zopfli
zstd
)

View File

@ -9,6 +9,7 @@ Directory | Project | Home Page
----------- | ------------------------------------------------- | -------------------------------------------------------------------- | -----------
`jsonnet/` | Jsonnet - The Data Templating Language | [github.com/google/jsonnet](https://github.com/google/jsonnet) | CMake
`hunspell/` | Hunspell - The most popular spellchecking library | [github.com/hunspell/hunspell](https://github.com/hunspell/hunspell) | CMake
`zopfli` | Zopfli - Compression Algorithm | [github.com/google/zopfli](https://github.com/google/zopfli) | CMake
`zstd/` | Zstandard - Fast real-time compression algorithm | [github.com/facebook/zstd](https://github.com/facebook/zstd) | CMake
## Projects Shipping with Sandboxed API Sandboxes

View File

@ -21,15 +21,14 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
add_subdirectory(
"${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
EXCLUDE_FROM_ALL
)
FetchContent_Declare(
libhunspell
if(NOT TARGET sapi::sapi)
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
EXCLUDE_FROM_ALL)
endif()
FetchContent_Declare(libhunspell
GIT_REPOSITORY https://github.com/hunspell/hunspell.git
GIT_TAG 31e6d6323026a3bef12c5912ce032d88bfef2091
)
@ -44,13 +43,22 @@ if(NOT libhunspell_POPULATED)
if(NOT _sapi_CONFIG_STATUS STREQUAL "${libhunspell_CONFIG_STATUS}")
message("-- Configuring libhunspell...")
execute_process(
COMMAND autoreconf -vfi
COMMAND autoreconf -i
WORKING_DIRECTORY "${libhunspell_SOURCE_DIR}"
RESULT_VARIABLE _sapi_libhunspell_autoreconf_result
)
if(NOT _sapi_libhunspell_autoreconf_result EQUAL "0")
message(FATAL_ERROR "Configuration for libhunspell failed: "
"${_sapi_libhunspell_autoreconf_result}")
endif()
execute_process(
COMMAND ./configure --disable-dependency-tracking
WORKING_DIRECTORY "${libhunspell_SOURCE_DIR}"
RESULT_VARIABLE libhunspell_config_result
RESULT_VARIABLE _sapi_libhunspell_config_result
)
if(NOT libhunspell_config_result EQUAL "0")
message(FATAL_ERROR "Configuration for libhunspell failed")
if(NOT _sapi_libhunspell_config_result EQUAL "0")
message(FATAL_ERROR "Configuration for libhunspell failed: "
"${_sapi_libhunspell_config_result}")
endif()
file(SHA256 "${libhunspell_SOURCE_DIR}/config.status" _sapi_CONFIG_STATUS)
set(libhunspell_CONFIG_STATUS "${_sapi_CONFIG_STATUS}" CACHE INTERNAL "")

View File

@ -35,6 +35,7 @@ class HunspellSapiSandbox : public HunspellSandbox {
.AllowOpen()
.AllowRead()
.AllowWrite()
.AllowGetPIDs()
.AllowSystemMalloc()
.AllowExit()
.AllowSyscalls({

View File

@ -0,0 +1,68 @@
# Copyright 2022 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
#
# https://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.13..3.22)
project(sapi_zopfli CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
if(NOT TARGET sapi::sapi)
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
EXCLUDE_FROM_ALL)
endif()
FetchContent_Declare(zopfli
GIT_REPOSITORY https://github.com/google/zopfli.git
GIT_TAG 831773bc28e318b91a3255fa12c9fcde1606058b
)
FetchContent_MakeAvailable(zopfli)
add_sapi_library(
sapi_zopfli
FUNCTIONS
ZopfliInitOptions
ZopfliCompress
ZopfliDeflate
ZopfliZlibCompress
ZopfliGzipCompress
INPUTS
${zopfli_SOURCE_DIR}/src/zopfli/deflate.h
${zopfli_SOURCE_DIR}/src/zopfli/gzip_container.h
${zopfli_SOURCE_DIR}/src/zopfli/zlib_container.h
LIBRARY Zopfli::libzopfli
LIBRARY_NAME Zopfli
NAMESPACE ""
)
add_library(sapi_contrib::zopfli ALIAS sapi_zopfli)
target_include_directories(sapi_zopfli INTERFACE
"${PROJECT_BINARY_DIR}"
"${SAPI_SOURCE_DIR}"
)
if(SAPI_ENABLE_EXAMPLES)
add_subdirectory(example)
endif()
if(SAPI_ENABLE_TESTS)
add_subdirectory(test)
endif()

View File

@ -0,0 +1,23 @@
# Copyright 2022 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
#
# https://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(sapi_minizopfli
main.cc
../utils/utils_zopfli.cc
)
target_link_libraries(sapi_minizopfli PRIVATE
sapi_contrib::zopfli
sapi::sapi
absl::flags_parse
)

View File

@ -0,0 +1,73 @@
// Copyright 2022 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
//
// https://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 <unistd.h>
#include <fstream>
#include <iostream>
#include <string>
#include "sandboxed_api/util/flag.h"
#include "absl/flags/parse.h"
#include "contrib/zopfli/sandboxed.h"
#include "contrib/zopfli/utils/utils_zopfli.h"
ABSL_FLAG(bool, zlib, false, "zlib compression");
ABSL_FLAG(bool, gzip, false, "gzip compression");
int main(int argc, char* argv[]) {
std::string prog_name(argv[0]);
google::InitGoogleLogging(argv[0]);
std::vector<char*> args = absl::ParseCommandLine(argc, argv);
if (args.size() != 3) {
std::cerr << "Usage:\n " << prog_name << " INPUT OUTPUT\n";
return EXIT_FAILURE;
}
std::ifstream infile(args[1], std::ios::binary);
if (!infile.is_open()) {
std::cerr << "Unable to open " << args[1] << std::endl;
return EXIT_FAILURE;
}
std::ofstream outfile(args[2], std::ios::binary);
if (!outfile.is_open()) {
std::cerr << "Unable to open " << args[2] << std::endl;
return EXIT_FAILURE;
}
ZopfliSapiSandbox sandbox;
if (!sandbox.Init().ok()) {
std::cerr << "Unable to start sandbox\n";
return EXIT_FAILURE;
}
ZopfliApi api(&sandbox);
ZopfliFormat format = ZOPFLI_FORMAT_DEFLATE;
if (absl::GetFlag(FLAGS_zlib)) {
format = ZOPFLI_FORMAT_ZLIB;
} else if (absl::GetFlag(FLAGS_gzip)) {
format = ZOPFLI_FORMAT_GZIP;
}
absl::Status status = Compress(api, infile, outfile, format);
if (!status.ok()) {
std::cerr << "Unable to compress file.\n";
std::cerr << status << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

BIN
contrib/zopfli/files/binary Normal file

Binary file not shown.

2000
contrib/zopfli/files/text Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
// Copyright 2022 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
//
// https://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 CONTRIB_ZOPFLI_SANDBOXED_
#define CONTRIB_ZOPFLI_SANDBOXED_
#include <libgen.h>
#include <syscall.h>
#include <cerrno>
#include <memory>
#include "sapi_zopfli.sapi.h" // NOLINT(build/include)
class ZopfliSapiSandbox : public ZopfliSandbox {
public:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder *) override {
return sandbox2::PolicyBuilder()
.AllowStaticStartup()
.AllowWrite()
.AllowExit()
.AllowMmap()
.AllowSystemMalloc()
.AllowSyscalls({
__NR_sysinfo,
})
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
#endif
#ifdef __NR_openat
.BlockSyscallWithErrno(__NR_openat, ENOENT)
#endif
.BuildOrDie();
}
};
#endif // CONTRIB_ZOPFLI_SANDBOXED_

View File

@ -0,0 +1,28 @@
# Copyright 2022 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
#
# https://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(sapi_zopfli_test
zopfli_test.cc
../utils/utils_zopfli.cc
)
target_link_libraries(sapi_zopfli_test PRIVATE
sapi_contrib::zopfli
sapi::temp_file
sapi::test_main
)
gtest_discover_tests(sapi_zopfli_test PROPERTIES
ENVIRONMENT "TEST_FILES_DIR=${PROJECT_SOURCE_DIR}/files"
)

View File

@ -0,0 +1,98 @@
// Copyright 2022 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
//
// https://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 <fstream>
#include "contrib/zopfli/sandboxed.h"
#include "contrib/zopfli/utils/utils_zopfli.h"
#include "sandboxed_api/util/path.h"
#include "sandboxed_api/util/status_matchers.h"
#include "sandboxed_api/util/temp_file.h"
namespace {
using ::sapi::IsOk;
using ::testing::IsEmpty;
using ::testing::Not;
std::string GetTestFilePath(const std::string& filename) {
return sapi::file::JoinPath(getenv("TEST_FILES_DIR"), filename);
}
std::string GetTemporaryFile(const std::string& filename) {
absl::StatusOr<std::string> tmp_file =
sapi::CreateNamedTempFileAndClose(filename);
if (!tmp_file.ok()) {
return "";
}
return sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *tmp_file);
}
class TestText : public testing::TestWithParam<ZopfliFormat> {};
class TestBinary : public testing::TestWithParam<ZopfliFormat> {};
TEST_P(TestText, Compress) {
ZopfliSapiSandbox sandbox;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZopfliApi api(&sandbox);
std::string infile_s = GetTestFilePath("text");
std::string outfile_s = GetTemporaryFile("text.out");
ASSERT_THAT(outfile_s, Not(IsEmpty()));
std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open());
std::ofstream outfile(outfile_s, std::ios::binary);
ASSERT_TRUE(outfile.is_open());
absl::Status status = Compress(api, infile, outfile, GetParam());
ASSERT_THAT(status, IsOk()) << "Unable to compress file";
ASSERT_LT(outfile.tellp(), infile.tellg());
}
INSTANTIATE_TEST_SUITE_P(SandboxTest, TestText,
testing::Values(ZOPFLI_FORMAT_DEFLATE,
ZOPFLI_FORMAT_GZIP,
ZOPFLI_FORMAT_ZLIB));
TEST_P(TestBinary, Compress) {
ZopfliSapiSandbox sandbox;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZopfliApi api(&sandbox);
std::string infile_s = GetTestFilePath("binary");
std::string outfile_s = GetTemporaryFile("binary.out");
ASSERT_THAT(outfile_s, Not(IsEmpty()));
std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open());
std::ofstream outfile(outfile_s, std::ios::binary);
ASSERT_TRUE(outfile.is_open());
absl::Status status = Compress(api, infile, outfile, GetParam());
ASSERT_THAT(status, IsOk()) << "Unable to compress file";
ASSERT_LT(outfile.tellp(), infile.tellg());
}
INSTANTIATE_TEST_SUITE_P(SandboxTest, TestBinary,
testing::Values(ZOPFLI_FORMAT_DEFLATE,
ZOPFLI_FORMAT_GZIP,
ZOPFLI_FORMAT_ZLIB));
} // namespace

View File

@ -0,0 +1,56 @@
// Copyright 2022 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
//
// https://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 "contrib/zopfli/utils/utils_zopfli.h"
#include <unistd.h>
#include <fstream>
absl::Status Compress(ZopfliApi& api, std::ifstream& instream,
std::ofstream& outstream, ZopfliFormat format) {
// Get size of Stream
instream.seekg(0, std::ios_base::end);
std::streamsize ssize = instream.tellg();
instream.seekg(0, std::ios_base::beg);
// Read data
sapi::v::Array<uint8_t> inbuf(ssize);
instream.read(reinterpret_cast<char*>(inbuf.GetData()), ssize);
if (instream.gcount() != ssize) {
return absl::UnavailableError("Unable to read file");
}
// Compress
sapi::v::Struct<ZopfliOptions> options;
SAPI_RETURN_IF_ERROR(api.ZopfliInitOptions(options.PtrAfter()));
sapi::v::GenericPtr outptr;
sapi::v::IntBase<size_t> outsize(0);
SAPI_RETURN_IF_ERROR(
api.ZopfliCompress(options.PtrBefore(), format, inbuf.PtrBefore(), ssize,
outptr.PtrAfter(), outsize.PtrBoth()));
// Get and save data
sapi::v::Array<int8_t> outbuf(outsize.GetValue());
outbuf.SetRemote(reinterpret_cast<void*>(outptr.GetValue()));
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferFromSandboxee(&outbuf));
outstream.write(reinterpret_cast<char*>(outbuf.GetData()), outbuf.GetSize());
if (!outstream.good()) {
return absl::UnavailableError("Unable to write file");
}
return absl::OkStatus();
}

View File

@ -0,0 +1,26 @@
// Copyright 2022 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
//
// https://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 CONTRIB_ZOPFLI_UTILS_UTILS_ZOPFLI_H_
#define CONTRIB_ZOPFLI_UTILS_UTILS_ZOPFLI_H_
#include <fstream>
#include "absl/status/status.h"
#include "contrib/zopfli/sandboxed.h"
absl::Status Compress(ZopfliApi& api, std::ifstream& instream,
std::ofstream& outstream, ZopfliFormat format);
#endif // CONTRIB_ZOPFLI_UTILS_UTILS_ZOPFLI_H_