func refToken(f fancy.Reader) ([]byte, int64) { tok, p := ps.Token(f) if len(tok) > 0 && tok[0] >= '0' && tok[0] <= '9' { ps.Token(f) r, q := ps.Token(f) if string(r) == "R" { f.Seek(p, 0) tok = f.Slice(int(1 + q - p)) } else { f.Seek(p+int64(len(tok)), 0) } } return tok, p }
func tupel(f fancy.Reader, count int) [][]byte { r := make([][]byte, count) for i := 0; i < count; i++ { r[i], _ = ps.Token(f) } return r }
// xrefSkip() queries the start of the trailer for a (partial) xref-table. func xrefSkip(f fancy.Reader, xref int) int { f.Seek(int64(xref), 0) t, p := ps.Token(f) if string(t) != "xref" { return -1 } for { t, p = ps.Token(f) if t[0] < '0' || t[0] > '9' { f.Seek(p, 0) break } t, _ = ps.Token(f) ps.SkipLE(f) f.Seek(int64(num(t)*20), 1) } r, _ := f.Seek(0, 1) return int(r) }
// xrefRead() reads the xref table(s) of a PDF file. This is not recursive // in favour of not to have to keep track of already used starting points // for xrefs. func xrefRead(f fancy.Reader, p int) map[int]int { var back [MAX_PDF_UPDATES]int b := 0 s := _Bytes for ok := true; ok; { back[b] = p b++ p = xrefSkip(f, p) f.Seek(int64(p), 0) s, _ = ps.Token(f) if string(s) != "trailer" { return nil } s, _ = ps.Token(f) s, ok = Dictionary(s)["/Prev"] p = num(s) } r := make(map[int]int) for b != 0 { b-- f.Seek(int64(back[b]), 0) ps.Token(f) // skip "xref" for { m := tupel(f, 2) if string(m[0]) == "trailer" { break } ps.SkipLE(f) o := num(m[0]) dat := f.Slice(num(m[1]) * 20) for i := 0; i < len(dat); i += 20 { if dat[i+17] != 'n' { r[o] = 0, false } else { r[o] = num(dat[i : i+10]) } o++ } } } return r }
// pd.Stream() returns contents of a stream. func (pd *PdfReaderT) Stream(reference []byte) (DictionaryT, []byte) { q, d := pd.Resolve(reference) dic := pd.Dic(d) l := pd.Num(dic["/Length"]) pd.rdr.Seek(int64(q), 0) t, _ := ps.Token(pd.rdr) if string(t) != "stream" { return nil, []byte{} } ps.SkipLE(pd.rdr) return dic, pd.rdr.Slice(l) }
// Load() loads a PDF file of a given name. func Load(fn string) *PdfReaderT { r := new(PdfReaderT) r.File = fn r.rdr = fancy.FileReader(fn) if r.Startxref = xrefStart(r.rdr); r.Startxref == -1 { return nil } if r.Xref = xrefRead(r.rdr, r.Startxref); r.Xref == nil { return nil } r.rdr.Seek(int64(xrefSkip(r.rdr, r.Startxref)), 0) s, _ := ps.Token(r.rdr) if string(s) != "trailer" { return nil } s, _ = ps.Token(r.rdr) if r.Trailer = Dictionary(s); r.Trailer == nil { return nil } r.rcache = make(map[string][]byte) r.rncache = make(map[string]int) r.dicache = make(map[string]DictionaryT) return r }
// Dictionary() makes a map/hash from PDF dictionary data. func Dictionary(s []byte) DictionaryT { if len(s) < 4 { return nil } e := len(s) - 1 if s[0] != s[1] || s[0] != '<' || s[e] != s[e-1] || s[e] != '>' { return nil } r := make(DictionaryT) rdr := fancy.SliceReader(s[2 : e-1]) for { t, _ := ps.Token(rdr) if len(t) == 0 { break } if t[0] != '/' { return nil } k := string(t) t, _ = refToken(rdr) r[k] = t } return r }