Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / 3rd-party / zisofs_tools / compress.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* $Id: compress.c,v 1.4 2006/07/04 04:57:42 hpa Exp $ */
14 /* ----------------------------------------------------------------------- *
15  *   
16  *   Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
17  *
18  *   This program is free software; you can redistribute it and/or modify
19  *   it under the terms of the GNU General Public License as published by
20  *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
21  *   USA; either version 2 of the License, or (at your option) any later
22  *   version; incorporated herein by reference.
23  *
24  * ----------------------------------------------------------------------- */
25
26 #include "mkzftree.h"           /* Must be included first! */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <utime.h>
31 #include <unistd.h>
32 #include <zlib.h>
33
34 #include "iso9660.h"
35
36
37 int block_compress_file(FILE *input, FILE *output, off_t size)
38 {
39   struct compressed_file_header hdr;
40   Bytef inbuf[CBLOCK_SIZE], outbuf[2*CBLOCK_SIZE];
41   size_t bytes, pointer_bytes, nblocks, block;
42   uLong cbytes;                 /* uLong is a zlib datatype */
43   char *pointer_block, *curptr;
44   off_t position;
45   int i;
46   int force_compress = opt.force;
47   int zerr;
48   int err = EX_SOFTWARE;
49   
50   if ( (sizeof hdr) & 3 ) {
51     fputs("INTERNAL ERROR: header is not a multiple of 4\n", stderr);
52     abort();
53   }
54
55   memset(&hdr, 0, sizeof hdr);
56   memcpy(&hdr.magic, zisofs_magic, sizeof zisofs_magic);
57   hdr.header_size = (sizeof hdr) >> 2;
58   hdr.block_size = CBLOCK_SIZE_LG2;
59   set_731(&hdr.uncompressed_len, size);
60
61   if ( fwrite(&hdr, sizeof hdr, 1, output) != 1 )
62     return EX_CANTCREAT;
63
64   nblocks = (size+CBLOCK_SIZE-1) >> CBLOCK_SIZE_LG2;
65   pointer_bytes = 4*(nblocks+1);
66   pointer_block = xmalloc(pointer_bytes);
67   memset(pointer_block, 0, pointer_bytes);
68
69   if ( fseek(output, pointer_bytes, SEEK_CUR) == -1 ) {
70     err = EX_CANTCREAT;
71     goto free_ptr_bail;
72   }
73
74   curptr = pointer_block;
75   position = sizeof hdr + pointer_bytes;
76   
77   block = 0;
78   while ( (bytes = fread(inbuf, 1, CBLOCK_SIZE, input)) > 0 ) {
79     if ( bytes < CBLOCK_SIZE && block < nblocks-1 ) {
80       err = EX_IOERR;
81       goto free_ptr_bail;
82     }
83
84     /* HACK: If the file has our magic number, always compress */
85     if ( block == 0 && bytes >= sizeof zisofs_magic ) {
86       if ( !memcmp(inbuf, zisofs_magic, sizeof zisofs_magic) )
87         force_compress = 1;
88     }
89
90     set_731(curptr, position); curptr += 4;
91     
92     /* We have two special cases: a zero-length block is defined as all zero,
93        and a block the length of which is equal to the block size is unencoded. */
94
95     for ( i = 0 ; i < (int)CBLOCK_SIZE ; i++ ) {
96       if ( inbuf[i] ) break;
97     }
98
99     if ( i == CBLOCK_SIZE ) {
100       /* All-zero block.  No output */
101     } else {
102       cbytes = 2*CBLOCK_SIZE;
103       if ( (zerr = compress2(outbuf, &cbytes, inbuf, bytes, opt.level))
104            != Z_OK ) {
105         err = (zerr == Z_MEM_ERROR) ? EX_OSERR : EX_SOFTWARE;
106         goto free_ptr_bail;     /* Compression failure */
107       }
108       if ( fwrite(outbuf, 1, cbytes, output) != cbytes ) {
109         err = EX_CANTCREAT;
110         goto free_ptr_bail;
111       }
112       position += cbytes;
113     }
114     block++;
115   }
116
117   /* Set pointer to the end of the final block */
118   set_731(curptr, position);
119
120   /* Now write the pointer table */
121   if ( fseek(output, sizeof hdr, SEEK_SET) == -1 ||
122        fwrite(pointer_block, 1, pointer_bytes, output) != pointer_bytes ) {
123     err = EX_CANTCREAT;
124     goto free_ptr_bail;
125   }
126
127   free(pointer_block);
128
129   /* Now make sure that this was actually the right thing to do */
130   if ( !force_compress && position >= size ) {
131     /* Incompressible file, just copy it */
132     rewind(input);
133     rewind(output);
134
135     position = 0;
136     while ( (bytes = fread(inbuf, 1, CBLOCK_SIZE, input)) > 0 ) {
137       if ( fwrite(inbuf, 1, bytes, output) != bytes )
138         return EX_CANTCREAT;
139       position += bytes;
140     }
141
142     /* Truncate the file to the correct size */
143     fflush(output);
144     ftruncate(fileno(output), position);
145   }
146
147   /* If we get here, we're done! */
148   return 0;
149
150   /* Common bailout code */
151  free_ptr_bail:
152   free(pointer_block);
153   return err;
154 }
155