summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/main/cfe_zlibfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/main/cfe_zlibfs.c')
-rw-r--r--cfe/cfe/main/cfe_zlibfs.c453
1 files changed, 453 insertions, 0 deletions
diff --git a/cfe/cfe/main/cfe_zlibfs.c b/cfe/cfe/main/cfe_zlibfs.c
new file mode 100644
index 0000000..7ad0847
--- /dev/null
+++ b/cfe/cfe/main/cfe_zlibfs.c
@@ -0,0 +1,453 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * "Compressed" file system File: cfe_zlibfs.c
+ *
+ * This is more of a filesystem "hook" than an actual file system.
+ * You can stick it on the front of the chain of file systems
+ * that CFE calls and it will route data read from the
+ * underlying filesystem through ZLIB before passing it up to the
+ * user.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#if CFG_ZLIB
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_error.h"
+#include "cfe_fileops.h"
+#include "cfe_iocb.h"
+#include "cfe_devfuncs.h"
+#include "cfe_console.h"
+
+#include "cfe.h"
+
+#include "zlib.h"
+
+/* *********************************************************************
+ * ZLIBFS context
+ ********************************************************************* */
+
+/*
+ * File system context - describes overall file system info,
+ * such as the handle to the underlying device.
+ */
+
+typedef struct zlibfs_fsctx_s {
+ void *zlibfsctx_subfsctx;
+ const fileio_dispatch_t *zlibfsctx_subops;
+ int zlibfsctx_refcnt;
+} zlibfs_fsctx_t;
+
+/*
+ * File context - describes an open file on the file system.
+ * For raw devices, this is pretty meaningless, but we do
+ * keep track of where we are.
+ */
+
+#define ZLIBFS_BUFSIZE 1024
+typedef struct zlibfs_file_s {
+ zlibfs_fsctx_t *zlibfs_fsctx;
+ int zlibfs_fileoffset;
+ void *zlibfs_subfile;
+ z_stream zlibfs_stream;
+ uint8_t *zlibfs_inbuf;
+ uint8_t *zlibfs_outbuf;
+ int zlibfs_outlen;
+ uint8_t *zlibfs_outptr;
+ int zlibfs_eofseen;
+} zlibfs_file_t;
+
+/* *********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+static int zlibfs_fileop_init(void **fsctx,void *ctx);
+static int zlibfs_fileop_open(void **ref,void *fsctx,char *filename,int mode);
+static int zlibfs_fileop_read(void *ref,uint8_t *buf,int len);
+static int zlibfs_fileop_write(void *ref,uint8_t *buf,int len);
+static int zlibfs_fileop_seek(void *ref,int offset,int how);
+static void zlibfs_fileop_close(void *ref);
+static void zlibfs_fileop_uninit(void *fsctx);
+
+voidpf zcalloc(voidpf opaque,unsigned items, unsigned size);
+void zcfree(voidpf opaque,voidpf ptr);
+
+/* *********************************************************************
+ * ZLIB fileio dispatch table
+ ********************************************************************* */
+
+
+static uint8_t gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+const fileio_dispatch_t zlibfs_fileops = {
+ "z",
+ 0,
+ zlibfs_fileop_init,
+ zlibfs_fileop_open,
+ zlibfs_fileop_read,
+ zlibfs_fileop_write,
+ zlibfs_fileop_seek,
+ zlibfs_fileop_close,
+ zlibfs_fileop_uninit
+};
+
+/*
+ * Utility functions needed by the ZLIB routines
+ */
+voidpf zcalloc(voidpf opaque,unsigned items, unsigned size)
+{
+ void *ptr;
+
+ ptr = KMALLOC(items*size,0);
+ if (ptr) lib_memset(ptr,0,items*size);
+ return ptr;
+}
+
+void zcfree(voidpf opaque,voidpf ptr)
+{
+ KFREE(ptr);
+}
+
+
+static int zlibfs_fileop_init(void **newfsctx,void *curfsvoid)
+{
+ zlibfs_fsctx_t *fsctx;
+ fileio_ctx_t *curfsctx = (fileio_ctx_t *) curfsvoid;
+
+ *newfsctx = NULL;
+
+ fsctx = KMALLOC(sizeof(zlibfs_fsctx_t),0);
+ if (!fsctx) {
+ return CFE_ERR_NOMEM;
+ }
+
+ fsctx->zlibfsctx_refcnt = 0;
+ fsctx->zlibfsctx_subops = curfsctx->ops;
+ fsctx->zlibfsctx_subfsctx = curfsctx->fsctx;
+
+ *newfsctx = fsctx;
+
+ return 0;
+}
+
+
+static int get_byte(zlibfs_file_t *file,uint8_t *ch)
+{
+ int res;
+
+ res = BDREAD(file->zlibfs_fsctx->zlibfsctx_subops,
+ file->zlibfs_subfile,
+ ch,
+ 1);
+
+ return res;
+}
+
+
+static int check_header(zlibfs_file_t *file)
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ uint8_t c;
+ int res;
+
+ /* Check the gzip magic header */
+ for (len = 0; len < 2; len++) {
+ res = get_byte(file,&c);
+ if (c != gz_magic[len]) {
+ return -1;
+ }
+ }
+
+ get_byte(file,&c); method = (int) c;
+ get_byte(file,&c); flags = (int) c;
+
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ return -1;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(file,&c);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ get_byte(file,&c);
+ len = (uInt) c;
+ get_byte(file,&c);
+ len += ((uInt)c)<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while ((len-- != 0) && (get_byte(file,&c) == 1)) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((get_byte(file,&c) == 1) && (c != 0)) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((get_byte(file,&c) == 1) && (c != 0)) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(file,&c);
+ }
+
+ return 0;
+}
+
+static int zlibfs_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode)
+{
+ zlibfs_fsctx_t *fsctx;
+ zlibfs_file_t *file;
+ int err;
+
+ if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED;
+
+ fsctx = (zlibfs_fsctx_t *) fsctx_arg;
+
+ file = KMALLOC(sizeof(zlibfs_file_t),0);
+ if (!file) {
+ return CFE_ERR_NOMEM;
+ }
+
+ file->zlibfs_fileoffset = 0;
+ file->zlibfs_fsctx = fsctx;
+ file->zlibfs_inbuf = NULL;
+ file->zlibfs_outbuf = NULL;
+ file->zlibfs_eofseen = 0;
+
+ err = BDOPEN(fsctx->zlibfsctx_subops,&(file->zlibfs_subfile),
+ fsctx->zlibfsctx_subfsctx,filename);
+
+ if (err != 0) {
+ goto error2;
+ return err;
+ }
+
+ /* Open the zstream */
+
+ file->zlibfs_inbuf = KMALLOC(ZLIBFS_BUFSIZE,0);
+ file->zlibfs_outbuf = KMALLOC(ZLIBFS_BUFSIZE,0);
+
+ if (!file->zlibfs_inbuf || !file->zlibfs_outbuf) {
+ err = CFE_ERR_NOMEM;
+ goto error;
+ }
+
+ file->zlibfs_stream.next_in = NULL;
+ file->zlibfs_stream.avail_in = 0;
+ file->zlibfs_stream.next_out = file->zlibfs_outbuf;
+ file->zlibfs_stream.avail_out = ZLIBFS_BUFSIZE;
+ file->zlibfs_stream.zalloc = (alloc_func)0;
+ file->zlibfs_stream.zfree = (free_func)0;
+
+ file->zlibfs_outlen = 0;
+ file->zlibfs_outptr = file->zlibfs_outbuf;
+
+ err = inflateInit2(&(file->zlibfs_stream),-15);
+ if (err != Z_OK) {
+ err = CFE_ERR;
+ goto error;
+ }
+
+ check_header(file);
+
+ fsctx->zlibfsctx_refcnt++;
+
+ *ref = file;
+ return 0;
+
+error:
+ BDCLOSE(file->zlibfs_fsctx->zlibfsctx_subops,file->zlibfs_subfile);
+error2:
+ if (file->zlibfs_inbuf) KFREE(file->zlibfs_inbuf);
+ if (file->zlibfs_outbuf) KFREE(file->zlibfs_outbuf);
+ KFREE(file);
+ return err;
+}
+
+static int zlibfs_fileop_read(void *ref,uint8_t *buf,int len)
+{
+ zlibfs_file_t *file = (zlibfs_file_t *) ref;
+ int res = 0;
+ int err;
+ int amtcopy;
+ int ttlcopy = 0;
+
+ if (len == 0) return 0;
+
+ while (len) {
+
+ /* Figure the amount to copy. This is the min of what we
+ have left to do and what is available. */
+ amtcopy = len;
+ if (amtcopy > file->zlibfs_outlen) {
+ amtcopy = file->zlibfs_outlen;
+ }
+
+ /* Copy the data. */
+
+ if (buf) {
+ memcpy(buf,file->zlibfs_outptr,amtcopy);
+ buf += amtcopy;
+ }
+
+ /* Update the pointers. */
+ file->zlibfs_outptr += amtcopy;
+ file->zlibfs_outlen -= amtcopy;
+ len -= amtcopy;
+ ttlcopy += amtcopy;
+
+ /* If we've eaten all of the output, reset and call inflate
+ again. */
+
+ if (file->zlibfs_outlen == 0) {
+ /* If no input data to decompress, get some more if we can. */
+ if (file->zlibfs_eofseen) break;
+ if (file->zlibfs_stream.avail_in == 0) {
+ res = BDREAD(file->zlibfs_fsctx->zlibfsctx_subops,
+ file->zlibfs_subfile,
+ file->zlibfs_inbuf,
+ ZLIBFS_BUFSIZE);
+ /* If at EOF or error, get out. */
+ if (res <= 0) break;
+ file->zlibfs_stream.next_in = file->zlibfs_inbuf;
+ file->zlibfs_stream.avail_in = res;
+ }
+
+ /* inflate the input data. */
+ file->zlibfs_stream.next_out = file->zlibfs_outbuf;
+ file->zlibfs_stream.avail_out = ZLIBFS_BUFSIZE;
+ file->zlibfs_outptr = file->zlibfs_outbuf;
+ err = inflate(&(file->zlibfs_stream),Z_SYNC_FLUSH);
+ if (err == Z_STREAM_END) {
+ /* We can get a partial buffer fill here. */
+ file->zlibfs_eofseen = 1;
+ }
+ else if (err != Z_OK) {
+ res = CFE_ERR;
+ break;
+ }
+ file->zlibfs_outlen = file->zlibfs_stream.next_out -
+ file->zlibfs_outptr;
+ }
+
+ }
+
+ file->zlibfs_fileoffset += ttlcopy;
+
+ return (res < 0) ? res : ttlcopy;
+}
+
+static int zlibfs_fileop_write(void *ref,uint8_t *buf,int len)
+{
+ return CFE_ERR_UNSUPPORTED;
+}
+
+static int zlibfs_fileop_seek(void *ref,int offset,int how)
+{
+ zlibfs_file_t *file = (zlibfs_file_t *) ref;
+ int res;
+ int delta;
+
+ switch (how) {
+ case FILE_SEEK_BEGINNING:
+ delta = offset - file->zlibfs_fileoffset;
+ break;
+ case FILE_SEEK_CURRENT:
+ delta = offset;
+ break;
+ default:
+ return CFE_ERR_UNSUPPORTED;
+ break;
+ }
+
+ /* backward seeking not allowed on compressed streams */
+ if (delta < 0) {
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ res = zlibfs_fileop_read(ref,NULL,delta);
+
+ if (res < 0) return res;
+
+ return file->zlibfs_fileoffset;
+}
+
+
+static void zlibfs_fileop_close(void *ref)
+{
+ zlibfs_file_t *file = (zlibfs_file_t *) ref;
+
+ file->zlibfs_fsctx->zlibfsctx_refcnt--;
+
+ inflateEnd(&(file->zlibfs_stream));
+
+ BDCLOSE(file->zlibfs_fsctx->zlibfsctx_subops,file->zlibfs_subfile);
+
+ KFREE(file);
+}
+
+static void zlibfs_fileop_uninit(void *fsctx_arg)
+{
+ zlibfs_fsctx_t *fsctx = (zlibfs_fsctx_t *) fsctx_arg;
+
+ if (fsctx->zlibfsctx_refcnt) {
+ xprintf("zlibfs_fileop_uninit: warning: refcnt not zero\n");
+ }
+
+ BDUNINIT(fsctx->zlibfsctx_subops,fsctx->zlibfsctx_subfsctx);
+
+ KFREE(fsctx);
+}
+
+
+#endif