xref: /AOO41X/main/filter/source/placeware/zip.cxx (revision 9e0fc027f109ec4ffcb6033aeec742a099701108)
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