Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / 3rd-party / zisofs_tools / uncompress.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: uncompress.c,v 1.3 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 <stdio.h>
29 #include <stdlib.h>
30 #include <zlib.h>
31
32 #include "iso9660.h"
33
34 int block_uncompress_file(FILE *input, FILE *output, off_t size)
35 {
36   struct compressed_file_header hdr;
37   Bytef *inbuf, *outbuf;
38   int block_shift;
39   char *pointer_block, *pptr;
40   unsigned long nblocks;
41   unsigned long fullsize, block_size, block_size2;
42   size_t ptrblock_bytes;
43   unsigned long cstart, cend, csize;
44   uLong bytes;
45   int zerr;
46   int err = EX_SOFTWARE;
47
48   if ( (bytes = fread(&hdr, 1, sizeof hdr, input)) != sizeof hdr ) {
49     if ( bytes == (size_t)size ) {
50       /* Very short file; not compressed */
51       return ( fwrite(&hdr, 1, bytes, output) != bytes ) ? EX_CANTCREAT : 0;
52     } else {
53       return EX_IOERR;          /* Read error */
54     }
55   }
56
57   if ( memcmp(&hdr.magic, zisofs_magic, sizeof zisofs_magic) ) {
58     inbuf = xmalloc(CBLOCK_SIZE);
59     /* Not compressed */
60     memcpy(inbuf, &hdr, sizeof hdr);
61     bytes = sizeof hdr;
62     do {
63       if ( fwrite(inbuf, 1, bytes, output) != bytes )
64         return EX_CANTCREAT;
65     } while ( (bytes = fread(inbuf, 1, CBLOCK_SIZE, input)) > 0 );
66     free(inbuf);
67     return ferror(input) ? EX_IOERR : 0;
68   }
69
70   /* Now we know the file must be compressed.  Get the pointer table. */
71   if ( fseek(input, hdr.header_size << 2, SEEK_SET) == -1 )
72     return EX_IOERR;
73
74   fullsize    = get_731(hdr.uncompressed_len);
75   block_shift = hdr.block_size;
76   block_size  = 1UL << block_shift;
77   block_size2 = block_size << 1;
78   inbuf  = xmalloc(block_size2);
79   outbuf = xmalloc(block_size);
80
81   nblocks = (fullsize + block_size - 1) >> block_shift;
82
83   ptrblock_bytes = (nblocks+1) * 4;
84   pointer_block = xmalloc(ptrblock_bytes);
85
86   if ( (bytes = fread(pointer_block, 1, ptrblock_bytes, input)) != ptrblock_bytes ) {
87     err = EX_IOERR;
88     goto free_ptr_bail;
89   }
90   
91   pptr = pointer_block;
92   while ( fullsize ) {
93     cstart = get_731(pptr);
94     pptr += 4;
95     cend   = get_731(pptr);
96
97     csize = cend-cstart;
98
99     if ( csize == 0 ) {
100       memset(outbuf, 0, block_size);
101       bytes = block_size;
102     } else {
103       if ( csize > block_size2 ) {
104         err = EX_DATAERR;
105         goto free_ptr_bail;
106       }
107       
108       if ( fseek(input, cstart, SEEK_SET) == -1 ||
109            (bytes = fread(inbuf, 1, csize, input)) != csize ) {
110         err = EX_IOERR;
111         goto free_ptr_bail;
112       }
113       
114       bytes = block_size;               /* Max output buffer size */
115       if ( (zerr = uncompress(outbuf, &bytes, inbuf, csize)) != Z_OK ) {
116         err = (zerr = Z_MEM_ERROR) ? EX_OSERR : EX_DATAERR;
117         goto free_ptr_bail;
118       }
119     }
120       
121     if ( ((fullsize > block_size) && (bytes != block_size))
122          || ((fullsize <= block_size) && (bytes < fullsize)) ) {
123       err = EX_DATAERR;
124       goto free_ptr_bail;
125     }
126     
127     if ( bytes > fullsize )
128       bytes = fullsize;
129     
130     if ( fwrite(outbuf, 1, bytes, output) != bytes ) {
131       err = EX_CANTCREAT;
132       goto free_ptr_bail;
133     }
134
135     fullsize -= bytes;
136   }
137
138   err = 0;
139
140  free_ptr_bail:
141   free(pointer_block);
142   free(inbuf);
143   free(outbuf);
144   return err;
145 }
146
147