blob: 858afe09f25392c546282a28fe16fa1a1dc7187a [file] [log] [blame]
Brian Carlstromb0460ea2011-07-29 10:08:05 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_SRC_ZIP_ARCHIVE_H_
18#define ART_SRC_ZIP_ARCHIVE_H_
19
20#include <map>
21#include <stdint.h>
22#include <sys/mman.h>
23#include <zlib.h>
24
25#include "globals.h"
26#include "logging.h"
27#include "scoped_ptr.h"
28#include "stringpiece.h"
Brian Carlstrom7e93b502011-08-04 14:16:22 -070029#include "unordered_map.h"
Brian Carlstromb0460ea2011-07-29 10:08:05 -070030
31namespace art {
32
33class ZipArchive;
34class MemMap;
35
36class ZipEntry {
37
38 public:
39 // Uncompress an entry, in its entirety, to an open file descriptor.
40 bool Extract(int fd);
41
42 uint32_t GetCrc32();
43
44 private:
45
46 ZipEntry(ZipArchive* zip_archive, const uint8_t* ptr) : zip_archive_(zip_archive), ptr_(ptr) {};
47
48 // Zip compression methods
49 enum {
50 kCompressStored = 0, // no compression
51 kCompressDeflated = 8, // standard deflate
52 };
53
54 // kCompressStored, kCompressDeflated, ...
55 uint16_t GetCompressionMethod();
56
57 uint32_t GetCompressedLength();
58
59 uint32_t GetUncompressedLength();
60
61 // returns -1 on error
62 off_t GetDataOffset();
63
64 ZipArchive* zip_archive_;
65
66 // pointer to zip entry within central directory
67 const uint8_t* ptr_;
68
69 friend class ZipArchive;
70};
71
72// Used to keep track of unaligned mmap segments.
73class MemMap {
74 public:
75
76 // Map part of a file into a shared, read-only memory segment. The "start"
77 // offset is absolute, not relative.
78 //
79 // On success, returns returns a MemMap instance. On failure, returns a NULL;
80 static MemMap* Map(int fd, off_t start, size_t length) {
81 // adjust to be page-aligned
82 int page_offset = start % kPageSize;
83 off_t page_aligned_offset = start - page_offset;
84 size_t page_aligned_size = length + page_offset;
85 uint8_t* addr = reinterpret_cast<uint8_t*>(mmap(NULL,
86 page_aligned_size,
87 PROT_READ,
88 MAP_FILE | MAP_SHARED,
89 fd,
90 page_aligned_offset));
91 if (addr == MAP_FAILED) {
92 return NULL;
93 }
94 return new MemMap(addr+page_offset, length, addr, page_aligned_size);
95 }
96
97 ~MemMap() {
98 Unmap();
99 };
100
101 // Release a memory mapping, returning true on success or it was previously unmapped.
102 bool Unmap() {
103 if (base_addr_ == NULL && base_length_ == 0) {
104 return true;
105 }
106 int result = munmap(base_addr_, base_length_);
107 if (result != 0) {
108 return false;
109 }
110 base_addr_ = NULL;
111 base_length_ = 0;
112 return true;
113 }
114
115 void* GetAddress() {
116 return addr_;
117 }
118
119 size_t GetLength() {
120 return length_;
121 }
122
123 private:
124 MemMap(void* addr, size_t length, void* base_addr, size_t base_length)
125 : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) {
126 CHECK(addr_ != NULL);
127 CHECK(length_ != 0);
128 CHECK(base_addr_ != NULL);
129 CHECK(base_length_ != 0);
130 };
131
132 void* addr_; // start of data
133 size_t length_; // length of data
134
135 void* base_addr_; // page-aligned base address
136 size_t base_length_; // length of mapping
137};
138
139class ZipArchive {
140 public:
141
142 // Zip file constants.
143 static const uint32_t kEOCDSignature = 0x06054b50;
144 static const int32_t kEOCDLen = 22;
145 static const int32_t kEOCDNumEntries = 8; // offset to #of entries in file
146 static const int32_t kEOCDSize = 12; // size of the central directory
147 static const int32_t kEOCDFileOffset = 16; // offset to central directory
148
149 static const int32_t kMaxCommentLen = 65535; // longest possible in uint16_t
150 static const int32_t kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen);
151
152 static const uint32_t kLFHSignature = 0x04034b50;
153 static const int32_t kLFHLen = 30; // excluding variable-len fields
154 static const int32_t kLFHNameLen = 26; // offset to filename length
155 static const int32_t kLFHExtraLen = 28; // offset to extra length
156
157 static const uint32_t kCDESignature = 0x02014b50;
158 static const int32_t kCDELen = 46; // excluding variable-len fields
159 static const int32_t kCDEMethod = 10; // offset to compression method
160 static const int32_t kCDEModWhen = 12; // offset to modification timestamp
161 static const int32_t kCDECRC = 16; // offset to entry CRC
162 static const int32_t kCDECompLen = 20; // offset to compressed length
163 static const int32_t kCDEUncompLen = 24; // offset to uncompressed length
164 static const int32_t kCDENameLen = 28; // offset to filename length
165 static const int32_t kCDEExtraLen = 30; // offset to extra length
166 static const int32_t kCDECommentLen = 32; // offset to comment length
167 static const int32_t kCDELocalOffset = 42; // offset to local hdr
168
169 static ZipArchive* Open(const std::string& filename);
170 ZipEntry* Find(const char * name);
171
172 ~ZipArchive() {
173 Close();
174 }
175
176 private:
177 ZipArchive(int fd) : fd_(fd), num_entries_(0), dir_offset_(0) {}
178
179 bool MapCentralDirectory();
180 bool Parse();
181 void Close();
182
183 int fd_;
184 uint16_t num_entries_;
185 off_t dir_offset_;
186 scoped_ptr<MemMap> dir_map_;
Brian Carlstrom7e93b502011-08-04 14:16:22 -0700187 typedef std::tr1::unordered_map<StringPiece, const uint8_t*> DirEntries;
188 DirEntries dir_entries_;
Brian Carlstromb0460ea2011-07-29 10:08:05 -0700189
190 friend class ZipEntry;
191};
192
193} // namespace art
194
195#endif // ART_SRC_ZIP_ARCHIVE_H_