Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support array of content streams and parse them as a single stream (@romanpickl) #39

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 77 additions & 61 deletions ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,77 +49,93 @@ func newDict() Value {
// in PDF files, such as cmap files that describe the mapping from font code
// points to Unicode code points.
//
// There is no support for executable blocks, among other limitations.
// A stream can also be represented by an array of streams that has to be handled as a single stream
// In the case of a simple stream read only once, otherwise get the length of the stream to handle it properly
//
// There is no support for executable blocks, among other limitations.
func Interpret(strm Value, do func(stk *Stack, op string)) {
rd := strm.Reader()
b := newBuffer(rd, 0)
b.allowEOF = true
b.allowObjptr = false
b.allowStream = false
var stk Stack
var dicts []dict
Reading:
for {
tok := b.readToken()
if tok == io.EOF {
break
s := strm
strmlen := 1
if strm.Kind() == Array {
strmlen = strm.Len()
}

for i := 0; i < strmlen; i++ {
if strm.Kind() == Array {
s = strm.Index(i)
}
if kw, ok := tok.(keyword); ok {
switch kw {
case "null", "[", "]", "<<", ">>":

rd := s.Reader()

b := newBuffer(rd, 0)
b.allowEOF = true
b.allowObjptr = false
b.allowStream = false

Reading:
for {
tok := b.readToken()
if tok == io.EOF {
break
default:
for i := len(dicts) - 1; i >= 0; i-- {
if v, ok := dicts[i][name(kw)]; ok {
stk.Push(Value{nil, objptr{}, v})
continue Reading
}
if kw, ok := tok.(keyword); ok {
switch kw {
case "null", "[", "]", "<<", ">>":
break
default:
for i := len(dicts) - 1; i >= 0; i-- {
if v, ok := dicts[i][name(kw)]; ok {
stk.Push(Value{nil, objptr{}, v})
continue Reading
}
}
do(&stk, string(kw))
continue
case "dict":
stk.Pop()
stk.Push(Value{nil, objptr{}, make(dict)})
continue
case "currentdict":
if len(dicts) == 0 {
panic("no current dictionary")
}
stk.Push(Value{nil, objptr{}, dicts[len(dicts)-1]})
continue
case "begin":
d := stk.Pop()
if d.Kind() != Dict {
panic("cannot begin non-dict")
}
dicts = append(dicts, d.data.(dict))
continue
case "end":
if len(dicts) <= 0 {
panic("mismatched begin/end")
}
dicts = dicts[:len(dicts)-1]
continue
case "def":
if len(dicts) <= 0 {
panic("def without open dict")
}
val := stk.Pop()
key, ok := stk.Pop().data.(name)
if !ok {
panic("def of non-name")
}
dicts[len(dicts)-1][key] = val.data
continue
case "pop":
stk.Pop()
continue
}
do(&stk, string(kw))
continue
case "dict":
stk.Pop()
stk.Push(Value{nil, objptr{}, make(dict)})
continue
case "currentdict":
if len(dicts) == 0 {
panic("no current dictionary")
}
stk.Push(Value{nil, objptr{}, dicts[len(dicts)-1]})
continue
case "begin":
d := stk.Pop()
if d.Kind() != Dict {
panic("cannot begin non-dict")
}
dicts = append(dicts, d.data.(dict))
continue
case "end":
if len(dicts) <= 0 {
panic("mismatched begin/end")
}
dicts = dicts[:len(dicts)-1]
continue
case "def":
if len(dicts) <= 0 {
panic("def without open dict")
}
val := stk.Pop()
key, ok := stk.Pop().data.(name)
if !ok {
panic("def of non-name")
}
dicts[len(dicts)-1][key] = val.data
continue
case "pop":
stk.Pop()
continue
}
b.unreadToken(tok)
obj := b.readObject()
stk.Push(Value{nil, objptr{}, obj})
}
b.unreadToken(tok)
obj := b.readObject()
stk.Push(Value{nil, objptr{}, obj})
}
}

Expand Down