home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <ctype.h>
- #include <limits.h>
- #include <mem.h>
- #define INTERNAL
- #include "sqread.h"
-
- #define ERROR (-1)
- #define PATHLEN 312 /* Number of characters allowed in pathname */
- #define OK 0
-
- #define RECOGNIZE 0xFF76 /* unlikely pattern */
- #define DLE 0x90 /* repeat byte flag */
- #define SPEOF 256 /* special endfile token */
- #define NUMVALS 257 /* 256 data values plus SPEOF*/
-
- static int getuhuff(SQFILE *sqp);
- static int portgetw(FILE *f);
-
- /* BUG: you cannot select an arbitrary position in the output stream
- * to start your output (unless you make provisions for that). This is
- * because of the repeat compression. You can make provision for seeking
- * to the middle of a repeat sequence by terminating the repeat when
- * compressing the file.
- */
-
- SQFILE *
- sqopen (const char *path)
- {
- FILE *fp;
- SQFILE *sqp;
- int numnodes;
- int i;
-
- fp = fopen(path, "rb");
- if (!fp)
- return NULL;
- sqp = malloc(sizeof(SQFILE));
- if (!sqp)
- return NULL;
- sqp->file = fp;
- if(portgetw(fp) != (int) RECOGNIZE) {/* Process header */
- rewind(sqp->file);
- sqp->issq = 0;
- return sqp;
- }
- sqp->issq = 1;
- (void) portgetw(fp); /* checksum */
- while (getc(fp)) /* Read and discard the name */
- ;
-
- numnodes = portgetw(fp);
- if(numnodes < 0 || numnodes >= NUMVALS) {
- /* invalid decode tree */
- fclose(fp);
- return NULL;
- }
- /* Initialize for possible empty tree (SPEOF only) */
- sqp->sqleaf[0].children[0] = -(SPEOF + 1);
- sqp->sqleaf[0].children[1] = -(SPEOF + 1);
-
- for(i = 0; i < numnodes; ++i) { /* Get decoding tree from file */
- sqp->sqleaf[i].children[0] = portgetw(fp);
- sqp->sqleaf[i].children[1] = portgetw(fp);
- }
- sqp->rewpos = ftell(sqp->file);
- sqp->bpos = 7; /* force initial read */
- sqp->repct = 0; /* start with no repeats */
- return sqp;
- }
-
- void
- sqrewind(SQFILE *sqp)
- {
- sqp->bpos = 7; /* force initial read */
- sqp->repct = 0; /* start with no repeats */
- fseek(sqp->file, sqp->rewpos, SEEK_SET);
- }
-
-
- /* The "offset" is actually a bit offset within the file. Offset 0 is
- * bit 0, byte 0. Offset 8 is bit 0, byte 1. Etc...
- */
- long
- sqseek(SQFILE *sqp, long offset)
- {
- int bpos;
- long value;
-
- if (!sqp->issq)
- return fseek(sqp->file, offset, SEEK_SET);
-
- bpos = offset & 7;
- value = fseek(sqp->file, offset >> 3, SEEK_SET);
- if (bpos == 0) {
- sqp->bpos = 7;
- } else {
- sqp->bpos = bpos - 1;
- sqp->curin = getc(sqp->file) >> (bpos - 1);
- }
- sqp->repct = 0; /* start with no repeats */
- return value;
- }
-
-
- /* Get bytes with decoding - this decodes repetition,
- * calls getuhuff to decode file stream into byte
- * level code with only repetition encoding.
- *
- * The code is simple passing through of bytes except
- * that DLE is encoded as DLE-zero and other values
- * repeated more than twice are encoded as value-DLE-count.
- */
-
- int
- sqgetc(SQFILE *sqp)
- {
- int c;
-
- if (!sqp->issq)
- return getc(sqp->file);
-
- if(sqp->repct > 0) {
- /* Expanding a repeated char */
- --sqp->repct;
- return(sqp->value);
- } else {
- /* Nothing unusual */
- if((c = getuhuff(sqp)) != DLE) {
- /* It's not the special delimiter */
- sqp->value = c;
- if(sqp->value == EOF)
- sqp->repct = INT_MAX;
- return(sqp->value);
- } else {
- /* Special token */
- if((sqp->repct = getuhuff(sqp)) == 0)
- /* DLE, zero represents DLE */
- return(DLE);
- else {
- /* Begin expanding repetition */
- sqp->repct -= 2; /* 2nd time */
- return(sqp->value);
- }
- }
- }
- }
-
-
- /* Decode file stream into a byte level code with only
- * repetition encoding remaining.
- */
- static int
- getuhuff(SQFILE *sqp)
- {
- int i;
-
- /* Follow bit stream in tree to a leaf*/
- i = 0; /* Start at root of tree */
- do {
- if(++sqp->bpos > 7) {
- if((sqp->curin = getc(sqp->file)) == EOF)
- return(ERROR);
- sqp->bpos = 0;
- /* move a level deeper in tree */
- i = sqp->sqleaf[i].children[1 & sqp->curin];
- } else
- i = sqp->sqleaf[i].children[1 & (sqp->curin >>= 1)];
- } while(i >= 0);
-
- /* Decode fake node index to original data value */
- i = -(i + 1);
- /* Decode special endfile token to normal EOF */
- return(i == SPEOF) ? EOF : i;
- }
-
-
- char
- *sqgets (char *s, int n, SQFILE *sqp)
- {
- int c = '\0';
-
- while (c != '\n' && n > 1) {
- if ((c = sqgetc(sqp)) == EOF)
- return NULL;
- if (c == '\r')
- continue;
- *s++ = c;
- --n;
- }
- *s = '\0';
- return s;
- }
-
-
- long
- sqtell (SQFILE *sqp)
- {
- if (!sqp->issq)
- return ftell(sqp->file);
- return (ftell(sqp->file) << 3) + sqp->bpos;
- }
-
-
- long
- sqsize (SQFILE *sqp)
- {
- fseek(sqp->file, 0, SEEK_END);
- if (!sqp->issq)
- return ftell(sqp->file);
- return (ftell(sqp->file) << 3) + 7;
- }
-
-
- int
- sqclose (SQFILE *sqp)
- {
- int value = fclose(sqp->file);
- free(sqp);
- return value;
- }
-
-
- /*
- * Machine independent getw which always gets bytes in the same order
- * as the CP/M version of SQ wrote them
- */
- static int
- portgetw(f)
- FILE *f;
- {
- int c;
-
- c = getc(f) & 0377;
- return(c | (getc(f) << 8));
- }
-