| // 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 BAZEL_SRC_TOOLS_SINGLEJAR_INPUT_JAR_H_ |
| #define BAZEL_SRC_TOOLS_SINGLEJAR_INPUT_JAR_H_ 1 |
| |
| #ifndef __STDC_FORMAT_MACROS |
| #define __STDC_FORMAT_MACROS 1 |
| #endif |
| |
| #include <inttypes.h> |
| #include <stdlib.h> |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <string> |
| |
| #include "src/tools/singlejar/diag.h" |
| #include "src/tools/singlejar/mapped_file.h" |
| #include "src/tools/singlejar/zip_headers.h" |
| |
| /* |
| * An input jar. The usage pattern is: |
| * InputJar input_jar; |
| * if (!input_jar.Open("path/to/file")) { fail...} |
| * CDH *dir_entry; |
| * LH *local_header; |
| * while (dir_entry = input_jar.NextEntry(&local_header)) { |
| * // process entry. |
| * } |
| * input_jar.Close(); // actually, called by destructor, too. |
| */ |
| class InputJar { |
| public: |
| InputJar() {} |
| |
| ~InputJar() { Close(); } |
| |
| #ifndef _WIN32 |
| // Not used on Windows, only in Google's own code. Don't add more usage of it. |
| int fd() const { return mapped_file_.fd(); } |
| #endif |
| |
| // Opens the file, memory maps it and locates Central Directory. |
| bool Open(const std::string &path); |
| |
| // Creates an input jar from data that's already in memory. |
| // Requires a non-empty path for use in diagnostics. |
| bool Open(const std::string &path, unsigned char *data, size_t length); |
| |
| // Returns the next Central Directory Header or nullptr. |
| const CDH *NextEntry(const LH **local_header_ptr) { |
| if (path_.empty()) { |
| diag_errx(1, "%s:%d: call Open() first!", __FILE__, __LINE__); |
| } |
| if (!cdh_->is()) { |
| return nullptr; |
| } |
| const CDH *current_cdh = cdh_; |
| const uint8_t *new_cdr = ziph::byte_ptr(cdh_) + cdh_->size(); |
| if (!mapped_file_.mapped(new_cdr)) { |
| diag_errx( |
| 1, |
| "Bad directory record at offset 0x%" PRIx64 " of %s\n" |
| "file name length = %u, extra_field length = %u, comment length = %u", |
| CentralDirectoryRecordOffset(cdh_), path_.c_str(), |
| cdh_->file_name_length(), cdh_->extra_fields_length(), |
| cdh_->comment_length()); |
| } |
| cdh_ = reinterpret_cast<const CDH *>(new_cdr); |
| *local_header_ptr = LocalHeader(current_cdh); |
| return current_cdh; |
| } |
| |
| // Closes the file. |
| bool Close(); |
| |
| uint64_t CentralDirectoryRecordOffset(const void *cdr) const { |
| return mapped_file_.offset(cdr); |
| } |
| |
| const LH *LocalHeader(const CDH *cdh) const { |
| return reinterpret_cast<const LH *>( |
| mapped_file_.address(cdh->local_header_offset() + preamble_size_)); |
| } |
| |
| uint64_t LocalHeaderOffset(const LH *lh) const { |
| return mapped_file_.offset(lh); |
| } |
| |
| const uint8_t *mapped_start() const { |
| return mapped_file_.address(0); |
| } |
| |
| private: |
| bool LocateCentralDirectory(const std::string &path); |
| |
| std::string path_; |
| MappedFile mapped_file_; |
| const CDH *cdh_; // current directory entry |
| uint64_t preamble_size_; // Bytes before the Zip proper. |
| }; |
| |
| #endif // BAZEL_SRC_TOOLS_SINGLEJAR_INPUT_JAR_H_ |