1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26
27 /*
28 #include <tools/datetime.hxx>
29 */
30 #include <osl/diagnose.h>
31 #include <rtl/crc.h>
32
33 #include "zip.hxx"
34 #include "zipfile.hxx"
35
36 using namespace rtl;
37
38 /** this struct describes one entry in a zip file */
39 struct ZipEntry
40 {
41 OString name; /* the name we used */
42 sal_Int32 offset; /* where the header starts */
43 sal_Int32 endOffset; /* where the file data ends */
44 sal_Int32 crc;
45 sal_Int32 modTime; /* dos mod time & date */
46 sal_Int32 fileLen; /* file size, in bytes */
47 };
48
49 /** put one byte inside this stream */
putC(unsigned char c,osl::File & rFile)50 static osl::File::RC putC( unsigned char c, osl::File& rFile )
51 {
52 sal_uInt64 nBytesWritten;
53 osl::File::RC nRC = rFile.write( &c, 1, nBytesWritten );
54
55 OSL_ASSERT( nBytesWritten == 1 );
56 return nRC;
57 }
58
59 /** write a short to the ZipFile */
writeShort(sal_Int16 s)60 void ZipFile::writeShort( sal_Int16 s)
61 {
62 if( !isError() )
63 {
64 mnRC = putC( static_cast< unsigned char >( s & 0xff ), mrFile );
65 if( !isError() )
66 mnRC = putC( static_cast< unsigned char >( (s >> 8) & 0xff ), mrFile );
67 }
68 }
69
70 /** write a long to the ZipFile */
71
writeLong(sal_Int32 l)72 void ZipFile::writeLong( sal_Int32 l )
73 {
74 if( !isError() )
75 {
76 mnRC = putC( static_cast< unsigned char >( l & 0xff ), mrFile);
77 if( !isError() )
78 {
79 mnRC = putC( static_cast< unsigned char >( (l >> 8) & 0xff ), mrFile);
80 if( !isError() )
81 {
82 mnRC = putC( static_cast< unsigned char >( (l >> 16) & 0xff ), mrFile);
83 if( !isError() )
84 {
85 mnRC = putC( static_cast< unsigned char >( (l >> 24) & 0xff ), mrFile);
86 }
87 }
88 }
89 }
90 }
91
92 /** copy the zipentries file to the zipfile and updates the crc of that zipentry */
copyAndCRC(ZipEntry * e,osl::File & rFile)93 void ZipFile::copyAndCRC(ZipEntry *e, osl::File& rFile)
94 {
95 char buf[2048];
96 sal_uInt64 n, nWritten;
97
98 e->crc = rtl_crc32( 0, 0L, 0 );
99
100 while( !isError() )
101 {
102 mnRC = rFile.read( buf, sizeof(buf), n );
103 if(n == 0)
104 break;
105
106 if( !isError() )
107 {
108 sal_uInt32 nTemp = static_cast<sal_uInt32>(n);
109 e->crc = rtl_crc32( e->crc, (const void *) buf, nTemp );
110 mnRC = mrFile.write( buf, n, nWritten );
111 OSL_ASSERT( n == nWritten );
112 }
113 }
114
115 if( !isError() )
116 {
117 sal_uInt64 nPosition = 0;
118 mnRC = mrFile.getPos( nPosition );
119 if( !isError() )
120 {
121 e->endOffset = static_cast< sal_Int32 >( nPosition );
122 }
123 }
124 }
125
126 /** write a yet empty local header for a zipentry to the zipfile */
writeDummyLocalHeader(ZipEntry * e)127 void ZipFile::writeDummyLocalHeader(ZipEntry *e)
128 {
129 sal_Int32 len = zf_lfhSIZE + e->name.getLength();
130 sal_Int32 i;
131
132 sal_uInt64 nPosition = 0;
133 mnRC = mrFile.getPos( nPosition );
134 if( !isError() )
135 {
136 e->offset = static_cast< sal_Int32 >( nPosition );
137
138 for (i = 0; (i < len) && !isError(); ++i)
139 mnRC = putC(0, mrFile);
140 }
141 }
142
143 /** write the local header for a zipentry to the zipfile */
writeLocalHeader(ZipEntry * e)144 void ZipFile::writeLocalHeader(ZipEntry *e)
145 {
146 TimeValue aTime;
147 osl_getSystemTime( &aTime );
148
149 oslDateTime aDate;
150 osl_getDateTimeFromTimeValue( &aTime, &aDate );
151
152 e->modTime = ((aDate.Year - 1980) << 25) | (aDate.Month << 21) | (aDate.Day << 16) |
153 (aDate.Hours << 11) | (aDate.Minutes << 5) | (aDate.Seconds >> 1);
154
155 e->fileLen = e->endOffset - e->offset - zf_lfhSIZE - e->name.getLength();
156
157 if(!isError())
158 {
159 mnRC = mrFile.setPos( Pos_Absolut, e->offset );
160
161 writeLong(zf_LFHSIGValue); // magic number
162 writeShort(zf_Vers(1, 0)); // extract version
163 writeShort(0); // flags
164 writeShort(zf_compNone); // compression method
165 writeLong(e->modTime); // file mod date & time
166 writeLong(e->crc); // file crc
167 writeLong(e->fileLen); // compressed size
168 writeLong(e->fileLen); // uncompressed size
169 writeShort((sal_Int16) e->name.getLength()); // name length
170 writeShort(0); // extra length field
171
172 if( !isError() )
173 {
174 sal_uInt64 nWritten;
175 mnRC = mrFile.write( e->name.getStr(), e->name.getLength(), nWritten ); // file name
176 OSL_ASSERT( nWritten == (sal_uInt64)e->name.getLength() );
177 if( !isError() )
178 {
179 mnRC = mrFile.setPos( Pos_Absolut, e->endOffset );
180 }
181 }
182 }
183 }
184
185 /* write a zipentry in the central dir to the zipfile */
writeCentralDir(ZipEntry * e)186 void ZipFile::writeCentralDir(ZipEntry *e)
187 {
188 writeLong(zf_CDHSIGValue); // magic number
189 writeShort(zf_Vers(1, 0)); // version made by
190 writeShort(zf_Vers(1, 0)); // vers to extract
191 writeShort(0); // flags
192 writeShort(zf_compNone); // compression method
193 writeLong(e->modTime); // file mod time & date
194 writeLong(e->crc);
195 writeLong(e->fileLen); // compressed file size
196 writeLong(e->fileLen); // uncompressed file size
197 writeShort((sal_Int16) e->name.getLength()); // name length
198 writeShort(0); // extra field length
199 writeShort(0); // file comment length
200 writeShort(0); // disk number start
201 writeShort(0); // internal file attributes
202 writeLong(0); // external file attributes
203 writeLong(e->offset); // offset w.r.t disk
204 if( !isError() )
205 {
206 sal_uInt64 nWritten;
207 mrFile.write( e->name.getStr(), e->name.getLength(), nWritten ); // file name
208 OSL_ASSERT( nWritten == (sal_uInt64)e->name.getLength() );
209 }
210 }
211
212 /* write the end of the central dir to the zipfile */
writeEndCentralDir(sal_Int32 nCdOffset,sal_Int32 nCdSize)213 void ZipFile::writeEndCentralDir(sal_Int32 nCdOffset, sal_Int32 nCdSize)
214 {
215 writeLong(zf_ECDSIGValue); // magic number
216 writeShort(0); // disk num
217 writeShort(0); // disk with central dir
218 writeShort( static_cast< sal_Int16 >( maEntries.size() ) ); // number of file entries
219 writeShort( static_cast< sal_Int16 >( maEntries.size() ) ); // number of file entries
220 writeLong(nCdSize); // central dir size
221 writeLong(nCdOffset);
222 writeShort(0); // comment len
223 }
224
225
226 /****************************************************************
227 * The exported functions
228 ****************************************************************/
229
230 /* Create a zip file for writing, return a handle for it.
231 * RETURNS: A new zip-file output object, or NULL if it failed, in
232 * which case *errMsgBuffer will contain an error message string. */
ZipFile(osl::File & rFile)233 ZipFile::ZipFile(osl::File& rFile )
234 : mrFile( rFile ), mbOpen( true ), mnRC( osl::File::E_None )
235 {
236 }
237
~ZipFile()238 ZipFile::~ZipFile()
239 {
240 if( mbOpen )
241 close();
242 }
243
244 /* Add a file to this zip with the given name.
245 * RETURNS: true if successful, else false. If false, the caller should
246 * call zip_Close() and delete the bum zip file.
247 */
addFile(osl::File & rFile,const OString & rName)248 bool ZipFile::addFile( osl::File& rFile, const OString& rName )
249 {
250 OSL_ASSERT( mbOpen );
251
252 if( !mbOpen )
253 return false;
254
255 OSL_ASSERT( 0 != rName.getLength() );
256
257 if(0 == rName.getLength())
258 return false;
259
260 mnRC = rFile.open( osl_File_OpenFlag_Read );
261
262 if( !isError() )
263 {
264 ZipEntry *e = new ZipEntry;
265 e->name = rName;
266 maEntries.push_back(e);
267
268 writeDummyLocalHeader(e);
269 if( !isError() )
270 {
271 copyAndCRC(e, rFile);
272 if(!isError())
273 {
274 writeLocalHeader(e);
275 }
276 }
277
278 rFile.close();
279 }
280
281 return !isError();
282 }
283
284 /* Finish up the zip file, close it, and deallocate the zip file object.
285 * RETURNS: true if successful, else false.
286 */
close()287 bool ZipFile::close()
288 {
289 OSL_ASSERT( mbOpen );
290
291 if( !mbOpen )
292 return false;
293
294 if( !isError() )
295 {
296 sal_uInt64 nCdOffset;
297 mrFile.getPos( nCdOffset );
298
299 std::vector< ZipEntry* >::iterator aIter( maEntries.begin() );
300 while((aIter != maEntries.end()) && !isError())
301 {
302 writeCentralDir( (*aIter++) );
303 }
304
305 if( !isError() )
306 {
307 sal_uInt64 nCdSize;
308 mrFile.getPos( nCdSize );
309
310 nCdSize -= nCdOffset;
311
312 if( !isError() )
313 {
314 writeEndCentralDir(static_cast<sal_Int32>(nCdOffset), static_cast<sal_Int32>(nCdSize));
315 }
316 }
317 }
318
319 std::vector< ZipEntry* >::iterator aIter( maEntries.begin() );
320 while( aIter != maEntries.end() )
321 {
322 delete (*aIter++);
323 }
324
325 mbOpen = false;
326
327 return !isError();
328 }
329