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