summaryrefslogtreecommitdiff
path: root/3rd-party/zisofs_tools/compress.c
diff options
context:
space:
mode:
Diffstat (limited to '3rd-party/zisofs_tools/compress.c')
-rw-r--r--3rd-party/zisofs_tools/compress.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/3rd-party/zisofs_tools/compress.c b/3rd-party/zisofs_tools/compress.c
new file mode 100644
index 0000000..56f0af0
--- /dev/null
+++ b/3rd-party/zisofs_tools/compress.c
@@ -0,0 +1,155 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* $Id: compress.c,v 1.4 2006/07/04 04:57:42 hpa Exp $ */
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include "mkzftree.h" /* Must be included first! */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <utime.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#include "iso9660.h"
+
+
+int block_compress_file(FILE *input, FILE *output, off_t size)
+{
+ struct compressed_file_header hdr;
+ Bytef inbuf[CBLOCK_SIZE], outbuf[2*CBLOCK_SIZE];
+ size_t bytes, pointer_bytes, nblocks, block;
+ uLong cbytes; /* uLong is a zlib datatype */
+ char *pointer_block, *curptr;
+ off_t position;
+ int i;
+ int force_compress = opt.force;
+ int zerr;
+ int err = EX_SOFTWARE;
+
+ if ( (sizeof hdr) & 3 ) {
+ fputs("INTERNAL ERROR: header is not a multiple of 4\n", stderr);
+ abort();
+ }
+
+ memset(&hdr, 0, sizeof hdr);
+ memcpy(&hdr.magic, zisofs_magic, sizeof zisofs_magic);
+ hdr.header_size = (sizeof hdr) >> 2;
+ hdr.block_size = CBLOCK_SIZE_LG2;
+ set_731(&hdr.uncompressed_len, size);
+
+ if ( fwrite(&hdr, sizeof hdr, 1, output) != 1 )
+ return EX_CANTCREAT;
+
+ nblocks = (size+CBLOCK_SIZE-1) >> CBLOCK_SIZE_LG2;
+ pointer_bytes = 4*(nblocks+1);
+ pointer_block = xmalloc(pointer_bytes);
+ memset(pointer_block, 0, pointer_bytes);
+
+ if ( fseek(output, pointer_bytes, SEEK_CUR) == -1 ) {
+ err = EX_CANTCREAT;
+ goto free_ptr_bail;
+ }
+
+ curptr = pointer_block;
+ position = sizeof hdr + pointer_bytes;
+
+ block = 0;
+ while ( (bytes = fread(inbuf, 1, CBLOCK_SIZE, input)) > 0 ) {
+ if ( bytes < CBLOCK_SIZE && block < nblocks-1 ) {
+ err = EX_IOERR;
+ goto free_ptr_bail;
+ }
+
+ /* HACK: If the file has our magic number, always compress */
+ if ( block == 0 && bytes >= sizeof zisofs_magic ) {
+ if ( !memcmp(inbuf, zisofs_magic, sizeof zisofs_magic) )
+ force_compress = 1;
+ }
+
+ set_731(curptr, position); curptr += 4;
+
+ /* We have two special cases: a zero-length block is defined as all zero,
+ and a block the length of which is equal to the block size is unencoded. */
+
+ for ( i = 0 ; i < (int)CBLOCK_SIZE ; i++ ) {
+ if ( inbuf[i] ) break;
+ }
+
+ if ( i == CBLOCK_SIZE ) {
+ /* All-zero block. No output */
+ } else {
+ cbytes = 2*CBLOCK_SIZE;
+ if ( (zerr = compress2(outbuf, &cbytes, inbuf, bytes, opt.level))
+ != Z_OK ) {
+ err = (zerr == Z_MEM_ERROR) ? EX_OSERR : EX_SOFTWARE;
+ goto free_ptr_bail; /* Compression failure */
+ }
+ if ( fwrite(outbuf, 1, cbytes, output) != cbytes ) {
+ err = EX_CANTCREAT;
+ goto free_ptr_bail;
+ }
+ position += cbytes;
+ }
+ block++;
+ }
+
+ /* Set pointer to the end of the final block */
+ set_731(curptr, position);
+
+ /* Now write the pointer table */
+ if ( fseek(output, sizeof hdr, SEEK_SET) == -1 ||
+ fwrite(pointer_block, 1, pointer_bytes, output) != pointer_bytes ) {
+ err = EX_CANTCREAT;
+ goto free_ptr_bail;
+ }
+
+ free(pointer_block);
+
+ /* Now make sure that this was actually the right thing to do */
+ if ( !force_compress && position >= size ) {
+ /* Incompressible file, just copy it */
+ rewind(input);
+ rewind(output);
+
+ position = 0;
+ while ( (bytes = fread(inbuf, 1, CBLOCK_SIZE, input)) > 0 ) {
+ if ( fwrite(inbuf, 1, bytes, output) != bytes )
+ return EX_CANTCREAT;
+ position += bytes;
+ }
+
+ /* Truncate the file to the correct size */
+ fflush(output);
+ ftruncate(fileno(output), position);
+ }
+
+ /* If we get here, we're done! */
+ return 0;
+
+ /* Common bailout code */
+ free_ptr_bail:
+ free(pointer_block);
+ return err;
+}
+