Commit 6297ccf3 by Jamie Madill Committed by Commit Bot

Replace ijar sources with Chromium subtree mirror.

This will ensure a smoother update process. Bug: angleproject:2344 Change-Id: I81bf496ea013825588b1baa573855ce809a8decf Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2842355Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent f78927b0
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
/third_party/gles1_conform /third_party/gles1_conform
/third_party/glmark2/src /third_party/glmark2/src
/third_party/googletest /third_party/googletest
/third_party/ijar
/third_party/jdk/current /third_party/jdk/current
/third_party/jdk/extras/java_8 /third_party/jdk/extras/java_8
/third_party/jinja2 /third_party/jinja2
......
...@@ -347,6 +347,11 @@ deps = { ...@@ -347,6 +347,11 @@ deps = {
'condition': 'not build_with_chromium', 'condition': 'not build_with_chromium',
}, },
'third_party/ijar': {
'url': '{chromium_git}/chromium/src/third_party/ijar@174c5004785b456f247a6535694dec16e0ef1e2b',
'condition': 'checkout_android and not build_with_chromium',
},
# libjpeg_turbo is used by glmark2. # libjpeg_turbo is used by glmark2.
'third_party/libjpeg_turbo': { 'third_party/libjpeg_turbo': {
'url': '{chromium_git}/chromium/deps/libjpeg_turbo.git@7b4981b6500ccba10733c352b9ed2dad14ce3c73', 'url': '{chromium_git}/chromium/deps/libjpeg_turbo.git@7b4981b6500ccba10733c352b9ed2dad14ce3c73',
......
...@@ -55,6 +55,7 @@ ANGLE_CHROMIUM_DEPS = [ ...@@ -55,6 +55,7 @@ ANGLE_CHROMIUM_DEPS = [
'third_party/catapult', 'third_party/catapult',
'third_party/colorama/src', 'third_party/colorama/src',
'third_party/depot_tools', 'third_party/depot_tools',
'third_party/ijar',
'third_party/jdk', 'third_party/jdk',
'third_party/jdk/extras', 'third_party/jdk/extras',
'third_party/jinja2', 'third_party/jinja2',
......
package(
default_visibility = [
"//src:__subpackages__",
"//third_party/ijar:__subpackages__",
],
)
licenses(["notice"]) # Apache 2.0
cc_library(
name = "zip",
srcs = [
"zip.cc",
] + select({
"//src:windows": [
"mapped_file_windows.cc",
],
"//conditions:default": [
"mapped_file_unix.cc",
],
}),
hdrs = [
"common.h",
"mapped_file.h",
"zip.h",
],
visibility = [
"//src:__subpackages__",
"//third_party/ijar:__subpackages__",
"//tools/test:__pkg__",
],
deps = [
":platform_utils",
":zlib_client",
] + select({
"//src:windows": [
"//src/main/cpp/util:errors",
"//src/main/cpp/util:filesystem",
"//src/main/cpp/util:logging",
"//src/main/cpp/util:strings",
],
"//conditions:default": [
],
}),
)
cc_library(
name = "zlib_client",
srcs = ["zlib_client.cc"],
hdrs = [
"common.h",
"zlib_client.h",
],
deps = ["//third_party/zlib"],
)
cc_library(
name = "platform_utils",
srcs = ["platform_utils.cc"],
hdrs = [
"common.h",
"platform_utils.h",
],
visibility = ["//visibility:private"],
deps = [
"//src/main/cpp/util:errors",
"//src/main/cpp/util:filesystem",
"//src/main/cpp/util:logging",
],
)
cc_binary(
name = "zipper",
srcs = ["zip_main.cc"],
visibility = ["//visibility:public"],
deps = [":zip"],
)
cc_binary(
name = "ijar",
srcs = [
"classfile.cc",
"ijar.cc",
],
visibility = ["//visibility:public"],
deps = [":zip"],
)
filegroup(
name = "srcs",
srcs = glob(["**"]) + ["//third_party/ijar/test:srcs"],
visibility = ["//third_party:__pkg__"],
)
filegroup(
name = "embedded_zipper_sources",
srcs = [
"zip.cc",
"zip.h",
"zip_main.cc",
"common.h",
"mapped_file.h",
"platform_utils.cc",
"platform_utils.h",
"zlib_client.cc",
"zlib_client.h",
"BUILD",
] + select({
"//src:windows": [
"mapped_file_windows.cc",
],
"//conditions:default": [
"mapped_file_unix.cc",
],
}),
visibility = ["//visibility:public"],
)
filegroup(
name = "transitive_sources",
srcs = [":srcs"] + ["//src/main/cpp/util:embedded_java_tools"],
visibility = ["//visibility:public"],
)
genrule(
name = "ijar_transitive_zip",
srcs = [
":ijar_srcs_zip",
"//src:zlib_zip",
"//src/main/cpp/util:cpp_util_with_deps_zip",
],
outs = ["ijar_srcs_with_deps.zip"],
cmd = "$(location //src:merge_zip_files) - $@ $(SRCS)",
tools = ["//src:merge_zip_files"],
visibility = ["//visibility:public"],
)
genrule(
name = "ijar_srcs_zip",
srcs = glob(
["**"],
exclude = ["BUILD"],
) + [
":ijar",
":zipper",
],
outs = ["ijar_srcs.zip"],
cmd = "$(location //src:zip_files) ijar $@ $(SRCS)",
tools = ["//src:zip_files"],
visibility = ["//visibility:private"],
)
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# A tool that removes all non-interface-specific parts from a .jar file.
if (is_linux || is_chromeos) {
executable("ijar") {
sources = [
"classfile.cc",
"common.h",
"ijar.cc",
"mapped_file.h",
"mapped_file_unix.cc",
"platform_utils.cc",
"platform_utils.h",
"zip.cc",
"zip.h",
"zlib_client.cc",
"zlib_client.h",
]
deps = [ "//third_party/zlib" ]
# Always build release since this is a build tool.
if (is_debug) {
configs -= [ "//build/config:debug" ]
configs += [ "//build/config:release" ]
}
}
}
monorail: {
component: "Build"
}
team_email: "build@chromium.org"
agrieve@chromium.org
dpranke@google.com
Name: ijar
URL: https://github.com/bazelbuild/bazel
Version: b786db0994a4c4c65e3f93a4f6fa268780caff9c
License: Apache 2.0
License File: NOT_SHIPPED
Security Critical: No
Description:
A tool for generating interface .jars from normal .jars.
Local Modifications:
- Removed test directory
- Removed code from platform_utils.cc that referenced "blaze_util".
- Removed mapped_file_windows.cc since it caused checkdeps to fail.
- Added BUILD.gn
ijar: A tool for generating interface .jars from normal .jars
=============================================================
Alan Donovan, 26 May 2007.
Rationale:
In order to improve the speed of compilation of Java programs in
Bazel, the output of build steps is cached.
This works very nicely for C++ compilation: a compilation unit
includes a .cc source file and typically dozens of header files.
Header files change relatively infrequently, so the need for a
rebuild is usually driven by a change in the .cc file. Even after
syncing a slightly newer version of the tree and doing a rebuild,
many hits in the cache are still observed.
In Java, by contrast, a compilation unit involves a set of .java
source files, plus a set of .jar files containing already-compiled
JVM .class files. Class files serve a dual purpose: from the JVM's
perspective, they are containers of executable code, but from the
compiler's perspective, they are interface definitions. The problem
here is that .jar files are very much more sensitive to change than
C++ header files, so even a change that is insignificant to the
compiler (such as the addition of a print statement to a method in a
prerequisite class) will cause the jar to change, and any code that
depends on this jar's interface will be recompiled unnecessarily.
The purpose of ijar is to produce, from a .jar file, a much smaller,
simpler .jar file containing only the parts that are significant for
the purposes of compilation. In other words, an interface .jar
file. By changing ones compilation dependencies to be the interface
jar files, unnecessary recompilation is avoided when upstream
changes don't affect the interface.
Details:
ijar is a tool that reads a .jar file and emits a .jar file
containing only the parts that are relevant to Java compilation.
For example, it throws away:
- Files whose name does not end in ".class".
- All executable method code.
- All private methods and fields.
- All constants and attributes except the minimal set necessary to
describe the class interface.
- All debugging information
(LineNumberTable, SourceFile, LocalVariableTables attributes).
It also sets to zero the file modification times in the index of the
.jar file.
Implementation:
ijar is implemented in C++, and runs very quickly. For example
(when optimized) it takes only 530ms to process a 42MB
.jar file containing 5878 classes, resulting in an interface .jar
file of only 11.4MB in size. For more usual .jar sizes of a few
megabytes, a runtime of 50ms is typical.
The implementation strategy is to mmap both the input jar and the
newly-created _interface.jar, and to scan through the former and
emit the latter in a single pass. There are a couple of locations
where some kind of "backpatching" is required:
- in the .zip file format, for each file, the size field precedes
the data. We emit a zero but note its location, generate and emit
the stripped classfile, then poke the correct size into the
location.
- for JVM .class files, the header (including the constant table)
precedes the body, but cannot be emitted before it because it's
not until we emit the body that we know which constants are
referenced and which are garbage. So we emit the body into a
temporary buffer, then emit the header to the output jar, followed
by the contents of the temp buffer.
Also note that the zip file format has unnecessary duplication of
the index metadata: it has header+data for each file, then another
set of (similar) headers at the end. Rather than save the metadata
explicitly in some datastructure, we just record the addresses of
the already-emitted zip metadata entries in the output file, and
then read from there as necessary.
Notes:
This code has no dependency except on the STL and on zlib.
Almost all of the getX/putX/ReadX/WriteX functions in the code
advance their first argument pointer, which is passed by reference.
It's tempting to discard package-private classes and class members.
However, this would be incorrect because they are a necessary part
of the package interface, as a Java package is often compiled in
multiple stages. For example: in Bazel, both java tests and java
code inhabit the same Java package but are compiled separately.
Assumptions:
We assume that jar files are uncompressed v1.0 zip files (created
with 'jar c0f') with a zero general_purpose_bit_flag.
We assume that javap/javac don't need the correct CRC checksums in
the .jar file.
We assume that it's better simply to abort in the face of unknown
input than to risk leaving out something important from the output
(although in the case of annotations, it should be safe to ignore
ones we don't understand).
TODO:
Maybe: ensure a canonical sort order is used for every list (jar
entries, class members, attributes, etc.) This isn't essential
because we can assume the compiler is deterministic and the order in
the source files changes little. Also, it would require two passes. :(
Maybe: delete dynamically-allocated memory.
Add (a lot) more tests. Include a test of idempotency.
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// 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.
//
// common.h -- common definitions.
//
#ifndef INCLUDED_DEVTOOLS_IJAR_COMMON_H
#define INCLUDED_DEVTOOLS_IJAR_COMMON_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#ifdef _WIN32
# define PATH_MAX 4096
typedef int mode_t;
#endif // _WIN32
namespace devtools_ijar
{
typedef unsigned long long u8;
typedef uint32_t u4;
typedef uint16_t u2;
typedef uint8_t u1;
// be = big endian, le = little endian
inline u1 get_u1(const u1 *&p)
{
return *p++;
}
inline u2 get_u2be(const u1 *&p)
{
u4 x = (p[0] << 8) | p[1];
p += 2;
return x;
}
inline u2 get_u2le(const u1 *&p)
{
u4 x = (p[1] << 8) | p[0];
p += 2;
return x;
}
inline u4 get_u4be(const u1 *&p)
{
u4 x = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
p += 4;
return x;
}
inline u4 get_u4le(const u1 *&p)
{
u4 x = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
p += 4;
return x;
}
inline u8 get_u8le(const u1 *&p)
{
u4 lo = get_u4le(p);
u4 hi = get_u4le(p);
u8 x = ((u8)hi << 32) | lo;
return x;
}
inline void put_u1(u1 *&p, u1 x)
{
*p++ = x;
}
inline void put_u2be(u1 *&p, u2 x)
{
*p++ = x >> 8;
*p++ = x & 0xff;
}
inline void put_u2le(u1 *&p, u2 x)
{
*p++ = x & 0xff;
*p++ = x >> 8;
;
}
inline void put_u4be(u1 *&p, u4 x)
{
*p++ = x >> 24;
*p++ = (x >> 16) & 0xff;
*p++ = (x >> 8) & 0xff;
*p++ = x & 0xff;
}
inline void put_u4le(u1 *&p, u4 x)
{
*p++ = x & 0xff;
*p++ = (x >> 8) & 0xff;
*p++ = (x >> 16) & 0xff;
*p++ = x >> 24;
}
inline void put_u8le(u1 *&p, u8 x)
{
put_u4le(p, x & 0xffffffff);
put_u4le(p, (x >> 32) & 0xffffffff);
}
// Copy n bytes from src to p, and advance p.
inline void put_n(u1 *&p, const u1 *src, size_t n)
{
memcpy(p, src, n);
p += n;
}
extern bool verbose;
} // namespace devtools_ijar
#endif // INCLUDED_DEVTOOLS_IJAR_COMMON_H
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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 <algorithm>
#include "third_party/ijar/common.h"
#include "third_party/ijar/zlib_client.h"
namespace devtools_ijar
{
u4 ComputeCrcChecksum(u1 *buf, size_t length)
{
return 0;
}
size_t TryDeflate(u1 *buf, size_t length)
{
return 0;
}
Decompressor::Decompressor() {}
Decompressor::~Decompressor() {}
DecompressedFile *Decompressor::UncompressFile(const u1 *buffer, size_t bytes_avail)
{
return NULL;
}
char *Decompressor::GetError()
{
return NULL;
}
int Decompressor::error(const char *fmt, ...)
{
return 0;
}
} // namespace devtools_ijar
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// 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 INCLUDED_THIRD_PARTY_IJAR_MAPPED_FILE_H
#define INCLUDED_THIRD_PARTY_IJAR_MAPPED_FILE_H
#include "third_party/ijar/common.h"
namespace devtools_ijar
{
struct MappedInputFileImpl;
struct MappedOutputFileImpl;
// A memory mapped input file.
class MappedInputFile
{
private:
MappedInputFileImpl *impl_;
protected:
const char *errmsg_;
bool opened_;
u1 *buffer_;
size_t length_;
public:
MappedInputFile(const char *name);
virtual ~MappedInputFile();
// If opening the file succeeded or not.
bool Opened() const { return opened_; }
// Description of the last error that happened.
const char *Error() const { return errmsg_; }
// The mapped contents of the file.
u1 *Buffer() const { return buffer_; }
// The length of the file.
size_t Length() const { return length_; }
// Unmap a given number of bytes from the beginning of the file.
void Discard(size_t bytes);
int Close();
};
class MappedOutputFile
{
private:
MappedOutputFileImpl *impl_;
protected:
const char *errmsg_;
bool opened_;
u1 *buffer_;
size_t estimated_size_;
public:
MappedOutputFile(const char *name, size_t estimated_size);
virtual ~MappedOutputFile();
// If opening the file succeeded or not.
bool Opened() const { return opened_; }
// Description of the last error that happened.
const char *Error() const { return errmsg_; }
// The mapped contents of the file.
u1 *Buffer() const { return buffer_; }
int Close(size_t size);
};
} // namespace devtools_ijar
#endif
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <algorithm>
#include "third_party/ijar/mapped_file.h"
#define MAX_ERROR 2048
namespace devtools_ijar
{
static char errmsg[MAX_ERROR];
struct MappedInputFileImpl
{
size_t discarded_;
int fd_;
};
MappedInputFile::MappedInputFile(const char *name)
{
impl_ = NULL;
opened_ = false;
int fd = open(name, O_RDONLY);
if (fd < 0)
{
snprintf(errmsg, MAX_ERROR, "open(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}
off_t length = lseek(fd, 0, SEEK_END);
if (length < 0)
{
snprintf(errmsg, MAX_ERROR, "lseek(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}
void *buffer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
if (buffer == MAP_FAILED)
{
snprintf(errmsg, MAX_ERROR, "mmap(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}
impl_ = new MappedInputFileImpl();
impl_->fd_ = fd;
impl_->discarded_ = 0;
buffer_ = reinterpret_cast<u1 *>(buffer);
length_ = length;
opened_ = true;
}
MappedInputFile::~MappedInputFile()
{
delete impl_;
}
void MappedInputFile::Discard(size_t bytes)
{
munmap(buffer_ + impl_->discarded_, bytes);
impl_->discarded_ += bytes;
}
int MappedInputFile::Close()
{
if (close(impl_->fd_) < 0)
{
snprintf(errmsg, MAX_ERROR, "close(): %s", strerror(errno));
errmsg_ = errmsg;
return -1;
}
return 0;
}
struct MappedOutputFileImpl
{
int fd_;
int mmap_length_;
};
MappedOutputFile::MappedOutputFile(const char *name, size_t estimated_size)
: estimated_size_(estimated_size)
{
impl_ = NULL;
opened_ = false;
int fd = open(name, O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd < 0)
{
snprintf(errmsg, MAX_ERROR, "open(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}
// Create mmap-able sparse file
if (ftruncate(fd, estimated_size) < 0)
{
snprintf(errmsg, MAX_ERROR, "ftruncate(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}
// Ensure that any buffer overflow in JarStripper will result in
// SIGSEGV or SIGBUS by over-allocating beyond the end of the file.
size_t mmap_length = std::min(static_cast<size_t>(estimated_size + sysconf(_SC_PAGESIZE)),
std::numeric_limits<size_t>::max());
void *mapped = mmap(NULL, mmap_length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mapped == MAP_FAILED)
{
snprintf(errmsg, MAX_ERROR, "mmap(): %s", strerror(errno));
errmsg_ = errmsg;
return;
}
impl_ = new MappedOutputFileImpl();
impl_->fd_ = fd;
impl_->mmap_length_ = mmap_length;
buffer_ = reinterpret_cast<u1 *>(mapped);
opened_ = true;
}
MappedOutputFile::~MappedOutputFile()
{
delete impl_;
}
int MappedOutputFile::Close(size_t size)
{
if (size > estimated_size_)
{
snprintf(errmsg, MAX_ERROR, "size %zu > estimated size %zu", size, estimated_size_);
errmsg_ = errmsg;
return -1;
}
munmap(buffer_, impl_->mmap_length_);
if (ftruncate(impl_->fd_, size) < 0)
{
snprintf(errmsg, MAX_ERROR, "ftruncate(): %s", strerror(errno));
errmsg_ = errmsg;
return -1;
}
if (close(impl_->fd_) < 0)
{
snprintf(errmsg, MAX_ERROR, "close(): %s", strerror(errno));
errmsg_ = errmsg;
return -1;
}
return 0;
}
} // namespace devtools_ijar
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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 "third_party/ijar/platform_utils.h"
#include <limits.h>
#include <stdio.h>
#if defined(_WIN32) || defined(__CYGWIN__)
# include <windows.h>
#else // !(defined(_WIN32) || defined(__CYGWIN__))
# include <sys/stat.h>
# include <sys/types.h>
# include <unistd.h>
#endif // defined(_WIN32) || defined(__CYGWIN__)
#include <string>
namespace devtools_ijar
{
using std::string;
bool stat_file(const char *path, Stat *result)
{
#if defined(_WIN32) || defined(__CYGWIN__)
std::wstring wpath;
std::string error;
bool success = false;
BY_HANDLE_FILE_INFORMATION info;
HANDLE handle = ::CreateFileW(
/* lpFileName */ wpath.c_str(),
/* dwDesiredAccess */ GENERIC_READ,
/* dwShareMode */ FILE_SHARE_READ,
/* lpSecurityAttributes */ NULL,
/* dwCreationDisposition */ OPEN_EXISTING,
/* dwFlagsAndAttributes */ FILE_ATTRIBUTE_NORMAL,
/* hTemplateFile */ NULL);
if (handle == INVALID_HANDLE_VALUE)
{
// Opening it as a file failed, try opening it as a directory.
handle = ::CreateFileW(
/* lpFileName */ wpath.c_str(),
/* dwDesiredAccess */ GENERIC_READ,
/* dwShareMode */ FILE_SHARE_READ,
/* lpSecurityAttributes */ NULL,
/* dwCreationDisposition */ OPEN_EXISTING,
/* dwFlagsAndAttributes */ FILE_FLAG_BACKUP_SEMANTICS,
/* hTemplateFile */ NULL);
}
if (handle != INVALID_HANDLE_VALUE && ::GetFileInformationByHandle(handle, &info))
{
success = true;
bool is_dir = (info.dwFileAttributes != INVALID_FILE_ATTRIBUTES) &&
(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
// TODO(laszlocsomor): use info.nFileSizeHigh after we updated total_size to
// be u8 type.
result->total_size = is_dir ? 0 : info.nFileSizeLow;
// TODO(laszlocsomor): query the actual permissions and write in file_mode.
result->file_mode = 0777;
result->is_directory = is_dir;
}
::CloseHandle(handle);
return success;
#else // !(defined(_WIN32) || defined(__CYGWIN__))
struct stat statst;
if (stat(path, &statst) < 0)
{
return false;
}
result->total_size = statst.st_size;
result->file_mode = statst.st_mode;
result->is_directory = (statst.st_mode & S_IFDIR) != 0;
return true;
#endif
}
} // namespace devtools_ijar
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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 THIRD_PARTY_IJAR_PLATFORM_UTILS_H_
#define THIRD_PARTY_IJAR_PLATFORM_UTILS_H_
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string>
#include "third_party/ijar/common.h"
namespace devtools_ijar
{
// Platform-independent stat data.
struct Stat
{
// Total size of the file in bytes.
int total_size;
// The Unix file mode from the stat.st_mode field.
mode_t file_mode;
// True if this is a directory.
bool is_directory;
};
// Converts a Stat object to ZIP attributes.
inline u4 stat_to_zipattr(const Stat &file_stat)
{
return (((u4)file_stat.file_mode) << 16) | (file_stat.is_directory != 0 ? 0x10 : 0);
}
// Writes stat data into `result` about the file under `path`.
// Returns true if file is found and can be stat'ed.
// Returns false if the file is not found or cannot be stat'ed.
// Doesn't report any errors because it can also be used to simply check if a
// file exists.
bool stat_file(const char *path, Stat *result);
// Writes `size` bytes from `data` into file under `path`.
// The file is created or overwritten and is set to have `perm` permissions.
// Returns true upon success: file is created and all data is written.
// Returns false upon failure and reports the error to stderr.
bool write_file(const char *path, unsigned int perm, const void *data, size_t size);
// Reads at most `size` bytes into `buffer` from the file under `path`.
// Returns true upon success: file is opened and all data is read.
// Returns false upon failure and reports the error to stderr.
bool read_file(const char *path, void *buffer, size_t size);
// Returns the current working directory.
// Returns the empty string upon failure and reports the error to stderr.
std::string get_cwd();
// Do a recursive mkdir of all folders of path except the last path
// segment (if path ends with a / then the last path segment is empty).
// All folders are created using "perm" for creation mode, and are writable and
// openable by the current user.
// Returns true if all directories were created and permissions set.
// Returns false upon failure and reports the error to stderr.
bool make_dirs(const char *path, unsigned int perm);
} // namespace devtools_ijar
#endif // THIRD_PARTY_IJAR_PLATFORM_UTILS_H_
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// 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.
//
// zip.h -- .zip (.jar) file reading/writing routines.
//
// This file specifies the interface to use the ZIP implementation of ijar.
//
#ifndef INCLUDED_THIRD_PARTY_IJAR_ZIP_H
#define INCLUDED_THIRD_PARTY_IJAR_ZIP_H
#include <sys/stat.h>
#include "third_party/ijar/common.h"
namespace devtools_ijar
{
// Tells if this is a directory entry from the mode. This method
// is safer than zipattr_to_mode(attr) & S_IFDIR because the unix
// mode might not be set in DOS zip files.
inline bool zipattr_is_dir(u4 attr)
{
return (attr & 0x10) != 0;
}
// Convert a ZIP file attribute to a Unix file permission mask.
inline mode_t zipattr_to_perm(u4 attr)
{
return ((mode_t)((attr >> 16) & 0777));
}
//
// Class interface for building ZIP files
//
class ZipBuilder
{
public:
virtual ~ZipBuilder() {}
// Returns the text for the last error, or null on no last error.
virtual const char *GetError() = 0;
// Add a new file to the ZIP, the file will have path "filename"
// and external attributes "attr". This function returns a pointer
// to a memory buffer to write the data of the file into. This buffer
// is owned by ZipBuilder and should not be free'd by the caller. The
// file length is then specified when the files is finished written
// using the FinishFile(size_t) function.
// On failure, returns NULL and GetError() will return an non-empty message.
virtual u1 *NewFile(const char *filename, const u4 attr) = 0;
// Finish writing a file and specify its length. After calling this method
// one should not reuse the pointer given by NewFile. The file can be
// compressed using the deflate algorithm by setting `compress` to true.
// By default, CRC32 are not computed as java tooling doesn't care, but
// computing it can be activated by setting `compute_crc` to true.
// On failure, returns -1 and GetError() will return an non-empty message.
virtual int FinishFile(size_t filelength, bool compress = false, bool compute_crc = false) = 0;
// Write an empty file, it is equivalent to:
// NewFile(filename, 0);
// FinishFile(0);
// On failure, returns -1 and GetError() will return an non-empty message.
virtual int WriteEmptyFile(const char *filename) = 0;
// Finish writing the ZIP file. This method can be called only once
// (subsequent calls will do nothing) and none of
// NewFile/FinishFile/WriteEmptyFile should be called after calling Finish. If
// this method was not called when the object is destroyed, it will be called.
// It is here as a convenience to get information on the final generated ZIP
// file.
// On failure, returns -1 and GetError() will return an non-empty message.
virtual int Finish() = 0;
// Get the current size of the ZIP file. This size will not be matching the
// final ZIP file until Finish() has been called because Finish() is actually
// writing the central directory of the ZIP File.
virtual size_t GetSize() = 0;
// Returns the current number of files stored in the ZIP.
virtual int GetNumberFiles() = 0;
// Create a new ZipBuilder writing the file zip_file and the size of the
// output will be at most estimated_size. Use ZipBuilder::EstimateSize() or
// ZipExtractor::CalculateOuputLength() to have an estimated_size depending on
// a list of file to store.
// On failure, returns NULL. Refer to errno for error code.
static ZipBuilder *Create(const char *zip_file, size_t estimated_size);
// Estimate the maximum size of the ZIP files containing files in the "files"
// null-terminated array.
// Returns 0 on error.
static u8 EstimateSize(char const *const *files, char const *const *zip_paths, int nb_entries);
};
//
// An abstract class to process data from a ZipExtractor.
// Derive from this class if you wish to process data from a ZipExtractor.
//
class ZipExtractorProcessor
{
public:
virtual ~ZipExtractorProcessor() {}
// Tells whether to skip or process the file "filename". "attr" is the
// external file attributes and can be converted to unix mode using the
// zipattr_to_mode() function. This method is suppoed to returns true
// if the file should be processed and false if it should be skipped.
virtual bool Accept(const char *filename, const u4 attr) = 0;
// Process a file accepted by Accept. The file "filename" has external
// attributes "attr" and length "size". The file content is accessible
// in the buffer pointed by "data".
virtual void Process(const char *filename,
const u4 attr,
const u1 *data,
const size_t size) = 0;
};
//
// Class interface for reading ZIP files
//
class ZipExtractor
{
public:
virtual ~ZipExtractor() {}
// Returns the text for the last error, or null on no last error.
virtual const char *GetError() = 0;
// Process the next files, returns false if the end of ZIP file has been
// reached. The processor provided by the Create method will be called
// if a file is encountered. If false is returned, check the return value
// of GetError() for potential errors.
virtual bool ProcessNext() = 0;
// Process the all files, returns -1 on error (GetError() will be populated
// on error).
virtual int ProcessAll();
// Reset the file pointer to the beginning.
virtual void Reset() = 0;
// Return the size of the ZIP file.
virtual size_t GetSize() = 0;
// Return the size of the resulting zip file by keeping only file
// accepted by the processor and storing them uncompressed. This
// method can be used to create a ZipBuilder for storing a subset
// of the input files.
// On error, 0 is returned and GetError() returns a non-empty message.
virtual u8 CalculateOutputLength() = 0;
// Create a ZipExtractor that extract the zip file "filename" and process
// it with "processor".
// On error, a null pointer is returned and the value of errno should be
// checked.
static ZipExtractor *Create(const char *filename, ZipExtractorProcessor *processor);
};
} // namespace devtools_ijar
#endif // INCLUDED_THIRD_PARTY_IJAR_ZIP_H
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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 <stdlib.h>
#include <algorithm>
#include <cstdio>
#include <zlib.h>
#include "third_party/ijar/common.h"
#include "third_party/ijar/zlib_client.h"
namespace devtools_ijar
{
u4 ComputeCrcChecksum(u1 *buf, size_t length)
{
return crc32(0, buf, length);
}
size_t TryDeflate(u1 *buf, size_t length)
{
u1 *outbuf = reinterpret_cast<u1 *>(malloc(length));
z_stream stream;
// Initialize the z_stream strcut for reading from buf and wrinting in outbuf.
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.total_in = length;
stream.avail_in = length;
stream.total_out = length;
stream.avail_out = length;
stream.next_in = buf;
stream.next_out = outbuf;
// deflateInit2 negative windows size prevent the zlib wrapper to be used.
if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8,
Z_DEFAULT_STRATEGY) != Z_OK)
{
// Failure to compress => return the buffer uncompressed
free(outbuf);
return length;
}
if (deflate(&stream, Z_FINISH) == Z_STREAM_END)
{
// Compression successful and fits in outbuf, let's copy the result in buf.
length = stream.total_out;
memcpy(buf, outbuf, length);
}
deflateEnd(&stream);
free(outbuf);
// Return the length of the resulting buffer
return length;
}
Decompressor::Decompressor()
{
uncompressed_data_allocated_ = INITIAL_BUFFER_SIZE;
uncompressed_data_ = reinterpret_cast<u1 *>(malloc(uncompressed_data_allocated_));
}
Decompressor::~Decompressor()
{
free(uncompressed_data_);
}
DecompressedFile *Decompressor::UncompressFile(const u1 *buffer, size_t bytes_avail)
{
z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = bytes_avail;
stream.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(buffer));
int ret = inflateInit2(&stream, -MAX_WBITS);
if (ret != Z_OK)
{
error("inflateInit: %d\n", ret);
return NULL;
}
int uncompressed_until_now = 0;
while (true)
{
stream.avail_out = uncompressed_data_allocated_ - uncompressed_until_now;
stream.next_out = uncompressed_data_ + uncompressed_until_now;
int old_avail_out = stream.avail_out;
ret = inflate(&stream, Z_SYNC_FLUSH);
int uncompressed_now = old_avail_out - stream.avail_out;
uncompressed_until_now += uncompressed_now;
switch (ret)
{
case Z_STREAM_END:
{
struct DecompressedFile *decompressedFile =
reinterpret_cast<DecompressedFile *>(malloc(sizeof(DecompressedFile)));
// zlib said that there is no more data to decompress.
u1 *new_p = reinterpret_cast<u1 *>(stream.next_in);
decompressedFile->compressed_size = new_p - buffer;
decompressedFile->uncompressed_size = uncompressed_until_now;
decompressedFile->uncompressed_data = uncompressed_data_;
inflateEnd(&stream);
return decompressedFile;
}
case Z_OK:
{
// zlib said that there is no more room in the buffer allocated for
// the decompressed data. Enlarge that buffer and try again.
if (uncompressed_data_allocated_ == MAX_BUFFER_SIZE)
{
error(
"ijar does not support decompressing files "
"larger than %dMB.\n",
static_cast<int>((MAX_BUFFER_SIZE / (1024 * 1024))));
return NULL;
}
uncompressed_data_allocated_ *= 2;
if (uncompressed_data_allocated_ > MAX_BUFFER_SIZE)
{
uncompressed_data_allocated_ = MAX_BUFFER_SIZE;
}
uncompressed_data_ = reinterpret_cast<u1 *>(
realloc(uncompressed_data_, uncompressed_data_allocated_));
break;
}
case Z_DATA_ERROR:
case Z_BUF_ERROR:
case Z_STREAM_ERROR:
case Z_NEED_DICT:
default:
{
error("zlib returned error code %d during inflate.\n", ret);
return NULL;
}
}
}
}
char *Decompressor::GetError()
{
if (errmsg[0] == 0)
{
return NULL;
}
return errmsg;
}
int Decompressor::error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(errmsg, 4 * PATH_MAX, fmt, ap);
va_end(ap);
return -1;
}
} // namespace devtools_ijar
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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 THIRD_PARTY_IJAR_ZLIB_CLIENT_H_
#define THIRD_PARTY_IJAR_ZLIB_CLIENT_H_
#include <limits.h>
#include "third_party/ijar/common.h"
namespace devtools_ijar
{
// Try to compress a file entry in memory using the deflate algorithm.
// It will compress buf (of size length) unless the compressed size is bigger
// than the input size. The result will overwrite the content of buf and the
// final size is returned.
size_t TryDeflate(u1 *buf, size_t length);
u4 ComputeCrcChecksum(u1 *buf, size_t length);
struct DecompressedFile
{
u1 *uncompressed_data;
u4 uncompressed_size;
u4 compressed_size;
};
class Decompressor
{
public:
Decompressor();
~Decompressor();
DecompressedFile *UncompressFile(const u1 *buffer, size_t bytes_avail);
char *GetError();
private:
// Administration of memory reserved for decompressed data. We use the same
// buffer for each file to avoid some malloc()/free() calls and free the
// memory only in the dtor. C-style memory management is used so that we
// can call realloc.
u1 *uncompressed_data_;
size_t uncompressed_data_allocated_;
// last error
char errmsg[4 * PATH_MAX];
int error(const char *fmt, ...);
// Buffer size is initially INITIAL_BUFFER_SIZE. It doubles in size every
// time it is found too small, until it reaches MAX_BUFFER_SIZE. If that is
// not enough, we bail out. We only decompress class files, so they should
// be smaller than 64K anyway, but we give a little leeway.
// MAX_BUFFER_SIZE must be bigger than the size of the biggest file in the
// ZIP. It is set to 2GB here because no one has audited the code for 64-bit
// cleanliness.
static const size_t INITIAL_BUFFER_SIZE = 256 * 1024; // 256K
static const size_t MAX_BUFFER_SIZE = std::numeric_limits<int32_t>::max();
};
} // namespace devtools_ijar
#endif // THIRD_PARTY_IJAR_ZLIB_CLIENT_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment