<< Previous Message Main Index Next Message >>
<< Previous Message in Thread This Month Next Message in Thread >>
Date   : Wed, 27 Nov 1991 02:54:06 GMT
From   : cis.ohio-state.edu!zaphod.mps.ohio-state.edu!think.com!spool.mu.edu!munnari.oz.au!newsroom.utas.edu.au!bruny.cc.utas.edu.au!u895217@ucbvax.Berkeley.EDU (Scott Marshall)
Subject: Re: LBR files on MS-DOS

arj@cam-orl.co.uk (Andy Jackson) writes:

>arj@cam-orl.co.uk (Andy Jackson) writes:
>: Sorry if this is the wrong place to ask.....
>: 
>: I have recently aquired some files (archives ?) in .LBR format. Is there
>: any way that I can get at the contents on a PC.
>:
>Sorry about the waste of bandwidth...

>   I found a copy of delbr11.exe on wuarchive.wustl.edu. This
>extracted the files, but now I have a what appear to be a number of
>compressed files. They have all had the middle letter of the extension
>converted to a Z. i.e.

>           AAAAAAA.ASM => AAAAAAA.AZM

>What do I need to extract these now ???.

A program to do this is following:



/*----------------------------------------------------------------------------*/
/*  UNCRunch/C - LZW uncruncher compatible with Z-80 CP/M program CRUNCH
2.3  */
/*                     (C) Copyright 1986 - Frank Prindle                    */
/*                 May be reproduced for non-profit use only                 */
/*----------------------------------------------------------------------------*/
/* This program is largely based on the previous works of Steven Greenberg,
  */
/* Joe Orost, James Woods, Ken Turkowski, Steve Davies, Jim McKie, Spencer
   */
/* Thomas, Terry Welch, and (of course) Lempel and Ziv.                              */
/*----------------------------------------------------------------------------*/
/*  Portability related assumptions:                                         */
/*    1. fopen called with "rb" or "wb" is sufficient to make getc/putc
xfer  */
/*       bytes in binary, without newline or control-z translation (this
is   */
/*       default for UNIX anyway, and the "b" has no effect).         
       */
/*    2. size of type "long" is at least 4 bytes (for getbuf to work).
       */
/*----------------------------------------------------------------------------*/
#define VERSION "2.31D"
#define DATE "11 June 1987"

/*#define DUMBLINKER*/ /*define this if linker makes a huge executable image*/
                       /*containing mostly zeros (big tables will instead be*/
                       /*allocated at run time)*/

#define XLAT_FN_CHARS  {'/','%'} /*FOR UNIX*/
                       /*define comma separated pairs of {undesirable char,*/
                       /*replacement char} for filenames - no need to include*/
                       /*control characters, as these are automatically*/
                       /*translated to question marks (?)*/
/*----------------------------------------------------------------------------*/

#include "stdio.h"

/*Macro definition - ensure letter is lower case*/
#define tolower(c) (((c)>='A' && (c)<='Z')?(c)-('A'-'a'):(c))

/*Macro definition - is character a control (non-printing) character?*/
#define iscntrl(c) (c<' ' || c=='\177')

#define TABLE_SIZE  4096       /*size of main lzw table for 12 bit codes*/
#define XLATBL_SIZE 5003       /*size of physical translation table*/

/*special values for predecessor in table*/
#define NOPRED 0x6fff          /*no predecessor in table*/
#define EMPTY  0x8000          /*empty table entry (xlatbl only)*/
#define REFERENCED 0x2000      /*table entry referenced if this bit set*/
#define IMPRED 0x7fff          /*impossible predecessor*/

#define EOFCOD 0x100           /*special code for end-of-file*/
#define RSTCOD 0x101           /*special code for adaptive reset*/
#define NULCOD 0x102           /*special filler code*/
#define SPRCOD 0x103           /*spare special code*/

#define REPEAT_CHARACTER 0x90  /*following byte is repeat count*/

#ifdef DUMBLINKER

  /*main lzw table and it's structure*/
  struct entry {
       short predecessor;      /*index to previous entry, if any*/
       char suffix;            /*character suffixed to previous entries*/
  } *table;

  /*auxilliary physical translation table*/
  /*translates hash to main table index*/
  short *xlatbl;

  /*byte string stack used by decode*/
  char *stack;

#else

  struct entry {
       short predecessor;      /*index to previous entry, if any*/
       char suffix;            /*character suffixed to previous entries*/
  } table[TABLE_SIZE];

  /*auxilliary physical translation table*/
  /*translates hash to main table index*/
  short xlatbl[XLATBL_SIZE];

  /*byte string stack used by decode*/
  char stack[TABLE_SIZE];

#endif

/*other global variables*/
char   codlen;                 /*variable code length in bits (9-12)*/
short  trgmsk;                 /*mask for codes of current length*/
char   fulflg;                 /*full flag - set once main table is full*/
short  entry;                  /*next available main table entry*/
long   getbuf;                 /*buffer used by getcode*/
short  getbit;                 /*residual bit counter used by getcode*/
char   entflg;                 /*inhibit main loop from entering this code*/
char   repeat_flag;            /*so send can remember if repeat required*/
int    finchar;                /*first character of last substring output*/
int    lastpr;                 /*last predecessor (in main loop)*/
short  cksum;                  /*checksum of all bytes written to output file*/

FILE   *infd;                  /*currently open input file*/
FILE   *outfd;                 /*currently open output file*/

main(argc,argv)
int argc;
char *argv[];
       {
       /*usage check*/
       if (argc-- < 2)
               {
               printf("Usage : uncr <crunched_file_name> ...\n");
               exit(0);
               }

       /*who am i*/
       printf("UNCRunch/C Version %s (%s)\n\n",VERSION,DATE);

#ifdef DUMBLINKER
       /*allocate storage now for the big tables (keeps load short)*/
       table=(struct entry *)malloc(TABLE_SIZE*sizeof(struct entry));
       xlatbl=(short *)malloc(XLATBL_SIZE*sizeof(short));
       stack=(char *)malloc(TABLE_SIZE*sizeof(char));
       if(table==NULL || xlatbl==NULL || stack==NULL)
               {
               printf("***** not enough memory to run this program!\n");
               exit(0);
               }
#endif

       /*do all the files specified*/
       while(argc--) uncrunch(*++argv);

       /*all done all files*/
       exit(0);
       }


/*uncrunch a single file*/
uncrunch(filename)
char *filename;
       {
       int c;                  
       char *p;
       char *index();
       char outfn[80];                 /*space to build output file name*/
       int pred;                       /*current predecessor (in main loop)*/
       char reflevel;                  /*ref rev level from input file*/
       char siglevel;                  /*sig rev level from input file*/
       char errdetect;                 /*error detection flag from input file*/
       short file_cksum;               /*checksum read from input file*/

       /*filename character translation array*/
       static int xlat_fn_chars[][2] = {XLAT_FN_CHARS, {-1,-1}};

       /*initialize variables for uncrunching a file*/
       intram();

       /*open input file*/
       if ( 0 == (infd = fopen(filename,"rb")) )
               {
               printf("***** can't open %s\n", filename);
               return;
               }

       /*verify this is a crunched file*/
       if (getc(infd) != 0x76 || getc(infd) != 0xfe)
               {
               printf("***** %s is not a crunched file\n",filename);
               fclose(infd);
               return;
               }

       /*extract and build output file name*/
       printf("%s --> ",filename);
       for(p=outfn; (*p=getc(infd))!='\0'; p++)
               {
               int *q;

               /*translate to lower case and strip high order bit*/
               *p=tolower((*p)&0x7f);

               /*make any control character into a question mark*/
               if(iscntrl(*p)) *p = '?';

               /*translate undesirable characters in file name*/
               for(q = &xlat_fn_chars[0][0]; *q!=(-1); q+=2)
                       {
                       if(*p == *q)
                               {
                               *p = *(q+1);
                               break;
                               }
                       }
               }
       printf("%s\n",outfn);
       *(index(outfn,'.')+4)='\0';     /*truncate non-name portion*/
       if(p=index(outfn,' ')) *p='\0'; /*truncate trailing blanks*/

       /*read the four info bytes*/
       reflevel=getc(infd);
       siglevel=getc(infd);
       errdetect=getc(infd);
       getc(infd); /*skip spare*/

       /*make sure we can uncrunch this format file*/
       /*note: this program does not support CRUNCH 1.x format*/
       if(siglevel < 0x20 || siglevel > 0x2f)
               {
               printf("***** this version of UNCR cannot process %s!\n",
                       filename);
               fclose(infd);
               return;
               }

       /*open output file*/
       if ( 0 == (outfd =fopen( outfn,"wb")) )
               {
               printf("***** can't create %s\n",outfn);
               fclose(infd);
               return;
               }

       /*set up atomic code definitions*/
       initb2();

       /*main decoding loop*/
       pred=NOPRED;
       for(;;)
               {
               /*remember last predecessor*/
               lastpr=pred;

               /*read and process one code*/
               if((pred=getcode())==EOFCOD) /*end-of-file code*/
                       {
                       break; /*all lzw codes read*/
                       }

               else if(pred==RSTCOD) /*reset code*/
                       {
                       entry=0;
                       fulflg=0;
                       codlen=9;
                       trgmsk=0x1ff;
                       pred=NOPRED;
                       entflg=1;
                       initb2();
                       }

               else /*a normal code (nulls already deleted)*/
                       {
                       /*check for table full*/
                       if(fulflg!=2)
                               {
                               /*strategy if table not full*/
                               if(decode(pred)==0)enterx(lastpr,finchar);
                               else entflg=0;
                               }
                       else
                               {
                               /*strategy if table is full*/
                               decode(pred);
                               entfil(lastpr,finchar); /*attempt to reassign*/
                               }
                       }
               }

       /*verify checksum if required*/
       if(errdetect==0)
               {
               file_cksum=getc(infd);
               file_cksum|=getc(infd)<<8;
               if((file_cksum&0xffff)!=(cksum&0xffff))
                       {
                       printf("***** checksum error detected in ");
                       printf("%s!\n",filename);
                       }
               }

       /*close files*/
       fclose(infd);
       fclose(outfd);

       /*all done this file*/
       return;
       }


/*initialize the lzw and physical translation tables*/
initb2()
       {
       register int i;
       register struct entry *p;
       p=table;

       /*first mark all entries of xlatbl as empty*/
       for(i=0;i<XLATBL_SIZE;i++) xlatbl[i]=EMPTY;

       /*enter atomic and reserved codes into lzw table*/
       for(i=0;i<0x100;i++) enterx(NOPRED,i);       /*first 256 atomic codes*/
       for(i=0;i<4;i++) enterx(IMPRED,0);   /*reserved codes*/
       }


/*enter the next code into the lzw table*/
enterx(pred,suff)
int pred;              /*table index of predecessor*/
int suff;              /*suffix byte represented by this entry*/
       {
       register struct entry *ep;
       ep = &table[entry];

       /*update xlatbl to point to this entry*/
       figure(pred,suff);

       /*make the new entry*/
       ep->predecessor = (short)pred;
       ep->suffix = (char)suff;
       entry++;

       /*if only one entry of the current code length remains, update to*/
       /*next code length because main loop is reading one code ahead*/
       if(entry >= trgmsk)
               {
               if(codlen<12)
                       {
                       /*table not full, just make length one more bit*/
                       codlen++;
                       trgmsk=(trgmsk<<1)|1;
                       }
               else
                       {
                       /*table almost full (fulflg==0) or full (fulflg==1)*/
                       /*just increment fulflg - when it gets to 2 we will*/
                       /*never be called again*/
                       fulflg++;
                       }
               }
       }


/*find an empty entry in xlatbl which hashes from this predecessor/suffix*/
/*combo, and store the index of the next available lzw table entry in it*/
figure(pred,suff)
int pred;
int suff;
       {
       short *hash();
       auto int disp;
       register short *p;
       p=hash(pred,suff,&disp);

       /*follow secondary hash chain as necessary to find an empty slot*/
       while(((*p)&0xffff) != EMPTY)
               {
               p+=disp;
               if(p<xlatbl)p+=XLATBL_SIZE;
               }

       /*stuff next available index into this slot*/
       *p=entry;
       }


/*hash pred/suff into xlatbl pointer*/
/*duplicates the hash algorithm used by CRUNCH 2.3*/
short *hash(pred,suff,disploc)
int pred;
int suff;
int *disploc;
       {
       register int hashval;
       
       hashval=(((pred>>4)^suff) | ((pred&0xf)<<8)) + 1;
       *disploc=hashval-XLATBL_SIZE;
       return (xlatbl + hashval);
       }
       

/*initialize variables for each file to be uncrunched*/
intram()
       {
       trgmsk=0x1ff;   /*nine bits*/
       codlen=9;       /*    "    */
       fulflg=0;       /*table empty*/
       entry=0;        /*    "      */
       getbit=0;       /*buffer emtpy*/
       entflg=1;       /*first code always atomic*/
       repeat_flag=0;  /*repeat not active*/
       cksum=0;        /*zero checsum*/
       }


/*return a code of length "codlen" bits from the input file bit-stream*/
getcode()
       {
       register int hole;
       int code;

       /*always get at least a byte*/
       getbuf=(getbuf<<codlen)|(((long)getc(infd))<<(hole=codlen-getbit));
       getbit=8-hole;

       /*if is not enough to supply codlen bits, get another byte*/
       if(getbit<0)
               {
               getbuf |= ((long)getc(infd))<<(hole-8);
               getbit+=8;
               }

       if(feof(infd))
               {
               printf("***** Unexpected EOF on input file!\n");
               return EOFCOD;
               }

       /*skip spare or null codes*/
       if((code=((getbuf>>8) & trgmsk)) == NULCOD || code == SPRCOD)
               {
               return getcode();       /*skip this code, get next*/
               }

       return code;
       }


/*decode this code*/
decode(code)
short code;
       {
       register char *stackp;          /*byte string stack pointer*/
       register struct entry *ep;
       ep = &table[code];

       if(code>=entry)
               {
               /*the ugly exception, "WsWsW"*/
               entflg=1;
               enterx(lastpr,finchar);
               }

       /*mark corresponding table entry as referenced*/
       ep->predecessor |= REFERENCED;

       /*walk back the lzw table starting with this code*/
       stackp=stack;
       while(ep > &table[255]) /*i.e. code not atomic*/
               {
               *stackp++ = ep->suffix;
               ep = &table[(ep->predecessor)&0xfff];
               }

       /*then emit all bytes corresponding to this code in forward order*/
       send(finchar=(ep->suffix)&0xff); /*first byte*/

       while(stackp > stack)                 /*the rest*/
               {
               send((*--stackp)&0xff);
               }

       return(entflg);
       }


/*write a byte to output file*/
/*repeat byte (0x90) expanded here*/
/*checksumming of output stream done here*/
send(c)
register int c;
       {
       static int savec;       /*previous byte put to output*/

       /*repeat flag may have been set by previous call*/
       if(repeat_flag)
               {

               /*repeat flag was set - emit (c-1) copies of savec*/
               /*or (if c is zero), emit the repeat byte itself*/
               repeat_flag=0;
               if(c)
                       {
                       cksum+=(savec)*(c-1);
                       while(--c) putc(savec,outfd);
                       }
               else
                       {
                       putc(REPEAT_CHARACTER,outfd);
                       cksum+=REPEAT_CHARACTER;
                       }
               }
       else
               {
               /*normal case - emit c or set repeat flag*/
               if(c==REPEAT_CHARACTER)
                       {
                       repeat_flag++;
                       }
               else
                       {
                       putc(savec=c,outfd);
                       cksum+=(c&0xff);
                       }
               }
       }


/*attempt to reassign an existing code which has*/
/*been defined, but never referenced*/
entfil(pred,suff)
int pred;              /*table index of predecessor*/
int suff;              /*suffix byte represented by this entry*/
       {
       auto int disp;
       register struct entry *ep;
       short *hash();
       short *p;
       p=hash(pred,suff,&disp);

       /*search the candidate codes (all those which hash from this new*/
       /*predecessor and suffix) for an unreferenced one*/
       while(*p!=(short)EMPTY)
               {

               /*candidate code*/
               ep = &table[*p];
               if(((ep->predecessor)&REFERENCED)==0)
                       {
                       /*entry reassignable, so do it!*/
                       ep->predecessor=pred;
                       ep->suffix=suff;

                       /*discontinue search*/
                       break;
                       }

               /*candidate unsuitable - follow secondary hash chain*/
               /*and keep searching*/
               p+=disp;
               if(p<xlatbl)p+=XLATBL_SIZE;
               }
       }

/*end of source file*/

<< Previous Message Main Index Next Message >>
<< Previous Message in Thread This Month Next Message in Thread >>