Unified · Split
| @@ -0,0 +1,121 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include "pdf.h" | ||
| 5 | |||
| 6 | static int | ||
| 7 | bufgrow(Buffer *b, int sz) | ||
| 8 | { | ||
| 9 | uchar *r; | ||
| 10 | int maxsz; | ||
| 11 | |||
| 12 | if(b->maxsz < 1){ | ||
| 13 | if((b->b = mallocz(128, 1)) == nil) | ||
| 14 | return -1; | ||
| 15 | b->maxsz = 128; | ||
| 16 | } | ||
| 17 | for(maxsz = b->maxsz; b->sz+sz > maxsz; maxsz *= 2); | ||
| 18 | if(maxsz != b->maxsz){ | ||
| 19 | if((r = realloc(b->b, maxsz)) == nil) | ||
| 20 | return -1; | ||
| 21 | memset(r+b->maxsz, 0, maxsz-b->maxsz); | ||
| 22 | b->b = r; | ||
| 23 | b->maxsz = maxsz; | ||
| 24 | } | ||
| 25 | |||
| 26 | return 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | void | ||
| 30 | bufinit(Buffer *b, uchar *d, int sz) | ||
| 31 | { | ||
| 32 | memset(b, 0, sizeof(*b)); | ||
| 33 | if(d != nil){ | ||
| 34 | b->b = d; | ||
| 35 | b->sz = sz; | ||
| 36 | b->ro = 1; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | void | ||
| 41 | buffree(Buffer *b) | ||
| 42 | { | ||
| 43 | if(b->ro == 0) | ||
| 44 | free(b->b); | ||
| 45 | } | ||
| 46 | |||
| 47 | int | ||
| 48 | bufeof(Buffer *b) | ||
| 49 | { | ||
| 50 | return b->off == b->sz; | ||
| 51 | } | ||
| 52 | |||
| 53 | uchar * | ||
| 54 | bufdata(Buffer *b, int *sz) | ||
| 55 | { | ||
| 56 | *sz = b->sz; | ||
| 57 | return b->b; | ||
| 58 | } | ||
| 59 | |||
| 60 | int | ||
| 61 | bufreadn(Buffer *b, void *bio, int sz) | ||
| 62 | { | ||
| 63 | int n, end; | ||
| 64 | |||
| 65 | if(bufgrow(b, sz) != 0) | ||
| 66 | return -1; | ||
| 67 | for(end = b->sz+sz; b->sz < end; b->sz += n){ | ||
| 68 | if((n = Bread(bio, b->b+b->sz, sz)) < 1) | ||
| 69 | return -1; | ||
| 70 | sz -= n; | ||
| 71 | } | ||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | int | ||
| 76 | bufput(Buffer *b, uchar *d, int sz) | ||
| 77 | { | ||
| 78 | if(b->ro) | ||
| 79 | sysfatal("bufferput on readonly buffer"); | ||
| 80 | if(bufgrow(b, sz) != 0) | ||
| 81 | return -1; | ||
| 82 | |||
| 83 | memmove(b->b+b->sz, d, sz); | ||
| 84 | b->sz += sz; | ||
| 85 | |||
| 86 | return sz; | ||
| 87 | } | ||
| 88 | |||
| 89 | int | ||
| 90 | bufget(Buffer *b, uchar *d, int sz) | ||
| 91 | { | ||
| 92 | if(sz == 0) | ||
| 93 | return 0; | ||
| 94 | |||
| 95 | if(b->off > b->sz) | ||
| 96 | sysfatal("buffer: off(%d) > sz(%d)", b->off, b->sz); | ||
| 97 | if(sz > b->sz - b->off) | ||
| 98 | sz = b->sz - b->off; | ||
| 99 | memmove(d, b->b+b->off, sz); | ||
| 100 | b->off += sz; | ||
| 101 | b->eof = sz == 0; | ||
| 102 | |||
| 103 | return sz; | ||
| 104 | } | ||
| 105 | |||
| 106 | void | ||
| 107 | bufdump(Buffer *b) | ||
| 108 | { | ||
| 109 | Biobuf bio; | ||
| 110 | int i, j; | ||
| 111 | |||
| 112 | Binit(&bio, 2, OWRITE); | ||
| 113 | Bprint(&bio, "%d bytes:\n", b->sz); | ||
| 114 | for(i = 0; i < b->sz;){ | ||
| 115 | Bprint(&bio, "%04x\t", i); | ||
| 116 | for(j = 0; i < b->sz && j < 16; j++, i++) | ||
| 117 | Bprint(&bio, "%02x%s", b->b[i], (j+1)&7 ? " " : " "); | ||
| 118 | Bprint(&bio, "\n"); | ||
| 119 | } | ||
| 120 | Bterm(&bio); | ||
| 121 | } | ||
| @@ -69,7 +69,7 @@ pdfdictget(Object *o, char *name) · 68 unmodified lines | |||
| 69 | { | 69 | { |
| 70 | int i; | 70 | int i; |
| 71 | 71 | ||
| 72 | if(o == nil || o->type != Odict || name == nil) | 72 | if(o == nil || (o->type != Ostream && o->type != Odict) || name == nil) |
| 73 | return nil; | 73 | return nil; |
| 74 | for(i = 0; i < o->dict.nkv && strcmp(name, o->dict.kv[i].key) != 0; i++); | 74 | for(i = 0; i < o->dict.nkv && strcmp(name, o->dict.kv[i].key) != 0; i++); |
| 75 | 75 | ||
| @@ -0,0 +1,38 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <flate.h> | ||
| 5 | #include "pdf.h" | ||
| 6 | |||
| 7 | static int | ||
| 8 | bw(void *aux, void *d, int n) | ||
| 9 | { | ||
| 10 | return bufput(aux, d, n); | ||
| 11 | } | ||
| 12 | |||
| 13 | static int | ||
| 14 | bget(void *aux) | ||
| 15 | { | ||
| 16 | uchar c; | ||
| 17 | |||
| 18 | return bufget(aux, &c, 1) == 1 ? c : -1; | ||
| 19 | } | ||
| 20 | |||
| 21 | int | ||
| 22 | fFlate(void *aux, Buffer *bi, Buffer *bo) | ||
| 23 | { | ||
| 24 | int r; | ||
| 25 | |||
| 26 | USED(aux); | ||
| 27 | |||
| 28 | do{ | ||
| 29 | r = inflatezlib(bo, bw, bi, bget); | ||
| 30 | }while(r == FlateOk && !bufeof(bi)); | ||
| 31 | |||
| 32 | if(r != FlateOk){ | ||
| 33 | werrstr("%s", flateerr(r)); | ||
| 34 | return -1; | ||
| 35 | } | ||
| 36 | |||
| 37 | return 0; | ||
| 38 | } | ||
| @@ -3,17 +3,72 @@ · 2 unmodified lines | |||
| 3 | #include <bio.h> | 3 | #include <bio.h> |
| 4 | #include "pdf.h" | 4 | #include "pdf.h" |
| 5 | 5 | ||
| 6 | /* | 6 | /* 7.4 Filters */ |
| 7 | 7.4 | 7 | |
| 8 | 8 | struct Filter { | |
| 9 | ASCIIHex | 9 | char *name; |
| 10 | ASCII85 | 10 | int (*readall)(void *aux, Buffer *bi, Buffer *bo); |
| 11 | LZW | 11 | int (*open)(Filter *f, Object *o); |
| 12 | Flate | 12 | void (*close)(Filter *f); |
| 13 | RunLength | 13 | void *aux; |
| 14 | CCITTFax | 14 | }; |
| 15 | JBIG2 | 15 | |
| 16 | DCT | 16 | int fFlate(void *aux, Buffer *bi, Buffer *bo); |
| 17 | JPX | 17 | |
| 18 | Crypt | 18 | static Filter filters[] = { |
| 19 | */ | 19 | {"ASCII85Decode", nil, nil, nil}, |
| 20 | {"ASCIIHexDecode", nil, nil, nil}, | ||
| 21 | {"CCITTFaxDecode", nil, nil, nil}, | ||
| 22 | {"CryptDecode", nil, nil, nil}, | ||
| 23 | {"DCTDecode", nil, nil, nil}, | ||
| 24 | {"FlateDecode", fFlate}, | ||
| 25 | {"JBIG2Decode", nil, nil, nil}, | ||
| 26 | {"JPXDecode", nil, nil, nil}, | ||
| 27 | {"LZWDecode", nil, nil, nil}, | ||
| 28 | {"RunLengthDecode", nil, nil, nil}, | ||
| 29 | }; | ||
| 30 | |||
| 31 | Filter * | ||
| 32 | filteropen(char *name, Object *o) | ||
| 33 | { | ||
| 34 | int i; | ||
| 35 | Filter *f; | ||
| 36 | |||
| 37 | for(i = 0; i < nelem(filters) && strcmp(filters[i].name, name) != 0; i++); | ||
| 38 | if(i >= nelem(filters)){ | ||
| 39 | werrstr("no such filter %q", name); | ||
| 40 | return nil; | ||
| 41 | } | ||
| 42 | if(filters[i].readall == nil){ | ||
| 43 | werrstr("filter %q not implemented", name); | ||
| 44 | return nil; | ||
| 45 | } | ||
| 46 | if((f = malloc(sizeof(*f))) == nil) | ||
| 47 | return nil; | ||
| 48 | memmove(f, &filters[i], sizeof(*f)); | ||
| 49 | if(f->open != nil && f->open(f, o) != 0){ | ||
| 50 | free(f); | ||
| 51 | return nil; | ||
| 52 | } | ||
| 53 | |||
| 54 | return f; | ||
| 55 | } | ||
| 56 | |||
| 57 | int | ||
| 58 | filterrun(Filter *f, Buffer *bi, Buffer *bo) | ||
| 59 | { | ||
| 60 | if(f->readall(f->aux, bi, bo) != 0){ | ||
| 61 | werrstr("filter[%s]: %r", f->name); | ||
| 62 | return -1; | ||
| 63 | } | ||
| 64 | fprint(2, "filter[%s]: %d → %d %d\n", f->name, bi->sz, bo->sz, bo->off); | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | void | ||
| 69 | filterclose(Filter *f) | ||
| 70 | { | ||
| 71 | if(f->close != nil) | ||
| 72 | f->close(f); | ||
| 73 | free(f); | ||
| 74 | } | ||
| @@ -22,7 +22,7 @@ threadmain(int argc, char **argv) · 21 unmodified lines | |||
| 22 | Object *v; | 22 | Object *v; |
| 23 | 23 | ||
| 24 | quotefmtinstall(); | 24 | quotefmtinstall(); |
| 25 | deflateinit(); | 25 | inflateinit(); |
| 26 | 26 | ||
| 27 | ARGBEGIN{ | 27 | ARGBEGIN{ |
| 28 | default: | 28 | default: |
| @@ -5,8 +5,10 @@ TARG=pdfs · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | OFILES=\ | 6 | OFILES=\ |
| 7 | array.$O\ | 7 | array.$O\ |
| 8 | buffer.$O\ | ||
| 8 | dict.$O\ | 9 | dict.$O\ |
| 9 | eval.$O\ | 10 | eval.$O\ |
| 11 | f_flate.$O\ | ||
| 10 | filter.$O\ | 12 | filter.$O\ |
| 11 | main.$O\ | 13 | main.$O\ |
| 12 | misc.$O\ | 14 | misc.$O\ |
| @@ -14,6 +16,7 @@ OFILES=\ · 1 unmodified line | |||
| 14 | object.$O\ | 16 | object.$O\ |
| 15 | pdf.$O\ | 17 | pdf.$O\ |
| 16 | pdfs.$O\ | 18 | pdfs.$O\ |
| 19 | stream.$O\ | ||
| 17 | string.$O\ | 20 | string.$O\ |
| 18 | 21 | ||
| 19 | HFILES=\ | 22 | HFILES=\ |
| @@ -13,6 +13,31 @@ static Object null = { · 12 unmodified lines | |||
| 13 | .type = Onull, | 13 | .type = Onull, |
| 14 | }; | 14 | }; |
| 15 | 15 | ||
| 16 | static char *otypes[] = { | ||
| 17 | [Obool] = "bool", | ||
| 18 | [Onum] = "num", | ||
| 19 | [Ostr] = "str", | ||
| 20 | [Oname] = "name", | ||
| 21 | [Oarray] = "array", | ||
| 22 | [Odict] = "dict", | ||
| 23 | [Ostream] = "stream", | ||
| 24 | [Onull] = "null", | ||
| 25 | [Oindir] = "indir", | ||
| 26 | }; | ||
| 27 | |||
| 28 | int | ||
| 29 | Tfmt(Fmt *f) | ||
| 30 | { | ||
| 31 | Object *o; | ||
| 32 | |||
| 33 | o = va_arg(f->args, Object*); | ||
| 34 | if(o == nil || o == &null) | ||
| 35 | return fmtprint(f, "null"); | ||
| 36 | if(o->type < 0 || o->type >= nelem(otypes)) | ||
| 37 | return fmtprint(f, "????"); | ||
| 38 | return fmtprint(f, "%s", otypes[o->type]); | ||
| 39 | } | ||
| 40 | |||
| 16 | /* General function to parse an object of any type. */ | 41 | /* General function to parse an object of any type. */ |
| 17 | Object * | 42 | Object * |
| 18 | pdfobj(Pdf *pdf, void *b) | 43 | pdfobj(Pdf *pdf, void *b) |
| @@ -49,8 +74,8 @@ pdfobj(Pdf *pdf, void *b) · 30 unmodified lines | |||
| 49 | goto err; | 74 | goto err; |
| 50 | } | 75 | } |
| 51 | o->type = Ostream; | 76 | o->type = Ostream; |
| 52 | o->stream.length = m->num; | 77 | o->stream.len = m->num; |
| 53 | o->stream.offset = Boffset(b); | 78 | o->stream.off = Boffset(b); |
| 54 | return o; | 79 | return o; |
| 55 | } | 80 | } |
| 56 | Bseek(b, off, 0); | 81 | Bseek(b, off, 0); |
| @@ -75,9 +75,7 @@ err: · 74 unmodified lines | |||
| 75 | static int | 75 | static int |
| 76 | trailerread(Pdf *pdf) | 76 | trailerread(Pdf *pdf) |
| 77 | { | 77 | { |
| 78 | int i; | ||
| 79 | Object *o; | 78 | Object *o; |
| 80 | KeyValue *kv; | ||
| 81 | 79 | ||
| 82 | if((o = pdfobj(pdf, pdf->bio)) == nil) | 80 | if((o = pdfobj(pdf, pdf->bio)) == nil) |
| 83 | goto err; | 81 | goto err; |
| @@ -87,12 +85,8 @@ trailerread(Pdf *pdf) · 3 unmodified lines | |||
| 87 | goto err; | 85 | goto err; |
| 88 | } | 86 | } |
| 89 | 87 | ||
| 90 | for(i = 0, kv = o->dict.kv; i < o->dict.nkv; i++, kv++){ | 88 | pdf->root = pdfdictget(o, "Root"); |
| 91 | if(strcmp(kv->key, "Root") == 0) | 89 | pdf->info = pdfdictget(o, "Info"); |
| 92 | pdf->root = kv->value; | ||
| 93 | else if(strcmp(kv->key, "Info") == 0) | ||
| 94 | pdf->info = kv->value; | ||
| 95 | } | ||
| 96 | pdfobjfree(o); | 90 | pdfobjfree(o); |
| 97 | o = nil; | 91 | o = nil; |
| 98 | 92 | ||
| @@ -101,8 +95,6 @@ trailerread(Pdf *pdf) · 2 unmodified lines | |||
| 101 | werrstr("no root"); | 95 | werrstr("no root"); |
| 102 | goto err; | 96 | goto err; |
| 103 | } | 97 | } |
| 104 | if(pdfeval(pdf, pdf->root) != 0 || pdfeval(pdf, pdf->info) != 0) | ||
| 105 | goto err; | ||
| 106 | 98 | ||
| 107 | return 0; | 99 | return 0; |
| 108 | err: | 100 | err: |
| @@ -121,6 +113,9 @@ pdfopen(int fd) · 12 unmodified lines | |||
| 121 | int nxref; /* 7.5.4 xref subsection number of objects */ | 113 | int nxref; /* 7.5.4 xref subsection number of objects */ |
| 122 | int xreftb; /* 7.5.4 xref table offset from the beginning of the file */ | 114 | int xreftb; /* 7.5.4 xref table offset from the beginning of the file */ |
| 123 | int i, n, off; | 115 | int i, n, off; |
| 116 | Stream *stream; | ||
| 117 | |||
| 118 | fmtinstall('T', Tfmt); | ||
| 124 | 119 | ||
| 125 | b = nil; | 120 | b = nil; |
| 126 | o = nil; | 121 | o = nil; |
| @@ -196,10 +191,16 @@ badxref: · 69 unmodified lines | |||
| 196 | } | 191 | } |
| 197 | }else if(isdigit(tmp[0])){ /* could be 7.5.8 xref stream (since PDF 1.5) */ | 192 | }else if(isdigit(tmp[0])){ /* could be 7.5.8 xref stream (since PDF 1.5) */ |
| 198 | Bseek(b, xreftb, 0); | 193 | Bseek(b, xreftb, 0); |
| 199 | if((o = pdfobj(pdf, b)) == nil || pdfeval(pdf, o) != 0) | 194 | if((o = pdfobj(pdf, b)) == nil || (stream = streamopen(pdf, o)) == nil) |
| 200 | goto err; | 195 | goto badxref; |
| 201 | 196 | streamclose(stream); | |
| 197 | pdf->root = pdfdictget(o, "Root"); | ||
| 198 | pdf->info = pdfdictget(o, "Info"); | ||
| 202 | } | 199 | } |
| 200 | if(pdfeval(pdf, pdf->root) != 0 || pdfeval(pdf, pdf->info) != 0) | ||
| 201 | goto err; | ||
| 202 | fprint(2, "root %T\n", pdf->root); | ||
| 203 | fprint(2, "info %T\n", pdf->info); | ||
| 203 | 204 | ||
| 204 | return pdf; | 205 | return pdf; |
| 205 | err: | 206 | err: |
| @@ -10,11 +10,23 @@ enum { · 9 unmodified lines | |||
| 10 | Oindir, /* 7.3.10 */ | 10 | Oindir, /* 7.3.10 */ |
| 11 | }; | 11 | }; |
| 12 | 12 | ||
| 13 | typedef struct Buffer Buffer; | ||
| 14 | typedef struct Filter Filter; | ||
| 13 | typedef struct KeyValue KeyValue; | 15 | typedef struct KeyValue KeyValue; |
| 14 | typedef struct Object Object; | 16 | typedef struct Object Object; |
| 15 | typedef struct Pdf Pdf; | 17 | typedef struct Pdf Pdf; |
| 16 | typedef struct Xref Xref; | ||
| 17 | typedef struct Stream Stream; | 18 | typedef struct Stream Stream; |
| 19 | typedef struct Xref Xref; | ||
| 20 | #pragma incomplete Filter | ||
| 21 | |||
| 22 | struct Buffer { | ||
| 23 | uchar *b; | ||
| 24 | int ro; | ||
| 25 | int maxsz; | ||
| 26 | int sz; | ||
| 27 | int off; | ||
| 28 | int eof; | ||
| 29 | }; | ||
| 18 | 30 | ||
| 19 | struct Object { | 31 | struct Object { |
| 20 | int type; | 32 | int type; |
| @@ -45,8 +57,8 @@ struct Object { · 24 unmodified lines | |||
| 45 | struct { | 57 | struct { |
| 46 | KeyValue *kv; | 58 | KeyValue *kv; |
| 47 | int nkv; | 59 | int nkv; |
| 48 | u32int length; /* packed */ | 60 | u32int len; /* packed */ |
| 49 | u32int offset; | 61 | u32int off; |
| 50 | }stream; | 62 | }stream; |
| 51 | }; | 63 | }; |
| 52 | }; | 64 | }; |
| @@ -72,9 +84,8 @@ struct Xref { · 19 unmodified lines | |||
| 72 | }; | 84 | }; |
| 73 | 85 | ||
| 74 | struct Stream { | 86 | struct Stream { |
| 75 | Biobuf; | 87 | Buffer buf; |
| 76 | Object *o; | 88 | void *bio; |
| 77 | u32int offset; | ||
| 78 | }; | 89 | }; |
| 79 | 90 | ||
| 80 | Pdf *pdfopen(int fd); | 91 | Pdf *pdfopen(int fd); |
| @@ -96,3 +107,19 @@ Object *pdfdictget(Object *o, char *name); · 15 unmodified lines | |||
| 96 | 107 | ||
| 97 | Stream *streamopen(Pdf *pdf, Object *o); | 108 | Stream *streamopen(Pdf *pdf, Object *o); |
| 98 | void streamclose(Stream *s); | 109 | void streamclose(Stream *s); |
| 110 | |||
| 111 | Filter *filteropen(char *name, Object *o); | ||
| 112 | int filterrun(Filter *f, Buffer *bi, Buffer *bo); | ||
| 113 | void filterclose(Filter *f); | ||
| 114 | |||
| 115 | void bufinit(Buffer *b, uchar *d, int sz); | ||
| 116 | void buffree(Buffer *b); | ||
| 117 | int bufeof(Buffer *b); | ||
| 118 | uchar *bufdata(Buffer *b, int *sz); | ||
| 119 | int bufreadn(Buffer *b, void *bio, int sz); | ||
| 120 | int bufput(Buffer *b, uchar *d, int sz); | ||
| 121 | int bufget(Buffer *b, uchar *d, int sz); | ||
| 122 | void bufdump(Buffer *b); | ||
| 123 | |||
| 124 | #pragma varargck type "T" Object * | ||
| 125 | int Tfmt(Fmt *f); | ||
| @@ -0,0 +1,93 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include "pdf.h" | ||
| 5 | |||
| 6 | static int | ||
| 7 | bufiof(Biobufhdr *b, void *data, long n) | ||
| 8 | { | ||
| 9 | Stream *s; | ||
| 10 | |||
| 11 | s = (void*)((char*)b - sizeof(*s)); | ||
| 12 | |||
| 13 | return bufget(&s->buf, data, n); | ||
| 14 | } | ||
| 15 | |||
| 16 | Stream * | ||
| 17 | streamopen(Pdf *pdf, Object *o) | ||
| 18 | { | ||
| 19 | Stream *s; | ||
| 20 | Buffer b, x; | ||
| 21 | Object *of, **flts; | ||
| 22 | Filter *f; | ||
| 23 | int i, nflts; | ||
| 24 | |||
| 25 | s = nil; | ||
| 26 | if(pdfeval(pdf, o) != 0 || o == nil || o->type != Ostream) /* FIXME open a string object as a stream as well? */ | ||
| 27 | return nil; | ||
| 28 | |||
| 29 | bufinit(&b, nil, 0); | ||
| 30 | if(Bseek(pdf->bio, o->stream.off, 0) != o->stream.off) | ||
| 31 | return nil; | ||
| 32 | if(bufreadn(&b, pdf->bio, o->stream.len) < 0) | ||
| 33 | goto err; | ||
| 34 | bufdump(&b); | ||
| 35 | |||
| 36 | /* see if there are any filters */ | ||
| 37 | if((of = pdfdictget(o, "Filter")) != nil){ | ||
| 38 | if(pdfeval(pdf, of) != 0) | ||
| 39 | goto err; | ||
| 40 | if(of->type == Oname){ /* one filter */ | ||
| 41 | flts = &of; | ||
| 42 | nflts = 1; | ||
| 43 | }else if(of->type == Oarray){ /* array of filters */ | ||
| 44 | flts = of->array.e; | ||
| 45 | nflts = of->array.ne; | ||
| 46 | }else{ | ||
| 47 | werrstr("filters type invalid (%T)", of); | ||
| 48 | goto err; | ||
| 49 | } | ||
| 50 | |||
| 51 | for(i = nflts-1; i >= 0; i--){ | ||
| 52 | if(flts[i]->type != Oname){ | ||
| 53 | werrstr("filter type invalid (%T)", flts[i]); | ||
| 54 | goto err; | ||
| 55 | } | ||
| 56 | if((f = filteropen(flts[i]->name, o)) == nil) | ||
| 57 | goto err; | ||
| 58 | bufinit(&x, nil, 0); | ||
| 59 | if(filterrun(f, &b, &x) != 0){ | ||
| 60 | buffree(&x); | ||
| 61 | goto err; | ||
| 62 | } | ||
| 63 | buffree(&b); | ||
| 64 | b = x; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | if((s = calloc(1, sizeof(*s)+sizeof(Biobuf))) == nil){ | ||
| 69 | buffree(&b); | ||
| 70 | return nil; | ||
| 71 | } | ||
| 72 | s->bio = (uchar*)(s+1); | ||
| 73 | s->buf = b; | ||
| 74 | Binit(s->bio, Bfildes(pdf->bio), OREAD); | ||
| 75 | Biofn(s->bio, bufiof); | ||
| 76 | |||
| 77 | bufdump(&s->buf); | ||
| 78 | |||
| 79 | return s; | ||
| 80 | err: | ||
| 81 | werrstr("stream: %r"); | ||
| 82 | buffree(&b); | ||
| 83 | free(s); | ||
| 84 | return nil; | ||
| 85 | } | ||
| 86 | |||
| 87 | void | ||
| 88 | streamclose(Stream *s) | ||
| 89 | { | ||
| 90 | buffree(&s->buf); | ||
| 91 | Bterm(s->bio); | ||
| 92 | free(s); | ||
| 93 | } | ||