commit 7a619571ed1a12ec43fa28372a67b561febada36
parent 6e6395f0eb761e375826676c1abd74ebae1ea185
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Wed, 30 Nov 2022 18:25:39 -0500
ar/puff: stream to StdOut
Diffstat:
M | fs/ar/puff.c | | | 64 | ++++++++++++++++++++++++++++++++-------------------------------- |
1 file changed, 32 insertions(+), 32 deletions(-)
diff --git a/fs/ar/puff.c b/fs/ar/puff.c
@@ -41,13 +41,19 @@
#define FIXLCODES 288
#define OUTBUFLEN $10000
+/* Output and buffering
+ * The puff algorithm needs to access its previously outputted contents up to
+ * 32K back. For this reason, we can't spit directly to StdOut. Instead, what we
+ * do is we have a buffer of twice the required size (64K) and spit there. This
+ * buffer is split in 2 pages. Whenever we hit the limit of one of the pages, we
+ * check if the other page is full. If yes, we spit it to StdOut and go on.
+*/
+
/* input and output state */
struct state {
- /* output state */
unsigned char out[OUTBUFLEN]; /* output buffer */
- unsigned int outcnt; /* bytes written to out so far */
-
- /* input state */
+ unsigned int outptr; /* current position in output buffer */
+ unsigned int outcnt; /* total bytes written to out so far */
unsigned char *in; /* input buffer */
unsigned int inlen; /* available input at in */
unsigned int incnt; /* bytes read so far */
@@ -57,6 +63,17 @@ struct state {
static state s;
+static void spit(unsigned char c) {
+ unsigned int pageptr;
+ s.out[s.outptr++] = c;
+ s.outcnt++;
+ if ((s.outcnt>=OUTBUFLEN) && (!(s.outptr % (OUTBUFLEN/2)))) {
+ // we finished a page and need to flush the "other"
+ pageptr = s.outptr ^ (OUTBUFLEN/2); // ptr to "other"
+ fwrite(&s.out[pageptr], OUTBUFLEN/2, StdOut());
+ }
+}
+
/*
* Return need bits from the input stream. This always leaves less than
* eight bits in the buffer. bits() works properly for need == 0.
@@ -128,16 +145,8 @@ static int stored()
/* copy len bytes from in to out */
if (s.incnt + len > s.inlen)
return 2; /* not enough input */
- if (s.out != NULL) {
- if (s.outcnt + len > OUTBUFLEN)
- return 1; /* not enough output space */
- while (len--)
- s.out[s.outcnt++] = s.in[s.incnt++];
- }
- else { /* just scanning */
- s.outcnt += len;
- s.incnt += len;
- }
+ while (len--)
+ spit(s.in[s.incnt++]);
/* done with a valid stored block */
return 0;
@@ -355,12 +364,7 @@ static int codes(huffman *lencode, huffman *distcode)
return symbol; /* invalid symbol */
if (symbol < 256) { /* literal: symbol is the byte */
/* write out the literal */
- if (s.out != NULL) {
- if (s.outcnt == OUTBUFLEN)
- return 1;
- s.out[s.outcnt] = symbol;
- }
- s.outcnt++;
+ spit(symbol);
}
else if (symbol > 256) { /* length */
/* get and compute length */
@@ -378,17 +382,9 @@ static int codes(huffman *lencode, huffman *distcode)
return -11; /* distance too far back */
/* copy length bytes from distance bytes back */
- if (s.out != NULL) {
- if (s.outcnt + len > OUTBUFLEN)
- return 1;
- while (len--) {
- s.out[s.outcnt] = dist > s.outcnt ?
- 0 : s.out[s.outcnt - dist];
- s.outcnt++;
- }
+ while (len--) {
+ spit(dist > s.outcnt ? 0 : s.out[(s.outcnt - dist) % OUTBUFLEN]);
}
- else
- s.outcnt += len;
}
} while (symbol != 256); /* end of block symbol */
@@ -681,7 +677,9 @@ int puff(unsigned char *source, unsigned int sourcelen)
{
int last, type; /* block information */
int err; /* return value */
+ unsigned int pageptr;
+ s.outptr = 0;
s.outcnt = 0;
s.in = source;
s.inlen = sourcelen;
@@ -701,9 +699,11 @@ int puff(unsigned char *source, unsigned int sourcelen)
break; /* return with error */
} while (!last);
- /* update the lengths and return */
if (err <= 0) {
- fwrite(s.out, s.outcnt, StdOut());
+ pageptr = s.outptr & (OUTBUFLEN/2);
+ if (s.outptr-pageptr) {
+ fwrite(&s.out[pageptr], s.outptr-pageptr, StdOut());
+ }
}
return err;
}