2 * This file has been modified for the cdrkit suite.
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).
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.
13 /* $Id: compress.c,v 1.4 2006/07/04 04:57:42 hpa Exp $ */
14 /* ----------------------------------------------------------------------- *
16 * Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
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.
24 * ----------------------------------------------------------------------- */
26 #include "mkzftree.h" /* Must be included first! */
37 int block_compress_file(FILE *input, FILE *output, off_t size)
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;
46 int force_compress = opt.force;
48 int err = EX_SOFTWARE;
50 if ( (sizeof hdr) & 3 ) {
51 fputs("INTERNAL ERROR: header is not a multiple of 4\n", stderr);
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);
61 if ( fwrite(&hdr, sizeof hdr, 1, output) != 1 )
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);
69 if ( fseek(output, pointer_bytes, SEEK_CUR) == -1 ) {
74 curptr = pointer_block;
75 position = sizeof hdr + pointer_bytes;
78 while ( (bytes = fread(inbuf, 1, CBLOCK_SIZE, input)) > 0 ) {
79 if ( bytes < CBLOCK_SIZE && block < nblocks-1 ) {
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) )
90 set_731(curptr, position); curptr += 4;
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. */
95 for ( i = 0 ; i < (int)CBLOCK_SIZE ; i++ ) {
96 if ( inbuf[i] ) break;
99 if ( i == CBLOCK_SIZE ) {
100 /* All-zero block. No output */
102 cbytes = 2*CBLOCK_SIZE;
103 if ( (zerr = compress2(outbuf, &cbytes, inbuf, bytes, opt.level))
105 err = (zerr == Z_MEM_ERROR) ? EX_OSERR : EX_SOFTWARE;
106 goto free_ptr_bail; /* Compression failure */
108 if ( fwrite(outbuf, 1, cbytes, output) != cbytes ) {
117 /* Set pointer to the end of the final block */
118 set_731(curptr, position);
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 ) {
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 */
136 while ( (bytes = fread(inbuf, 1, CBLOCK_SIZE, input)) > 0 ) {
137 if ( fwrite(inbuf, 1, bytes, output) != bytes )
142 /* Truncate the file to the correct size */
144 ftruncate(fileno(output), position);
147 /* If we get here, we're done! */
150 /* Common bailout code */