1 /************************************************************************/
2 /*									*/
3 /*  Simple io streams, Data on the stream travels in In/Deflate format	*/
4 /*  using zlib. The implementation is a VERY SIMPLE ONE: It assumes	*/
5 /*  that the compressed files fit in memory.				*/
6 /*									*/
7 /************************************************************************/
8 
9 #   include	"appUtilConfig.h"
10 
11 #   include	<stdlib.h>
12 #   include	<string.h>
13 #   include	<zlib.h>
14 #   include	<time.h>
15 
16 #   include	"sioZip.h"
17 #   include	"sioEndian.h"
18 #   include	"utilMemoryBuffer.h"
19 #   include	"utilDosTime.h"
20 
21 #   include	<appDebugon.h>
22 
23 #   define	ZIPmethodSTORED			0
24 #   define	ZIPmethodDEFLATED		8
25 
26 #   define	ZIPflagsSTORED			0
27 #   define	ZIPflagsDEFLATED		0
28 
29 #   define	ZIPversionSTORED		0xa
30 #   define	ZIPversionDEFLATED		0xa
31 
32 #   define	ZIPsignatureDIRECTORY_ENTRY	0x02014b50
33 #   define	ZIPsignatureDIRECTORY_END	0x06054b50
34 #   define	ZIPsignatureMEMBER		0x04034b50
35 
36 #   define	ZIPattributesINTERNAL		0 /* binary */
37 #   define	ZIPattributesEXTERNAL		0 /* from stdin */
38 
39 /************************************************************************/
40 /*									*/
41 /*  Actual Output stream object.					*/
42 /*									*/
43 /************************************************************************/
44 
45 typedef struct ZipOutputStream
46     {
47     z_stream			zosZstream;
48     unsigned char		zosHasZstream;
49     unsigned char		zosOutputBuffer[SIOsizBUF];
50     ZipOutput *			zosZipOutput;
51     int				zosIndex;
52     unsigned long		zosHeaderOffset;
53 
54     int				zosVersion;
55     int				zosFlags;
56     int				zosMethod;
57     int				zosDosTime;
58     int				zosDosDate;
59 
60     MemoryBuffer		zosCollectedBuffer;
61 
62     unsigned long		zosAdlerCrc;
63     unsigned long		zosUncompressedSize;
64     unsigned long		zosCollectedSize;
65 
66     char *			zosFileName;
67     } ZipOutputStream;
68 
sioZipInitStream(ZipOutputStream * zos)69 static void sioZipInitStream(	ZipOutputStream *	zos )
70     {
71     zos->zosHasZstream= 0;
72     zos->zosZipOutput= (ZipOutput *)0;
73     zos->zosIndex= -1;
74     zos->zosHeaderOffset= 0;
75 
76     zos->zosVersion= ZIPversionSTORED;
77     zos->zosFlags= ZIPflagsSTORED;
78     zos->zosMethod= ZIPmethodSTORED;
79     zos->zosDosTime= 0;
80     zos->zosDosDate= 0;
81 
82     utilInitMemoryBuffer( &(zos->zosCollectedBuffer) );
83 
84     zos->zosAdlerCrc= 0;
85     zos->zosUncompressedSize= 0;
86     zos->zosCollectedSize= 0;
87 
88     zos->zosFileName= (char *)0;
89     }
90 
sioZipCleanStream(ZipOutputStream * zos)91 static void sioZipCleanStream(	ZipOutputStream *	zos )
92     {
93     utilCleanMemoryBuffer( &(zos->zosCollectedBuffer) );
94 
95     if  ( zos->zosHasZstream )
96 	{
97 	int ret= deflateEnd( &(zos->zosZstream) );
98 	if  ( ret != Z_OK )
99 	    { LLDEB(zos->zosHasZstream,ret);	}
100 	}
101 
102     if  ( zos->zosFileName )
103 	{ free( zos->zosFileName );	}
104     }
105 
106 /************************************************************************/
107 
sioZipInitOutput(ZipOutput * zo)108 void sioZipInitOutput(	ZipOutput *			zo )
109     {
110     zo->zoSosZip= (SimpleOutputStream *)0;
111     zo->zoBytesWritten= 0;
112 
113     utilInitPagedList( &(zo->zoFileList) );
114     utilStartPagedList( &(zo->zoFileList),
115 			    sizeof(ZipOutputStream),
116 			    (InitPagedListItem)sioZipInitStream,
117 			    (InitPagedListItem)sioZipCleanStream );
118 
119     zo->zoEntryCount= 0;
120     zo->zoDirectoryOffset= 0;
121     zo->zoDirectorySize= 0;
122 
123     return;
124     }
125 
sioZipCleanOutput(ZipOutput * zo)126 void sioZipCleanOutput(	ZipOutput *			zo )
127     {
128     /*  zo->zoSosZip Is owned by the consumer */
129 
130     utilCleanPagedList( &(zo->zoFileList) );
131 
132     return;
133     }
134 
135 /************************************************************************/
136 
sioZipWriteLocalFileHeader(const ZipOutputStream * zos)137 static int sioZipWriteLocalFileHeader(	const ZipOutputStream *	zos )
138     {
139     SimpleOutputStream *	sosZip= zos->zosZipOutput->zoSosZip;
140 
141     const int			extraLength= 0;
142 
143     int				done= 0;
144     int				fileNameLength= 0;
145 
146     if  ( zos->zosFileName )
147 	{ fileNameLength= strlen( zos->zosFileName );	}
148 
149     sioEndianPutLeUint32( ZIPsignatureMEMBER, sosZip ); done += 4;
150     sioEndianPutLeUint16( zos->zosVersion, sosZip ); done += 2;
151     sioEndianPutLeUint16( zos->zosFlags, sosZip ); done += 2;
152     sioEndianPutLeUint16( zos->zosMethod, sosZip ); done += 2;
153     sioEndianPutLeUint16( zos->zosDosTime, sosZip ); done += 2;
154     sioEndianPutLeUint16( zos->zosDosDate, sosZip ); done += 2;
155     sioEndianPutLeUint32( zos->zosAdlerCrc, sosZip ); done += 4;
156     sioEndianPutLeUint32( zos->zosCollectedSize, sosZip ); done += 4;
157     sioEndianPutLeUint32( zos->zosUncompressedSize, sosZip ); done += 4;
158     sioEndianPutLeUint16( fileNameLength, sosZip ); done += 2;
159     sioEndianPutLeUint16( extraLength, sosZip ); done += 2;
160 
161     if  ( fileNameLength > 0 )
162 	{
163 	sioOutPutString( zos->zosFileName, sosZip );
164 	done += fileNameLength;
165 	}
166 
167     /* no extra field */
168 
169     return done;
170     }
171 
sioZipWriteDirectoryEntry(const ZipOutputStream * zos)172 static int sioZipWriteDirectoryEntry(	const ZipOutputStream *	zos )
173     {
174     SimpleOutputStream *	sosZip= zos->zosZipOutput->zoSosZip;
175 
176     const int			extraLength= 0;
177     const int			commentLength= 0;
178     const int			diskNumberStart= 0;
179 
180     int				done= 0;
181     int				fileNameLength= 0;
182 
183     if  ( zos->zosFileName )
184 	{ fileNameLength= strlen( zos->zosFileName );	}
185 
186     sioEndianPutLeUint32( ZIPsignatureDIRECTORY_ENTRY, sosZip ); done += 4;
187     sioEndianPutLeUint16( zos->zosVersion, sosZip ); done += 2;
188     sioEndianPutLeUint16( zos->zosVersion, sosZip ); done += 2;
189     sioEndianPutLeUint16( zos->zosFlags, sosZip ); done += 2;
190     sioEndianPutLeUint16( zos->zosMethod, sosZip ); done += 2;
191     sioEndianPutLeUint16( zos->zosDosTime, sosZip ); done += 2;
192     sioEndianPutLeUint16( zos->zosDosDate, sosZip ); done += 2;
193     sioEndianPutLeUint32( zos->zosAdlerCrc, sosZip ); done += 4;
194     sioEndianPutLeUint32( zos->zosCollectedSize, sosZip ); done += 4;
195     sioEndianPutLeUint32( zos->zosUncompressedSize, sosZip ); done += 4;
196     sioEndianPutLeUint16( fileNameLength, sosZip ); done += 2;
197     sioEndianPutLeUint16( extraLength, sosZip ); done += 2;
198 
199     sioEndianPutLeUint16( commentLength, sosZip ); done += 2;
200     sioEndianPutLeUint16( diskNumberStart, sosZip ); done += 2;
201     sioEndianPutLeUint16( ZIPattributesINTERNAL, sosZip ); done += 2;
202     sioEndianPutLeUint32( ZIPattributesEXTERNAL, sosZip ); done += 4;
203 
204     sioEndianPutLeUint32( zos->zosHeaderOffset, sosZip ); done += 4;
205 
206     if  ( fileNameLength > 0 )
207 	{
208 	sioOutPutString( zos->zosFileName, sosZip );
209 	done += fileNameLength;
210 	}
211 
212     /* no extra field */
213     /* no comment */
214 
215     return done;
216     }
217 
sioZipWriteDirectoryEnd(const ZipOutput * zo)218 static int sioZipWriteDirectoryEnd(	const ZipOutput *	zo )
219     {
220     SimpleOutputStream *	sosZip= zo->zoSosZip;
221 
222     const int			diskNumber= 0;
223     const int			commentLength= 0;
224 
225     int				done= 0;
226 
227     sioEndianPutLeUint32( ZIPsignatureDIRECTORY_END, sosZip ); done += 4;
228     /*  number of this disk */
229     sioEndianPutLeUint16( diskNumber, sosZip ); done += 2;
230     /*  number of the disk where the central dir starts */
231     sioEndianPutLeUint16( diskNumber, sosZip ); done += 2;
232     /*  Entry count on this disk */
233     sioEndianPutLeUint16( diskNumber, sosZip ); done += 2;
234     /*  Total entry count */
235     sioEndianPutLeUint16( zo->zoEntryCount, sosZip ); done += 2;
236     sioEndianPutLeUint32( zo->zoDirectorySize, sosZip ); done += 4;
237     sioEndianPutLeUint32( zo->zoDirectoryOffset, sosZip ); done += 4;
238     sioEndianPutLeUint16( commentLength, sosZip ); done += 2;
239 
240     /* no comment */
241 
242     return done;
243     }
244 
245 /************************************************************************/
246 
247 typedef struct ZipStats
248     {
249     int			zsEntryCount;
250     unsigned long	zsDirectorySize;
251     } ZipStats;
252 
sioZipEmitDirectoryEntry(int n,void * voidzos,void * voidzs)253 static int sioZipEmitDirectoryEntry(	int		n,
254 					void *		voidzos,
255 					void *		voidzs )
256     {
257     ZipOutputStream *		zos= (ZipOutputStream *)voidzos;
258     ZipStats *			zs= (ZipStats *)voidzs;
259     ZipOutput *			zo= zos->zosZipOutput;
260 
261     int				step;
262 
263     step= sioZipWriteDirectoryEntry( zos );
264     if  ( step < 0 )
265 	{ LDEB(step); return -1;	}
266 
267     zs->zsEntryCount++;
268     zs->zsDirectorySize += step;
269 
270     zo->zoBytesWritten += step;
271     zo->zoDirectorySize += step;
272 
273     return 0;
274     }
275 
sioZipFlushOutput(ZipOutput * zo)276 int sioZipFlushOutput(		ZipOutput *		zo )
277     {
278     ZipStats	zs;
279     int		n;
280     int		step;
281 
282     zs.zsEntryCount= 0;
283     zs.zsDirectorySize= 0;
284 
285     zo->zoDirectoryOffset= zo->zoBytesWritten;
286 
287     n= utilPagedListForAll( &(zo->zoFileList),
288 				sioZipEmitDirectoryEntry, (void *)&zs );
289     if  ( n < 0 )
290 	{ LDEB(n); return -1;	}
291     if  ( n!= zs.zsEntryCount || n != zo->zoEntryCount )
292 	{ LLLDEB(n,zs.zsEntryCount,zo->zoEntryCount);	}
293 
294     step= sioZipWriteDirectoryEnd( zo );
295     if  ( step < 0 )
296 	{ LDEB(step); return -1;	}
297     zo->zoBytesWritten += step;
298 
299     return 0;
300     }
301 
302 /************************************************************************/
303 /*									*/
304 /*  The Zip compression routine:					*/
305 /*									*/
306 /************************************************************************/
307 
sioOutZipFlushBytesDeflated(ZipOutputStream * zos,int n)308 static int sioOutZipFlushBytesDeflated(	ZipOutputStream *	zos,
309 					int			n )
310     {
311     z_stream *			c_stream= &(zos->zosZstream);
312     const unsigned char *	b= zos->zosOutputBuffer;
313 
314     if  ( n > 0 && utilMemoryBufferAppendBytes( &(zos->zosCollectedBuffer), b, n ) )
315 	{ LDEB(n); return -1; }
316 
317     zos->zosCollectedSize += n;
318 
319     c_stream->next_out= zos->zosOutputBuffer;
320     c_stream->avail_out= SIOsizBUF;
321 
322     return n;
323     }
324 
sioOutZipWriteBytesDeflated(void * voidzos,const unsigned char * buffer,int count)325 static int sioOutZipWriteBytesDeflated(	void *			voidzos,
326 					const unsigned char *	buffer,
327 					int			count )
328     {
329     ZipOutputStream *		zos= (ZipOutputStream *)voidzos;
330     z_stream *			c_stream= &(zos->zosZstream);
331 
332     zos->zosUncompressedSize += count;
333     zos->zosAdlerCrc= crc32( zos->zosAdlerCrc, buffer, count );
334 
335     c_stream->next_in= (unsigned char *)buffer;
336     c_stream->avail_in= count;
337 
338     while( c_stream->avail_in > 0 )
339 	{
340 	int		ret;
341 
342 	if  ( c_stream->avail_out == 0 )
343 	    {
344 	    if  ( sioOutZipFlushBytesDeflated( zos, SIOsizBUF ) != SIOsizBUF )
345 		{ LDEB(SIOsizBUF); return -1;	}
346 	    }
347 
348 	ret= deflate( c_stream, Z_NO_FLUSH );
349 	if  ( ret != Z_OK )
350 	    { LDEB(ret); return -1;	}
351 	}
352 
353     return count;
354     }
355 
sioOutZipWriteBytesStored(void * voidzos,const unsigned char * buffer,int count)356 static int sioOutZipWriteBytesStored(	void *			voidzos,
357 					const unsigned char *	buffer,
358 					int			count )
359     {
360     ZipOutputStream *		zos= (ZipOutputStream *)voidzos;
361 
362     zos->zosUncompressedSize += count;
363     zos->zosAdlerCrc= crc32( zos->zosAdlerCrc, buffer, count );
364 
365     if  ( utilMemoryBufferAppendBytes( &(zos->zosCollectedBuffer), buffer, count ) )
366 	{ LDEB(count); return -1; }
367 
368     zos->zosCollectedSize += count;
369 
370     return count;
371     }
372 
373 /************************************************************************/
374 /*									*/
375 /*  Close a Zip output stream.						*/
376 /*									*/
377 /************************************************************************/
378 
sioOutZipFinishFile(ZipOutputStream * zos,int rval)379 static void sioOutZipFinishFile(	ZipOutputStream *	zos,
380 					int			rval )
381     {
382     ZipOutput *			zo= zos->zosZipOutput;
383 
384     if  ( zos->zosHasZstream )
385 	{
386 	int ret= deflateEnd( &(zos->zosZstream) );
387 	if  ( ret != Z_OK )
388 	    { LLDEB(zos->zosHasZstream,ret);	}
389 
390 	zos->zosHasZstream= 0;
391 	}
392 
393     utilCleanMemoryBuffer( &(zos->zosCollectedBuffer) );
394     utilInitMemoryBuffer( &(zos->zosCollectedBuffer) );
395 
396     if  ( rval )
397 	{
398 	if  ( zos->zosIndex >= 0 )
399 	    {
400 	    utilPagedListDeleteItemByNumber( &(zo->zoFileList), zos->zosIndex );
401 	    }
402 	}
403     else{
404 	zo->zoEntryCount++;
405 	}
406 
407     return;
408     }
409 
410 /************************************************************************/
411 /*									*/
412 /*  Emit a single local file 						*/
413 /*									*/
414 /************************************************************************/
415 
sioZipEmitFile(ZipOutputStream * zos)416 static int sioZipEmitFile(		ZipOutputStream *	zos )
417     {
418     ZipOutput *			zo= zos->zosZipOutput;
419     SimpleOutputStream *	sosZip= zo->zoSosZip;
420 
421     int				size;
422     const unsigned char *	bytes;
423 
424     int				step;
425 
426     zos->zosHeaderOffset= zo->zoBytesWritten;
427 
428     step= sioZipWriteLocalFileHeader( zos );
429     if  ( step < 0 )
430 	{ LDEB(step); return -1;	}
431     zo->zoBytesWritten += step;
432 
433     bytes= utilMemoryBufferGetBytes( &size, &(zos->zosCollectedBuffer) );
434     step= sioOutWriteBytes( sosZip, bytes, size );
435     if  ( step != size )
436 	{ LLDEB(step,size); return -1;	}
437     zo->zoBytesWritten += step;
438 
439     /*
440     Only if the file header flags had bit 0xa and the fileds were 0 there
441 
442     sioEndianPutLeInt32( zos->zosAdlerCrc, zos->zosSosZip ); done += 4;
443     sioEndianPutLeInt32( zos->zosCollectedSize, zos->zosSosZip ); done += 4;
444     sioEndianPutLeInt32( zos->zosUncompressedSize, zos->zosSosZip ); done += 4;
445     */
446 
447     return 0;
448     }
449 
sioOutZipCloseDeflated(void * voidzos)450 static int sioOutZipCloseDeflated(	void *		voidzos )
451     {
452     int				rval= 0;
453     int				ret;
454 
455     ZipOutputStream *		zos= (ZipOutputStream *)voidzos;
456     z_stream *			c_stream= &(zos->zosZstream);
457 
458     c_stream->next_in= (unsigned char *)0;
459     c_stream->avail_in= 0;
460 
461     for (;;)
462 	{
463 	if  ( c_stream->avail_out == 0 )
464 	    {
465 	    if  ( sioOutZipFlushBytesDeflated( zos, SIOsizBUF ) != SIOsizBUF )
466 		{ LDEB(SIOsizBUF); rval= -1; goto ready;	}
467 	    }
468 
469 	ret= deflate( c_stream, Z_FINISH );
470 	if  ( ret == Z_STREAM_END )
471 	    { break;	}
472 	if  ( ret != Z_OK )
473 	    { LDEB(ret); rval= -1; goto ready;	}
474 	}
475 
476     if  ( c_stream->avail_out < SIOsizBUF )
477 	{
478 	int	n= SIOsizBUF- c_stream->avail_out;
479 
480 	if  ( sioOutZipFlushBytesDeflated( zos, n ) != n )
481 	    { LDEB(n); return -1;	}
482 	}
483 
484     if  ( sioZipEmitFile( zos ) )
485 	{ LDEB(1); rval= -1; goto ready;	}
486 
487   ready:
488 
489     sioOutZipFinishFile( zos, rval );
490 
491     return rval;
492     }
493 
sioOutZipCloseStored(void * voidzos)494 static int sioOutZipCloseStored(	void *		voidzos )
495     {
496     int				rval= 0;
497 
498     ZipOutputStream *		zos= (ZipOutputStream *)voidzos;
499 
500     if  ( sioZipEmitFile( zos ) )
501 	{ LDEB(1); rval= -1; goto ready;	}
502 
503   ready:
504 
505     sioOutZipFinishFile( zos, rval );
506 
507     return rval;
508     }
509 
sioZipStartDeflated(ZipOutputStream * zos)510 static int sioZipStartDeflated(		ZipOutputStream *	zos )
511     {
512     int		ret;
513 
514     zos->zosZstream.zalloc = (alloc_func)0;
515     zos->zosZstream.zfree = (free_func)0;
516     zos->zosZstream.opaque = (voidpf)0;
517 
518     ret= deflateInit2( &(zos->zosZstream), Z_DEFAULT_COMPRESSION, Z_DEFLATED,
519 			    -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY );
520     if  ( ret != Z_OK )
521 	{ LDEB(ret); return -1;	}
522     zos->zosHasZstream= 1;
523 
524     zos->zosZstream.next_in= (unsigned char *)0;
525     zos->zosZstream.avail_in= 0;
526 
527     zos->zosZstream.next_out= zos->zosOutputBuffer;
528     zos->zosZstream.avail_out= SIOsizBUF;
529 
530     zos->zosVersion= ZIPversionDEFLATED;
531     zos->zosFlags= ZIPflagsDEFLATED;
532     zos->zosMethod= ZIPmethodDEFLATED;
533 
534     return 0;
535     }
536 
sioZipStartStored(ZipOutputStream * zos)537 static int sioZipStartStored(		ZipOutputStream *	zos )
538     {
539     zos->zosVersion= ZIPversionSTORED;
540     zos->zosFlags= ZIPflagsSTORED;
541     zos->zosMethod= ZIPmethodSTORED;
542 
543     return 0;
544     }
545 
sioOutZipOpen(ZipOutput * zo,const char * fileName,int deflated)546 SimpleOutputStream * sioOutZipOpen(	ZipOutput *		zo,
547 					const char *		fileName,
548 					int			deflated )
549     {
550     SimpleOutputStream *	sos= (SimpleOutputStream *)0;
551     ZipOutputStream *		zos= (ZipOutputStream *)0;
552 
553     {
554     int		n= -1;
555 
556     zos= (ZipOutputStream *)utilPagedListClaimNewItem( &n,
557 						&(zo->zoFileList) );
558     if  ( ! zos )
559 	{ XDEB(zos); goto ready;	}
560 
561     zos->zosIndex= n;
562     }
563 
564     zos->zosZipOutput= zo;
565     utilDosTimeDate( &(zos->zosDosTime), &(zos->zosDosDate),
566 						    time( (time_t *)0 ) );
567     if  ( fileName )
568 	{
569 	zos->zosFileName= strdup( fileName );
570 	if  ( ! zos->zosFileName )
571 	    { XDEB(zos->zosFileName); goto ready;	}
572 	}
573 
574     zos->zosAdlerCrc= crc32( 0L, Z_NULL, 0 );
575 
576     if  ( deflated )
577 	{
578 	if  ( sioZipStartDeflated( zos ) )
579 	    { LDEB(deflated); goto ready;	}
580 
581 	sos= sioOutOpen( (void *)zos,
582 			sioOutZipWriteBytesDeflated, sioOutZipCloseDeflated );
583 	if  ( ! sos )
584 	    { LXDEB(deflated,sos); goto ready;	}
585 	zos= (ZipOutputStream *)0; /* steal */
586 	}
587     else{
588 	if  ( sioZipStartStored( zos ) )
589 	    { LDEB(deflated); goto ready;	}
590 
591 	sos= sioOutOpen( (void *)zos,
592 			sioOutZipWriteBytesStored, sioOutZipCloseStored );
593 	if  ( ! sos )
594 	    { LXDEB(deflated,sos); goto ready;	}
595 	zos= (ZipOutputStream *)0; /* steal */
596 	}
597 
598   ready:
599 
600     if  ( zos )
601 	{ utilPagedListDeleteItemByNumber( &(zo->zoFileList), zos->zosIndex ); }
602 
603     return sos;
604     }
605 
606