1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Protocol Buffers - Google's data interchange format
32 // Copyright 2008 Google Inc. All rights reserved.
33 // https://developers.google.com/protocol-buffers/
34 //
35 // Redistribution and use in source and binary forms, with or without
36 // modification, are permitted provided that the following conditions are
37 // met:
38 //
39 // * Redistributions of source code must retain the above copyright
40 // notice, this list of conditions and the following disclaimer.
41 // * Redistributions in binary form must reproduce the above
42 // copyright notice, this list of conditions and the following disclaimer
43 // in the documentation and/or other materials provided with the
44 // distribution.
45 // * Neither the name of Google Inc. nor the names of its
46 // contributors may be used to endorse or promote products derived from
47 // this software without specific prior written permission.
48 //
49 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60
61 // Author: ambrose@google.com (Ambrose Feinstein),
62 // kenton@google.com (Kenton Varda)
63 //
64 // Based on http://www.pkware.com/documents/casestudies/APPNOTE.TXT
65
66 #include <google/protobuf/compiler/zip_writer.h>
67 #include <google/protobuf/io/coded_stream.h>
68
69 namespace google {
70 namespace protobuf {
71 namespace compiler {
72
73 // January 1, 1980 as a DOS date.
74 // see https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx
75 static const uint16 kDosEpoch = 1 << 5 | 1;
76
77 static const uint32 kCRC32Table[256] = {
78 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
79 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
80 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
81 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
82 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
83 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
84 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
85 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
86 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
87 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
88 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
89 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
90 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
91 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
92 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
93 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
94 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
95 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
96 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
97 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
98 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
99 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
100 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
101 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
102 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
103 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
104 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
105 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
106 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
107 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
108 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
109 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
110 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
111 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
112 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
113 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
114 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
115 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
116 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
117 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
118 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
119 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
120 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
121
ComputeCRC32(const std::string & buf)122 static uint32 ComputeCRC32(const std::string& buf) {
123 uint32 x = ~0U;
124 for (int i = 0; i < buf.size(); ++i) {
125 unsigned char c = buf[i];
126 x = kCRC32Table[(x ^ c) & 0xff] ^ (x >> 8);
127 }
128 return ~x;
129 }
130
WriteShort(io::CodedOutputStream * out,uint16 val)131 static void WriteShort(io::CodedOutputStream* out, uint16 val) {
132 uint8 p[2];
133 p[0] = static_cast<uint8>(val);
134 p[1] = static_cast<uint8>(val >> 8);
135 out->WriteRaw(p, 2);
136 }
137
ZipWriter(io::ZeroCopyOutputStream * raw_output)138 ZipWriter::ZipWriter(io::ZeroCopyOutputStream* raw_output)
139 : raw_output_(raw_output) {}
~ZipWriter()140 ZipWriter::~ZipWriter() {}
141
Write(const std::string & filename,const std::string & contents)142 bool ZipWriter::Write(const std::string& filename,
143 const std::string& contents) {
144 FileInfo info;
145
146 info.name = filename;
147 uint16 filename_size = filename.size();
148 info.offset = raw_output_->ByteCount();
149 info.size = contents.size();
150 info.crc32 = ComputeCRC32(contents);
151
152 files_.push_back(info);
153
154 // write file header
155 io::CodedOutputStream output(raw_output_);
156 output.WriteLittleEndian32(0x04034b50); // magic
157 WriteShort(&output, 10); // version needed to extract
158 WriteShort(&output, 0); // flags
159 WriteShort(&output, 0); // compression method: stored
160 WriteShort(&output, 0); // last modified time
161 WriteShort(&output, kDosEpoch); // last modified date
162 output.WriteLittleEndian32(info.crc32); // crc-32
163 output.WriteLittleEndian32(info.size); // compressed size
164 output.WriteLittleEndian32(info.size); // uncompressed size
165 WriteShort(&output, filename_size); // file name length
166 WriteShort(&output, 0); // extra field length
167 output.WriteString(filename); // file name
168 output.WriteString(contents); // file data
169
170 return !output.HadError();
171 }
172
WriteDirectory()173 bool ZipWriter::WriteDirectory() {
174 uint16 num_entries = files_.size();
175 uint32 dir_ofs = raw_output_->ByteCount();
176
177 // write central directory
178 io::CodedOutputStream output(raw_output_);
179 for (int i = 0; i < num_entries; ++i) {
180 const std::string& filename = files_[i].name;
181 uint16 filename_size = filename.size();
182 uint32 crc32 = files_[i].crc32;
183 uint32 size = files_[i].size;
184 uint32 offset = files_[i].offset;
185
186 output.WriteLittleEndian32(0x02014b50); // magic
187 WriteShort(&output, 10); // version made by
188 WriteShort(&output, 10); // version needed to extract
189 WriteShort(&output, 0); // flags
190 WriteShort(&output, 0); // compression method: stored
191 WriteShort(&output, 0); // last modified time
192 WriteShort(&output, kDosEpoch); // last modified date
193 output.WriteLittleEndian32(crc32); // crc-32
194 output.WriteLittleEndian32(size); // compressed size
195 output.WriteLittleEndian32(size); // uncompressed size
196 WriteShort(&output, filename_size); // file name length
197 WriteShort(&output, 0); // extra field length
198 WriteShort(&output, 0); // file comment length
199 WriteShort(&output, 0); // starting disk number
200 WriteShort(&output, 0); // internal file attributes
201 output.WriteLittleEndian32(0); // external file attributes
202 output.WriteLittleEndian32(offset); // local header offset
203 output.WriteString(filename); // file name
204 }
205 uint32 dir_len = output.ByteCount();
206
207 // write end of central directory marker
208 output.WriteLittleEndian32(0x06054b50); // magic
209 WriteShort(&output, 0); // disk number
210 WriteShort(&output, 0); // disk with start of central directory
211 WriteShort(&output, num_entries); // central directory entries (this disk)
212 WriteShort(&output, num_entries); // central directory entries (total)
213 output.WriteLittleEndian32(dir_len); // central directory byte size
214 output.WriteLittleEndian32(dir_ofs); // central directory offset
215 WriteShort(&output, 0); // comment length
216
217 return output.HadError();
218 }
219
220 } // namespace compiler
221 } // namespace protobuf
222 } // namespace google
223