mattermost-community-enterp.../vendor/github.com/ledongthuc/pdf/ps.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

157 lines
3.6 KiB
Go

// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pdf
import (
"fmt"
"io"
)
// A Stack represents a stack of values.
type Stack struct {
stack []Value
}
func (stk *Stack) Len() int {
return len(stk.stack)
}
func (stk *Stack) Push(v Value) {
stk.stack = append(stk.stack, v)
}
func (stk *Stack) Pop() Value {
n := len(stk.stack)
if n == 0 {
return Value{}
}
v := stk.stack[n-1]
stk.stack[n-1] = Value{}
stk.stack = stk.stack[:n-1]
return v
}
func newDict() Value {
return Value{nil, objptr{}, make(dict)}
}
// Interpret interprets the content in a stream as a basic PostScript program,
// pushing values onto a stack and then calling the do function to execute
// operators. The do function may push or pop values from the stack as needed
// to implement op.
//
// Interpret handles the operators "dict", "currentdict", "begin", "end", "def", and "pop" itself.
//
// Interpret is not a full-blown PostScript interpreter. Its job is to handle the
// very limited PostScript found in certain supporting file formats embedded
// in PDF files, such as cmap files that describe the mapping from font code
// points to Unicode code points.
//
// 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)) {
var stk Stack
var dicts []dict
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)
}
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
}
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(fmt.Sprintf("def of non-name: %+v", stk.Pop().data))
// Skip the value if it has key without value
continue
}
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})
}
}
}
type seqReader struct {
rd io.Reader
offset int64
}
func (r *seqReader) ReadAt(buf []byte, offset int64) (int, error) {
if offset != r.offset {
return 0, fmt.Errorf("non-sequential read of stream")
}
n, err := io.ReadFull(r.rd, buf)
r.offset += int64(n)
return n, err
}