home *** CD-ROM | disk | FTP | other *** search
- /* xpk.c - routines for the master xpk.library.
- Copyright (C) 1991, 1992, 1993 Kristian Nielsen.
-
- This file is part of XFH, the compressing file system handler.
-
- 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; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "CFS.h"
- #include <dossupport.h>
-
- #include <exec/ports.h>
- #include <exec/libraries.h>
- #include <utility/hooks.h>
- #include <utility/tagitem.h>
-
- #include <proto/exec.h>
- #include <proto/dos.h>
-
- #include <clib/alib_protos.h>
-
- #include <libraries/xpk.h>
-
- #include <string.h>
-
- /* These two include files are changing all the time. Hence the #undef. */
- #undef XpkFH
-
- struct Library *XpkBase;
-
-
- #ifndef min
- #define min(a,b) ((a)>(b) ? (b) : (a))
- #endif
-
- /* 'Conditional' tag - passed only if condition true. */
- #define TAGIF(c,t) ((c)?(t):TAG_IGNORE)
-
- /* Structure for holding an xpk file unpacked in memory. */
- struct unpackedxpk {
- struct xpkmemchunk *first,*last,*current;
- LONG currentpos;
- };
-
- /* Node in linked list of data buffers. */
- struct xpkmemchunk {
- struct xpkmemchunk *next;
- LONG abspos;
- LONG size;
- UBYTE *data; /* MUST be alloced with dosalloc(). */
- };
-
- struct XpkFH {
- struct CFSFH cfsfh;
- struct unpackedxpk *unpackedxpk;
- LONG filelen;
- UBYTE *InBuf; /* Buffer last returned by inhook. */
- UBYTE *OutBuf; /* Buffer last returned by outhook. */
- LONG InBufLen; /* Of InBuf. (ToDo: Not really used...) */
- LONG OutBufLen; /* Of OutBuf. (ToDo: Not really used...) */
- };
-
- struct XpkLock {
- struct CFSLock cfslock;
- };
-
-
-
- static struct unpackedxpk *newunpackedxpk(void){
- struct unpackedxpk *p;
-
- if(!dalloc(p)) return NULL;
- /* All fields 0 by default. */
- return p;
- }
-
- /* NOTE: 'data' should be allocated with dosalloc().
- * NOTE ALSO: Memory block may be larger than 'size' (will be freed by
- * dosfree() ).
- */
- static BOOL addxpkmemchunk(struct unpackedxpk *p, UBYTE *data, LONG size ){
- struct xpkmemchunk *q;
-
- if(!(dalloc(q))) return FALSE;
- q->next=NULL;
- q->size=size;
- q->data=data;
- if(!p->first){
- q->abspos = 0L;
- p->first=p->current=p->last = q;
- }else{
- q->abspos = p->last->abspos+p->last->size;
- p->last->next = q;
- p->last = q;
- }
- return TRUE;
- }
-
- static void killunpackedxpk(struct unpackedxpk *p){
- struct xpkmemchunk *q,*r;
-
- for(q=p->first;q;q=r){
- r=q->next;
- dfree(q->data);
- dfree(q);
- }
- dfree(p);
- }
-
- static BOOL seekunpackedxpk(struct unpackedxpk *p, LONG abspos){
- struct xpkmemchunk *q;
-
- if(abspos < 0 || !p->first || p->last->abspos+p->last->size < abspos)
- return (BOOL) (abspos == 0);
- /* Special case: seek just beyond end. */
- if(p->last->abspos+p->last->size == abspos){
- debug(("Seeking to last position in file: %ld.\n",abspos));
- p->current = p->last;
- p->currentpos = abspos;
- return DOSTRUE;
- }
- /* Start at current pos. if possible. */
- q = p->current->abspos <= abspos ? p->current : p->first;
- while(q->abspos+q->size <= abspos) q = q->next;
- p->current = q;
- p->currentpos = abspos;
- return DOSTRUE;
- }
-
- static BOOL readunpackedxpk(struct unpackedxpk *p, UBYTE *buf, LONG size){
- struct xpkmemchunk *q;
- LONG len,chunkpos;
-
- if(!p->first)
- return (BOOL) (size==0);
- q = p->current;
- while(size>0){
- if(p->last->abspos+p->last->size <= p->currentpos) return FALSE;
- chunkpos=p->currentpos-q->abspos;
- len = min(size,q->size-chunkpos);
- CopyMem(q->data+chunkpos,buf,len);
- size-=len;
- buf+=len;
- p->currentpos+=len;
- if(p->currentpos >= q->abspos+q->size) q=q->next;
- if(q) p->current = q;
- }
- return TRUE;
- }
-
-
-
- /*------------------------------------------------------------------------*
- * Hooks for Xpk packing / unpacking.
- */
-
- /* Structure for private hook data (glob & Xpkfilehandle). */
- struct xpkhookdata {
- glb glob;
- struct XpkFH *fh;
- };
-
-
- /* Free Xpk input buffer if nessesary. */
- static void FreeXpkInBuf(struct XpkFH *fh){
-
- /* debug(("FreeXpkInBuf: Checking if buffers allocated...\n")); */
- if(fh->InBuf){
- /* debug(("FreeXpkInBuf: Freeing buffer: %lx,%ld.\n",fh->InBuf,fh->InBufLen)); */
- dosfree(fh->InBuf);
- fh->InBuf = NULL;
- }
- }
-
- /* Allocate Xpk input buffer. */
- static UBYTE *AllocXpkInBuf(struct XpkFH *fh, LONG size){
-
- /* NOTE: I found out (the hard way...) that Xpk expects a buffer
- * 4 bytes larger than requested ... wierd. */
- size+=4;
- FreeXpkInBuf(fh);
- fh->InBufLen=size;
- if(!(fh->InBuf=dosalloc(size))){
- return 0L;
- }
- return fh->InBuf;
- }
-
- /* Free Xpk output buffer if nessesary. */
- static void FreeXpkOutBuf(struct XpkFH *fh){
-
- /* debug(("FreeXpkOutBuf: Checking if buffers allocated...\n")); */
- if(fh->OutBuf){
- /* debug(("FreeXpkOutBuf: Freeing buffer: %lx,%ld.\n",fh->OutBuf,fh->OutBufLen)); */
- dosfree(fh->OutBuf);
- fh->OutBuf = NULL;
- }
- }
-
- /* Allocate Xpk output buffer. */
- static UBYTE *AllocXpkOutBuf(struct XpkFH *fh, LONG size){
-
- /* NOTE: I found out (the hard way...) that Xpk expects a buffer
- * 4 bytes larger than requested ... wierd. */
- size+=4;
- FreeXpkOutBuf(fh);
- fh->OutBufLen=size;
- if(!(fh->OutBuf=dosalloc(size))){
- return 0L;
- }
- return fh->OutBuf;
- }
-
- /* Transfer control to actual hook function. Shields the actual */
- /* hook functions from any ugly assembler-like register considerations. */
-
- static LONG __asm DoXpkHook( register __a0 struct Hook *hook,
- register __a1 struct XpkIOMsg *msg,
- register __a2 void *dummy){
- struct xpkhookdata *hookdata = hook->h_Data;
- LONG ret;
- typedef LONG (*myhooktype)(glb, struct XpkFH *, ULONG, UBYTE **, LONG);
-
- ret = (*(myhooktype)hook->h_SubEntry)
- (hookdata->glob, hookdata->fh,msg->Type,(UBYTE **)&msg->Ptr,msg->Size);
- if(ret) msg->IOError = hookdata->glob->ioerr;
- return ret;
- }
-
-
- /* Calling conventions for hooks. */
- /* ToDo: When docs become available, check against this description. */
- /* */
- /* XpkIOMsg->IOError is set only in case of non-zero hook return value. */
- /* */
- /* Big problem: What is XIO_SEEK supposed to return in XpkIOMsg->Ptr? */
- /* The masterlib does the wierdest things... However, it (currently!) */
- /* only needs a non-zero return in case of succes. */
- /* */
- /* XIO_GETBUF/XIO_WRITE in xpkunpackout(): It is assumed that only one */
- /* buffer will be needed at any time, so that a second XIO_GETBUF may */
- /* free the buffer returned by the first. It is also assumed that */
- /* XIO_WRITE may grab the buffer it is writing if it was allocated by */
- /* XIO_GETBUF. */
- /* */
-
- /* Read() hook for unpacking. */
- static LONG xpkunpackin(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
- LONG actuallen;
-
- /* debug(("UnpackInHook: Type=%ld, Buf=%lx, Len=%ld.\n",type, *buf,size));*/
- switch(type){
- case XIO_READ:
- if(!*buf){
- if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
- }
- if( (actuallen = xRead(glob, fh->cfsfh.xfh, *buf, size)) != size){
- return actuallen >= 0 ? XPKERR_TRUNCATED : XPKERR_IOERRIN;
- }
- break;
- case XIO_WRITE:
- debug(("Error: xpkunpackin(): Xpk attemps to XIO_WRITE.\n"));
- return XPKERR_NOFUNC;
- case XIO_FREE:
- case XIO_ABORT:
- FreeXpkInBuf(fh);
- break;
- case XIO_GETBUF:
- if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
- break;
- case XIO_SEEK:
- if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){
- return XPKERR_IOERROUT;
- }
- *buf = (APTR) 4L; /* VERY strange... */
- break;
- case XIO_TOTSIZE:
- /* debug(("..... XIO_TOTSIZE: no action...\n")); */
- break;
- default:
- debug(("*** PANIC: xpkunpackin(): Unknown type of action requested.\n"));
- return XPKERR_NOFUNC;
- }
-
- return XPKERR_OK;
- }
-
-
- /* Write() hook for unpacking. */
- static LONG xpkunpackout(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
-
- /* debug(("UnpackOutHook: Type=%ld, Buf=%lx, Len=%ld.\n",type,*buf,size)); */
- switch(type){
- case XIO_READ:
- debug(("Error: xpkunpackout(): Xpk attemps to XIO_READ.\n"));
- return XPKERR_NOFUNC;
- case XIO_WRITE:
- if( *buf == fh->OutBuf /* && size == fh->OutBufLen */ ){
- /* Writing our previously allocated buffer. Just add it to */
- /* the filehandle, and mark it as used. */
- /* NOTE: because of safety margin, the added memory block is */
- /* larger than nesseeary. */
-
- /* debug(("Adding previously allocated buffer to filehandle: %lx\n",*buf)); */
- if(!addxpkmemchunk(fh->unpackedxpk,*buf,size)){
- debug(("Error: xpkunpackout(): Cannot add data.\n"));
- return XPKERR_NOMEM;
- }
- fh->OutBuf = NULL;
- fh->OutBufLen = 0L;
- }else{
- UBYTE *newbuf;
-
- /* debug(("Copying data into filehandle.\n")); */
- if( !(newbuf = dosalloc(size)) ){
- debug(("Error: xpkunpackout(): No memory.\n"));
- return XPKERR_NOMEM;
- }
- CopyMem(*buf,newbuf,size);
- if(!addxpkmemchunk(fh->unpackedxpk,newbuf,size)){
- debug(("Error: xpkunpackout(): Cannot add data.\n"));
- dosfree(newbuf);
- return XPKERR_NOMEM;
- }
- }
- break;
- case XIO_FREE:
- case XIO_ABORT:
- FreeXpkOutBuf(fh);
- break;
- case XIO_GETBUF:
- if( !(*buf = AllocXpkOutBuf(fh,size)) ){
- debug(("Error: xpkunpackout(): Cannot get buffer for xpk.\n"));
- return XPKERR_NOMEM;
- }
- /* debug(("xpkunpackout()/XIO_GETBUF: returning buffer %lx\n",*buf)); */
- break;
- case XIO_SEEK:
- /* Strange... Surely this code is wrong? I mean, there's no file
- * handle, is there? Commented out for now. */
- /* if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){ */
- /* return XPKERR_IOERROUT; */
- /* } */
- /* *buf = (APTR) 4L; /* VERY strange... */
- debug(("Error: xpkunpackout(): Xpk attempts to XIO_SEEK.\n"));
- return XPKERR_NOFUNC;
- /* break; */
- case XIO_TOTSIZE:
- /* debug(("..... XIO_TOTSIZE: no action...\n")); */
- break;
- default:
- debug(("*** PANIC: xpkunpackout(): Unknown type of action requested.\n"));
- return XPKERR_NOFUNC;
- }
- return XPKERR_OK;
- }
-
-
- /* Hooks for Xpk packing.
- * Currently, these use simple XpkFH file handles. However, I'm hoping
- * to eventually make them use async I/O.
- * NOTE BIEN: these XpkFH are FAKE, and cannot be used as such safely.
- * Specifically, the cfsfh is not valid (though cfsfh.xfh is).
- */
-
- /* NOTE: xpkpackin() / xpkpackout() are also used for unpacking. */
- /* Read() hook for packing. */
- static LONG xpkpackin(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
- LONG actuallen;
-
- /* debug(("PackInHook: Type=%ld, Buf=%lx, Len=%ld.\n",type, *buf,size));*/
- switch(type){
- case XIO_READ:
- if(!*buf){
- if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
- }
- if( (actuallen = xRead(glob, fh->cfsfh.xfh, *buf, size)) != size){
- return actuallen >= 0 ? XPKERR_TRUNCATED : XPKERR_IOERRIN;
- }
- break;
- case XIO_WRITE:
- debug(("Error: xpkpackin(): Xpk attemps to XIO_WRITE.\n"));
- return XPKERR_NOFUNC;
- case XIO_FREE:
- case XIO_ABORT:
- FreeXpkInBuf(fh);
- break;
- case XIO_GETBUF:
- if(!(*buf=AllocXpkInBuf(fh,size))) return XPKERR_NOMEM;
- break;
- case XIO_SEEK:
- if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){
- return XPKERR_IOERROUT;
- }
- *buf = (APTR) 4L; /* VERY strange... */
- break;
- case XIO_TOTSIZE:
- /* debug(("..... XIO_TOTSIZE: no action...\n")); */
- break;
- default:
- debug(("*** PANIC: xpkpackin(): Unknown type of action requested.\n"));
- return XPKERR_NOFUNC;
- }
-
- return XPKERR_OK;
- }
-
-
- /* Write() hook for packing. */
- static LONG xpkpackout(glb glob, struct XpkFH *fh, ULONG type, UBYTE **buf, LONG size){
-
- /* debug(("PackOutHook: Type=%ld, Buf=%lx, Len=%ld.\n",type,*buf,size));*/
- switch(type){
- case XIO_READ:
- debug(("Error: xpkpackout(): Xpk attemps to XIO_READ.\n"));
- return XPKERR_NOFUNC;
- case XIO_WRITE:
- if(xWrite(glob, fh->cfsfh.xfh, *buf, size) != size){
- return XPKERR_IOERROUT;
- }
- break;
- case XIO_FREE:
- case XIO_ABORT:
- FreeXpkOutBuf(fh);
- break;
- case XIO_GETBUF:
- if( !(*buf = AllocXpkOutBuf(fh,size)) ){
- debug(("Error: xpkpackout(): Cannot get buffer for xpk.\n"));
- return XPKERR_NOMEM;
- }
- /* debug(("xpkpackout()/XIO_GETBUF: returning buffer %lx\n",*buf)); */
- break;
- case XIO_SEEK:
- if( xSeek( glob, fh->cfsfh.xfh, size, OFFSET_CURRENT)<0 ){
- return XPKERR_IOERROUT;
- }
- *buf = (APTR) 4L; /* VERY strange... */
- break;
- case XIO_TOTSIZE:
- /* debug(("..... XIO_TOTSIZE: no action...\n")); */
- break;
- default:
- debug(("*** PANIC: xpkpackout(): Unknown type of action requested.\n"));
- return XPKERR_NOFUNC;
- }
- return XPKERR_OK;
- }
-
-
-
- /*------------------------------------------------------------------------*
- * Low-level interface to Xpk functions.
- */
-
-
- /* The following code is there to support pre-2.0 OS versions. The
- * problem is that Xpk insists on doing OpenLibrary() itself, which
- * causes the dreaded ASYNCPKT guru.
- */
-
- struct xpkunpackmsg{
- struct Message msg;
- void (*func)();
- glb glob;
- struct TagItem *tags;
- LONG result;
- };
-
- struct xpkexammsg{
- struct Message msg;
- void (*func)();
- glb glob;
- struct XpkFib *fib;
- struct TagItem *tags;
- LONG result;
- };
-
- struct xpkpackmsg{
- struct Message msg;
- void (*func)();
- glb glob;
- struct TagItem *tags;
- LONG result;
- };
-
- static void __asm CallXpkUnpackTags(register __a0 struct xpkunpackmsg *msg){
- struct MsgPort *port;
-
- debug(("Calling XpkUnpack(%lx)...", msg->tags ));
- port = msg->glob->ioport;
- if(msg->glob->ioport=CreatePort(NULL,0L)){
- msg -> result = XpkUnpack(msg->tags);
- DeletePort(msg->glob->ioport);
- }else{
- debug(("(no port)"));
- msg->result = XPKERR_NOMEM;
- }
- msg->glob->ioport = port;
- debug(("=%ld\n",msg->result));
- }
-
-
- static void __asm CallXpkExamine(register __a0 struct xpkexammsg *msg){
- struct MsgPort *port;
-
- debug(("Calling XpkExamine(%lx,%lx)...", msg->fib, msg->tags ));
- port = msg->glob->ioport;
- if(msg->glob->ioport=CreatePort(NULL,0L)){
- msg -> result = XpkExamine(msg->fib, msg->tags);
- DeletePort(msg->glob->ioport);
- }else{
- debug(("(no port)"));
- msg->result = XPKERR_NOMEM;
- }
- msg->glob->ioport = port;
- debug(("=%ld\n",msg->result));
- }
-
-
- static void __asm CallXpkPackTags(register __a0 struct xpkpackmsg *msg){
- struct MsgPort *port;
-
- debug(("Calling XpkPack(%lx)...", msg->tags ));
- port = msg->glob->ioport;
- if(msg->glob->ioport=CreatePort(NULL,0L)){
- msg -> result = XpkPack(msg->tags);
- DeletePort(msg->glob->ioport);
- }else{
- debug(("(no port)"));
- msg->result = XPKERR_NOMEM;
- }
- msg->glob->ioport = port;
- debug(("=%ld\n",msg->result));
- }
-
-
- static LONG MyXpkUnpackTags( glb glob, ULONG firsttag, ... ){
- /* Cannot call xpk from a Task (or handler) before KS 2.0. */
- if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
- return XpkUnpack( (struct TagItem *)&firsttag );
- }else{
- struct xpkunpackmsg msg,*msg2;
- extern void DoDOSSeg();
- struct MsgPort *procid;
-
- msg.msg.mn_Node.ln_Succ=NULL;
- msg.msg.mn_Node.ln_Pred=NULL;
- msg.msg.mn_Node.ln_Name=NULL;
- msg.msg.mn_Node.ln_Type=NT_MESSAGE;
- msg.msg.mn_Node.ln_Pri=0;
- msg.msg.mn_ReplyPort=glob->xpkport;
- msg.msg.mn_Length=sizeof(msg);
- msg.func=(void (*)()) CallXpkUnpackTags;
- msg.glob = glob;
- msg.tags = (struct TagItem *)&firsttag;
-
- if(!(procid=CreateProc /* Lets pray that 10K stack is enough... */
- ("XpkUnpack()",glob->mytask->tc_Node.ln_Pri,(BPTR)((ULONG)DoDOSSeg>>2),10000L)))
- return XPKERR_NOMEM;
-
- PutMsg(procid,(struct Message *)&msg);
- do WaitPort(glob->xpkport);
- while(!(msg2=(struct xpkunpackmsg *)GetMsg(glob->xpkport)));
-
- #ifdef DEBUG
- if(msg2!=&msg)
- dprintf("ERROR: bogus return message: &msg=%lx msg2=%lx\n",&msg,msg2);
- #endif
- return msg2->result;
- }
- }
-
- static LONG MyXpkExamine( glb glob, struct XpkFib *fib, ULONG firsttag, ... ){
- /* Cannot call xpk from a Task (or handler) before KS 2.0. */
- if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
- return XpkExamine( fib, (struct TagItem *)&firsttag );
- }else{
- struct xpkexammsg msg,*msg2;
- extern void DoDOSSeg();
- struct MsgPort *procid;
-
- msg.msg.mn_Node.ln_Succ=NULL;
- msg.msg.mn_Node.ln_Pred=NULL;
- msg.msg.mn_Node.ln_Name=NULL;
- msg.msg.mn_Node.ln_Type=NT_MESSAGE;
- msg.msg.mn_Node.ln_Pri=0;
- msg.msg.mn_ReplyPort=glob->xpkport;
- msg.msg.mn_Length=sizeof(msg);
- msg.func=(void (*)()) CallXpkExamine;
- msg.glob = glob;
- msg.fib = fib;
- msg.tags = (struct TagItem *)&firsttag;
-
- if(!(procid=CreateProc /* Lets pray that 10K stack is enough... */
- ("XpkExamine()",glob->mytask->tc_Node.ln_Pri,(BPTR)((ULONG)DoDOSSeg>>2),10000L)))
- return XPKERR_NOMEM;
-
- PutMsg(procid,(struct Message *)&msg);
- do WaitPort(glob->xpkport);
- while(!(msg2=(struct xpkexammsg *)GetMsg(glob->xpkport)));
-
- #ifdef DEBUG
- if(msg2!=&msg)
- dprintf("ERROR: bogus return message: &msg=%lx msg2=%lx\n",&msg,msg2);
- #endif
- return msg2->result;
- }
- }
-
- static LONG MyXpkPackTags( glb glob, ULONG firsttag, ... ){
- /* Cannot call Xpk from a Task (or handler) before KS 2.0. */
- if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
- return XpkPack( (struct TagItem *)&firsttag );
- }else{
- struct xpkpackmsg msg,*msg2;
- extern void DoDOSSeg();
- struct MsgPort *procid;
-
- msg.msg.mn_Node.ln_Succ=NULL;
- msg.msg.mn_Node.ln_Pred=NULL;
- msg.msg.mn_Node.ln_Name=NULL;
- msg.msg.mn_Node.ln_Type=NT_MESSAGE;
- msg.msg.mn_Node.ln_Pri=0;
- msg.msg.mn_ReplyPort=glob->xpkport;
- msg.msg.mn_Length=sizeof(msg);
- msg.func=(void (*)())CallXpkPackTags;
- msg.glob = glob;
- msg.tags = (struct TagItem *)&firsttag;
-
- if(!(procid=CreateProc /* Lets pray that 10K stack is enough... */
- ("XpkPack()",glob->mytask->tc_Node.ln_Pri,(BPTR)((ULONG)DoDOSSeg>>2),10000L)))
- return XPKERR_NOMEM;
-
- PutMsg(procid,(struct Message *)&msg);
- do WaitPort(glob->xpkport);
- while(!(msg2=(struct xpkpackmsg *)GetMsg(glob->xpkport)));
-
- #ifdef DEBUG
- if(msg2!=&msg)
- dprintf("ERROR: bogus return message: &msg=%lx msg2=%lx\n",&msg,msg2);
- #endif
- return msg2->result;
- }
- }
-
-
- /* This function opens an existing file in the xpk format, unpacking
- * it to memory with the help of the xpk.library. Note that due to
- * limitation in the current interface of xpk.library, the whole file
- * must be unpacked at once, which is more speed efficient (and by far
- * the easiest to implement), but requires rather a lot of memory
- * (potentially requiring the data to reside 2-3 times in main memory
- * simultaneously) and could result in memory fragmentation.
- */
- struct XpkFH *XpkOpenOldFile( glb glob, struct FileHandle *xfh ){
- struct XpkFH *fh;
- LONG res;
- LONG inlen;
- struct Hook inhook,outhook;
- struct xpkhookdata indata,outdata;
-
- if(!dalloc(fh)){
- OUTOFMEM;
- return NULL;
- }
- fh->cfsfh.objtype = XPKOBJECT;
- fh->cfsfh.mode = MODE_OLDFILE;
- fh->cfsfh.xfh = xfh;
- fh->cfsfh.f = &Xpkfunc;
- /* fh->cfsfh.filename and fh->cfsfh.parent NULL by default. */
-
- if(!(fh->unpackedxpk=newunpackedxpk())){
- OUTOFMEM;
- dfree(fh);
- return NULL;
- }
-
- inhook.h_Entry = (ULONG (*)())DoXpkHook;
- inhook.h_SubEntry = (ULONG (*)())xpkunpackin;
- indata.glob=glob;
- indata.fh=fh;
- inhook.h_Data = &indata;
- outhook.h_Entry = (ULONG (*)())DoXpkHook;
- outhook.h_SubEntry = (ULONG (*)())xpkunpackout;
- outdata.glob=glob;
- outdata.fh=fh;
- outhook.h_Data = &outdata;
-
- /* Get length of file, if possible. */
- inlen = xFileSizeXfh( glob, xfh );
-
- glob->ioerr = 0L; /* Set by hookfuncs if adequate. */
- res = MyXpkUnpackTags( glob,
- XPK_InHook, &inhook,
- XPK_OutHook, &outhook,
- XPK_Password, glob->xpkpassword,
- TAGIF(inlen!=-1L,XPK_InLen), inlen,
- TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
- TAG_DONE
- );
- debug(("XpkUnPack() returned: %ld\n",res));
- FreeXpkInBuf(fh);
- FreeXpkOutBuf(fh);
-
- if(res != XPKERR_OK){
- if(!glob->ioerr){
- /* ToDo: Since no adequate AmigaDOS error code exists, we */
- /* should perhaps open a requester to inform the user of */
- /* the problem (showing an XpkErr)? */
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE; /* More likely out of memory. */
- }
- killunpackedxpk(fh->unpackedxpk);
- dfree(fh);
- return NULL;
- }
- if(fh->unpackedxpk->first)
- fh->filelen = fh->unpackedxpk->last->abspos
- + fh->unpackedxpk->last->size; /* else 0 by default. */
- return fh;
- }
-
-
- /* Perform a XpkExamine() on an UFS file handle. */
- BOOL XpkExamine_FH( glb glob, struct FileHandle *xfh, struct XpkFib *fib ){
- LONG res;
- LONG inlen;
- struct XpkFH *fh;
- struct Hook inhook;
- struct xpkhookdata indata;
-
- if(!dalloc(fh)){ /* NOTE: NOT a real xpkfilehandle (only InBuf is used). */
- OUTOFMEM;
- return FALSE;
- }
- fh->cfsfh.xfh = xfh;
-
- inhook.h_Entry = (ULONG (*)())DoXpkHook;
- inhook.h_SubEntry = (ULONG (*)())xpkunpackin;
- indata.glob=glob;
- indata.fh=fh;
- inhook.h_Data = &indata;
-
- /* Get length of file, if possible. */
- inlen = xFileSizeXfh( glob, xfh );
-
- glob->ioerr = 0L; /* Set by hookfuncs if adequate. */
- res = MyXpkExamine( glob, fib,
- XPK_InHook,&inhook,
- TAGIF(inlen!=-1L,XPK_InLen), inlen,
- TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
- TAG_DONE
- );
- debug(("XpkExamine() returned: %ld\n",res));
- FreeXpkInBuf(fh);
- dfree(fh);
- /* Need a better error message here. */
- if( res && !glob->ioerr ) glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return (BOOL)( res==XPKERR_OK );
- }
-
-
- /* This is the function that does the actual compression (using xpk) from
- * one file handle to another.
- */
- static BOOL XpkPackFH2FH(glb glob, struct FileHandle *srcxfh,
- LONG inlen, struct FileHandle *dstxfh){
- struct XpkFH *srcxpkfh,*dstxpkfh; /* NOTE: these are FAKE/invalid. */
- LONG res;
- LONG outlen; /* Dummy variable. */
- struct Hook inhook,outhook;
- struct xpkhookdata indata,outdata;
-
- /* Create the two fake XpkFH filehandles for the hooks. */
- if(!dalloc(srcxpkfh)){
- OUTOFMEM;
- return FALSE;
- }
- if(!dalloc(dstxpkfh)){
- OUTOFMEM;
- dfree(srcxpkfh);
- return FALSE;
- }
- srcxpkfh->cfsfh.xfh = srcxfh; /* Buffer pointers NULL by default. */
- dstxpkfh->cfsfh.xfh = dstxfh; /* Buffer pointers NULL by default. */
-
- /* Set up hooks. */
- inhook.h_Entry = (ULONG (*)())DoXpkHook;
- inhook.h_SubEntry = (ULONG (*)())xpkpackin;
- indata.glob=glob;
- indata.fh=srcxpkfh;
- inhook.h_Data = &indata;
- outhook.h_Entry = (ULONG (*)())DoXpkHook;
- outhook.h_SubEntry = (ULONG (*)())xpkpackout;
- outdata.glob=glob;
- outdata.fh=dstxpkfh;
- outhook.h_Data = &outdata;
-
- glob->ioerr = 0L; /* Set by hookfuncs if adequate. */
- res = MyXpkPackTags( glob,
- XPK_InHook,&inhook,
- XPK_OutHook,&outhook,
- XPK_InLen,inlen,
- XPK_PackMethod,glob->packmode,
- XPK_StepDown,glob->stepdown,
- XPK_Password,glob->xpkpassword,
- XPK_GetOutLen,&outlen, /* NOTE: not used, buf xpk.doc says needed. */
- TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
- TAG_DONE
- );
- debug(("XpkPack() returned: %ld\n",res));
-
- FreeXpkInBuf(srcxpkfh);
- FreeXpkOutBuf(dstxpkfh);
- dfree(srcxpkfh);
- dfree(dstxpkfh);
-
- if(res != XPKERR_OK){
- if(!glob->ioerr){
- /* ToDo: Since no adequate AmigaDOS error code exists, we */
- /* should perhaps open a requester to inform the user of */
- /* the problem (showing an XpkErr)? */
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE; /* More likely out of memory. */
- }
- return FALSE;
- }
- return TRUE;
- }
-
-
- /* This is the function that does the actual compression (using xpk) from
- * one file handle to another.
- */
- static BOOL XpkUnPackFH2FH(glb glob, struct FileHandle *srcxfh,
- LONG inlen, struct FileHandle *dstxfh){
- struct XpkFH *srcxpkfh,*dstxpkfh; /* NOTE: these are FAKE/invalid. */
- LONG res;
- struct Hook inhook,outhook;
- struct xpkhookdata indata,outdata;
-
- /* Create the two fake XpkFH filehandles for the hooks. */
- if(!dalloc(srcxpkfh)){
- OUTOFMEM;
- return FALSE;
- }
- if(!dalloc(dstxpkfh)){
- OUTOFMEM;
- dfree(srcxpkfh);
- return FALSE;
- }
- srcxpkfh->cfsfh.xfh = srcxfh; /* Buffer pointers NULL by default. */
- dstxpkfh->cfsfh.xfh = dstxfh; /* Buffer pointers NULL by default. */
-
- /* Set up hooks. */
- inhook.h_Entry = (ULONG (*)())DoXpkHook;
- inhook.h_SubEntry = (ULONG (*)())xpkpackin;
- indata.glob=glob;
- indata.fh=srcxpkfh;
- inhook.h_Data = &indata;
- outhook.h_Entry = (ULONG (*)())DoXpkHook;
- outhook.h_SubEntry = (ULONG (*)())xpkpackout;
- outdata.glob=glob;
- outdata.fh=dstxpkfh;
- outhook.h_Data = &outdata;
-
- glob->ioerr = 0L; /* Set by hookfuncs if adequate. */
- res = MyXpkUnpackTags( glob,
- XPK_InHook,&inhook,
- XPK_OutHook,&outhook,
- XPK_InLen,inlen,
- XPK_Password,glob->xpkpassword,
- TAGIF(glob->xpksetpri,XPK_TaskPri), glob->xpkpri,
- TAG_DONE
- );
- debug(("XpkUnPack() returned: %ld\n",res));
-
- FreeXpkInBuf(srcxpkfh);
- FreeXpkOutBuf(dstxpkfh);
- dfree(srcxpkfh);
- dfree(dstxpkfh);
-
- if(res != XPKERR_OK){
- if(!glob->ioerr){
- /* ToDo: Since no adequate AmigaDOS error code exists, we */
- /* should perhaps open a requester to inform the user of */
- /* the problem (showing an XpkErr)? */
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE; /* More likely out of memory. */
- }
- return FALSE;
- }
- return TRUE;
- }
-
-
- /* NOTE BIEN: This function preserves the lock! */
- struct XpkFH *XpkOpenOldFileFromCopyOfLock( glb glob, struct XpkLock *lock ){
- struct FileHandle *xfh;
- struct XpkFH *fh;
-
- if(!(xfh = xOpenFromCopyOfLock(glob, lock->cfslock.xlock))){
- debug(("Unable to xOpenFromLock(): %ld.\n",glob->ioerr));
- return NULL;
- }
- fh = XpkOpenOldFile( glob, xfh );
- if(!fh){
- LONG saveioerr = glob->ioerr;
- xClose(glob,xfh);
- glob->ioerr = saveioerr;
- }
- return fh;
- }
-
-
- /* Check if a given filehandle belongs to an Xpk file. glob->ioerr
- * set and FALSE returned in case of error.
- */
-
- BOOL IsXpkFile( glb glob, struct FileHandle *xfh ){
- struct XpkFib fib;
-
- if( !XpkExamine_FH(glob, xfh, &fib) ){
- debug(("Error: IsXpkFile: XpkExamine_FH returned error\n"));
- return FALSE;
- }else if( fib.Type == XPKTYPE_PACKED ){
- return TRUE;
- }else{
- glob->ioerr = 0L;
- return FALSE;
- }
- }
-
-
- /* This is the main entry to the automatic compression, and is the
- * function passed to TransFormFile().
- */
- BOOL PackFile2File(glb glob, struct FileHandle *srcxfh,
- struct FileHandle *dstxfh, void *dummy){
- LONG srcsize;
-
- srcsize = xGetFileSize(glob, srcxfh);
- if(srcsize == -1L){
- debug(("Error: PackFile2File(): Could not obtain file length.\n"));
- return FALSE;
- }
- return XpkPackFH2FH(glob, srcxfh, srcsize, dstxfh);
- }
-
-
- /* This function is passed to TransFormFile() to unpack a file to another
- * file (to handle Write() to an Xpk file).
- */
- BOOL UnPackFile2File(glb glob, struct FileHandle *srcxfh,
- struct FileHandle *dstxfh, void *dummy){
- LONG srcsize;
-
- srcsize = xGetFileSize(glob, srcxfh);
- if(srcsize == -1L){
- debug(("Error: UnPackFile2File(): Could not obtain file length.\n"));
- return FALSE;
- }
- return XpkUnPackFH2FH(glob, srcxfh, srcsize, dstxfh);
- }
-
-
- /*------------------------------------------------------------------------*
- * Virtual functions for Open(), Read(), Lock() etc.
- */
-
- LONG Xpk_Read( glb glob, struct XpkFH *fh, UBYTE *buf, LONG len ){
-
- if( fh->unpackedxpk->currentpos+len > fh->filelen )
- len = fh->filelen - fh->unpackedxpk->currentpos;
- if( len <= 0 ) return 0L;
-
- if(!readunpackedxpk(fh->unpackedxpk, buf, len )){
- return -1L;
- }
- return len;
- }
-
-
- LONG Xpk_Seek( glb glob, struct XpkFH *fh, LONG pos, LONG offset ){
- LONG abspos;
- LONG oldpos = fh->unpackedxpk->currentpos;
-
- if( offset != OFFSET_BEGINNING &&
- offset != OFFSET_CURRENT &&
- offset != OFFSET_END ){
- debug(("Error: Xpk: Bad offset value for Seek(): %ld\n",offset));
- glob->ioerr = ERROR_ACTION_NOT_KNOWN;
- return -1L;
- }
- abspos = abs_seek_pos( fh->unpackedxpk->currentpos, fh->filelen, pos, offset );
- if( abspos < 0 || abspos > fh->filelen ){
- debug(("Error: Xpk: Bad abs. pos. in Seek(): %ld\n",abspos));
- glob->ioerr = ERROR_SEEK_ERROR;
- return -1L;
- }
- debug(("XpkSeek(): fh=%lx, pos=%ld, offset=%ld, abspos=%ld\n",fh,pos,offset,abspos));
- seekunpackedxpk(fh->unpackedxpk,abspos);
-
- return oldpos;
- }
-
-
- BOOL Xpk_Close( glb glob, struct XpkFH *fh ){
- BOOL res;
-
- if(!fh->cfsfh.xfh){
- debug(("Xpk_Close(): Bad fh.\n"));
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return FALSE;
- }
- res = xClose( glob, fh->cfsfh.xfh );
- if( res ){
- killunpackedxpk(fh->unpackedxpk);
- XObjUnStuffFH(glob, &fh->cfsfh);
- dfree(fh);
- }else{
- debug(("ERROR: Xpk: xClose() returned false - mem not freed.\n"));
- }
- return res;
- }
-
-
- /* Xpk_Write() needs to do some magic to prepare the file for writing. The
- * idea is to replace the file (on disk) with the unpacked data, then make
- * the file handle look like a CFSFH.
- *
- * One possibility would be to write the data in memory. However, since
- * the file could have changed since this Open(), it's safer to
- * uncompress the file again.
- */
- LONG Xpk_Write(glb glob, struct XpkFH *fh, UBYTE *buf, LONG len){
- BOOL res;
- char *filename = fh->cfsfh.filename;
- struct FileLock *xlock = fh->cfsfh.parent->xlock;
- struct FileHandle *xfh = fh->cfsfh.xfh;
- LONG currentpos;
-
- if(!glob->allowappend){
- debug(("Xpk_Write(): Appendmode not set - failing.\n"));
- glob->ioerr = ERROR_ACTION_NOT_KNOWN;
- return -1L;
- }
- if(!xfh){
- debug(("XpkWrite(): Bad fh.\n"));
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return -1L;
- }
- if(!filename){
- debug(("Error: Xpk_Write(): no name info.\n"));
- glob->ioerr = ERROR_ACTION_NOT_KNOWN;
- return -1L;
- }
- debug(("Attempting to uncompress file %s.\n",filename));
- if(!xChangeMode(glob, CHANGE_FH, xfh, MODE_NEWFILE)){
- debug(("Error: Xpk_Write(): xChangeMode(): %ld.\n",glob->ioerr));
- return -1L;
- }
- if(-1L == xSeek(glob, xfh, 0L, OFFSET_BEGINNING)){
- debug(("Error: Xpk_Write(): Could not seek to start: %ld.\n",glob->ioerr));
- return -1L;
- }
- res = TransformXFH(glob, xfh, xlock, filename, UnPackFile2File, NULL);
- debug(("TransformFile() returned: %ld.\n",res));
- fh->cfsfh.xfh = xfh = NULL; /* The handle was closed by TransformFile(). */
- if(!res){
- SAVEIOERR;
- /* Bad luck! The uncompress didn't work. Since our xfh is gone, we'll
- * have to do some magic to save as much as possible.
- */
- if( !(xfh=xOpen(glob, xlock, filename, fh->cfsfh.mode)) ){
- debug(("Error: File %s could not be re-opened: %d.\n",filename,glob->ioerr));
- /* Nothing to do about it, really... */
- }
- RESTIOERR;
- return -1L;
- }
- if( !(xfh=xOpen(glob, xlock, filename, fh->cfsfh.mode)) ){
- debug(("Error: File %s could not be re-opened: %d.\n",filename,glob->ioerr));
- /* Nothing to do about it, really... */
- return -1L;
- }
- fh->cfsfh.xfh = xfh;
- currentpos = fh->unpackedxpk->currentpos;
- killunpackedxpk(fh->unpackedxpk);
- if(!glob->compressreadwrite) XObjUnStuffFH(glob, &fh->cfsfh);
- XObjStealXpkFH(glob, &fh->cfsfh);
- if(-1L == xSeek(glob, xfh, currentpos, OFFSET_BEGINNING)){
- debug(("Error: Xpk_Write(): Could not seek to right pos: %ld.\n",glob->ioerr));
- return -1L;
- }else{
- return XObjWrite(glob, &fh->cfsfh, buf, len);
- }
- }
-
-
- struct XpkLock *XpkMakeLock( glb glob, struct FileLock *xlock, LONG mode ){
- struct XpkLock *newlock;
-
- if( !dalloc(newlock) ){
- OUTOFMEM;
- return NULL;
- }
- newlock->cfslock.objtype = XPKOBJECT;
- newlock->cfslock.mode = mode;
- newlock->cfslock.xlock = xlock;
- newlock->cfslock.f = &Xpkfunc;
- newlock->cfslock.refcount = 0; /* NOTE: NOT used for XpkObject's. */
- return newlock;
- }
-
-
- struct XpkLock *XpkDupLock( glb glob, struct XpkLock *lock ){
- struct XpkLock *newlock;
-
- /* XPKOBJECT locks have their xLocks xDupLock'ed, and the rest of
- * the fields are just copied vanilla.
- */
- if( !dalloc(newlock) ){
- OUTOFMEM;
- return 0L;
- }
- *newlock = *lock;
- newlock->cfslock.refcount = 0L; /* Again: refcount is not used. */
- if( !(newlock->cfslock.xlock = xDupLock(glob, lock->cfslock.xlock)) ){
- dfree(newlock);
- return 0L;
- }
- return newlock;
- }
-
-
- /* NOTE BIEN: The parent lock is a XOBJECT, not a XPKOBJECT! */
- struct CFSLock *XpkParentDir( glb glob, struct XpkLock *lock ){
- struct FileLock *xlock;
- struct CFSLock *newlock;
-
- if( !(xlock = xParentDir(glob, lock->cfslock.xlock)) ){
- return 0L;
- }
- newlock = XObjMakeLock( glob, xlock, ACCESS_READ );
- if( !newlock ){
- LONG saveioerr = glob->ioerr;
- xUnLock(glob, xlock);
- glob->ioerr = saveioerr;
- }
- return newlock;
- }
-
-
- /* NOTE BIEN: The parent lock is a XOBJECT, not a XPKOBJECT! */
- struct CFSLock *XpkParentFH( glb glob, struct XpkFH *fh ){
-
- return XObjParentFH(glob, &fh->cfsfh);
- }
-
-
- BOOL XpkUnLock( glb glob, struct XpkLock *lock ){
- BOOL err;
-
- if(lock->cfslock.refcount){
- /* This should NOT have happened! */
- debug(("\n\n***PANIC***: XpkUnLock: Nonzero refcount in lock (%ld).\n",lock->cfslock.refcount));
- return DOSFALSE;
- }
- err = xUnLock(glob, lock->cfslock.xlock);
-
- /* Now, what if the UnLock fails? I guess it's best to return FALSE
- * and let the lock live.
- */
- if(!err) return DOSFALSE;
- dfree(lock);
- return DOSTRUE;
- }
-
-
- BOOL XpkSameLock(glb glob, struct XpkLock *l1, struct XpkLock *l2 ){
- return (BOOL) (xSameLock( glob, l1->cfslock.xlock, l2->cfslock.xlock ) == LOCK_SAME);
- }
-
- LONG ATUL ( char *Ptr ){
- UWORD Index;
- LONG LW;
-
- for (Index=0,LW=0L;Index<8;Index++)
- LW=(LW<<4)+(LONG)(*Ptr++-'A');
-
- return LW;
- }
-
- BOOL XpkFastModifyFIB( struct FileInfoBlock *FIB ){
-
- if( (strncmp( FIB->fib_Comment, XFH_ID, 5 ) != 0) ||
- (strlen( FIB->fib_Comment ) != 50) ) return FALSE;
- debug(("XpkFastModifyFIB: header found: %s\n",FIB->fib_Comment));
-
- FIB->fib_Comment[0] = '\0';
- if ( (ATUL( &FIB->fib_Comment[6] ) == FIB->fib_Date.ds_Days) &&
- (ATUL( &FIB->fib_Comment[15] ) == FIB->fib_Date.ds_Minute) &&
- (ATUL( &FIB->fib_Comment[24] ) == FIB->fib_Date.ds_Tick) &&
- (ATUL( &FIB->fib_Comment[33] ) == FIB->fib_Size) ){
- FIB->fib_Size = ATUL( &FIB->fib_Comment[42] );
- debug(("XpkFastModifyFIB: header valid, size: %ld\n",FIB->fib_Size));
- return TRUE;
- }
-
- return FALSE;
- }
-
- BOOL XpkObjExamine( glb glob, struct XpkLock *lock, struct FileInfoBlock *fib ){
- BOOL err;
- struct FileHandle *xfh;
-
- debug(("XpkObjExamine(): "));
- err = xExamine(glob, lock->cfslock.xlock, fib);
- debug(("%ld,'%s'\n",err,fib->fib_FileName));
- if( !err ) return err;
-
- if( XpkFastModifyFIB( fib ) ) return DOSTRUE;
-
- xfh = xOpenFromCopyOfLock( glob, lock->cfslock.xlock );
- if( !xfh ){
- debug(("Error: XpkExamine(): Cannot open file from lock %lx.\n",lock));
- return DOSFALSE;
- }
- err = XpkModifyFIB( glob, lock, fib, xfh );
- if( !err ){
- LONG saveioerr;
-
- saveioerr = glob->ioerr;
- xClose( glob, xfh );
- glob->ioerr = saveioerr;
- return DOSFALSE;
- }else{
- xClose( glob, xfh );
- return DOSTRUE;
- }
- }
-
-
- /* XpkModifyFIB() has to fix the length of the file. */
- BOOL XpkModifyFIB( glb glob, struct XpkLock *lock,struct FileInfoBlock *fib, struct FileHandle *xfh ){
- struct XpkFib xpkfib;
-
- if( !XpkExamine_FH(glob, xfh, &xpkfib) ){
- debug(("Error: IsXpkFile: XpkExamine_FH returned error\n"));
- return FALSE;
- }
- fib->fib_Size = xpkfib.ULen;
- /* ToDo: Should NOT have fixed block size (look at UFS). */
- fib->fib_NumBlocks = (fib->fib_Size+BLOCKSIZE-1) / BLOCKSIZE;
-
- return DOSTRUE;
- }
-
-
- /*------------------------------------------------------------------------*
- * Initialise and cleanup functions.
- */
-
- BOOL InitXpk( glb glob ){
-
- if(!(glob->XpkBase = OpenLibrary("xpkmaster.library",0L)))
- return FALSE;
- XpkBase = glob->XpkBase;
- if( ((struct Library *)glob->DOSBase)->lib_Version >= 36){
- glob->xpkport = NULL;
- }else{
- if(!(glob->xpkport=CreatePort("CFS port for KS1.3 Xpk-calls.",0L))){
- CloseLibrary(glob->XpkBase);
- debug(("Error creating xpk message port.\n"));
- return FALSE;
- }
- }
-
- return TRUE;
- }
-
-
- void CleanupXpk( glb glob ){
-
- if( glob->xpkport ) DeletePort( glob->xpkport );
- if( glob->XpkBase ) CloseLibrary( XpkBase );
- }
-
-
- /* End of xpk.c */
-