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