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