-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfilter.go
More file actions
141 lines (133 loc) · 3.64 KB
/
Copy pathfilter.go
File metadata and controls
141 lines (133 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package pdfdisassembler
import (
"fmt"
"github.com/speedata/pdfdisassembler/internal/filter"
)
// decodeStream is the Stream.Content backend. It reads the raw bytes from
// the file, applies decryption if enabled, then runs the declared filter
// chain.
func (r *Reader) decodeStream(s *Stream) ([]byte, error) {
if s.rawOffset < 0 || s.rawOffset+s.rawLength > int64(len(r.buf)) {
return nil, fmt.Errorf("pdfdisassembler: stream %d %d R: bytes out of range", s.objNumber, s.objGeneration)
}
raw := r.buf[s.rawOffset : s.rawOffset+s.rawLength]
return r.applyFilters(s, raw, true)
}
// applyFilters decrypts (if encrypted is true and an encryption context
// exists) and runs the filter chain declared on the stream dict.
func (r *Reader) applyFilters(s *Stream, raw []byte, encrypted bool) ([]byte, error) {
data := raw
if encrypted && r.encrypt != nil {
// Cross-reference streams are themselves unencrypted; callers
// must pass encrypted=false for those.
dec, err := r.encrypt.decryptStream(data, s.objNumber, s.objGeneration)
if err != nil {
return nil, fmt.Errorf("pdfdisassembler: decrypt stream %d %d R: %w", s.objNumber, s.objGeneration, err)
}
data = dec
}
filters, params, err := r.streamFilterChain(s.Dict)
if err != nil {
return nil, fmt.Errorf("pdfdisassembler: stream %d %d R filter chain: %w", s.objNumber, s.objGeneration, err)
}
for i, name := range filters {
// Skip image-only filters: return what we have and report.
if filter.IsImageFilter(name) {
return nil, fmt.Errorf("pdfdisassembler: stream %d %d R uses image-only filter %q (not decoded)", s.objNumber, s.objGeneration, name)
}
p := params[i]
p.MaxOutput = r.MaxStreamSize
out, err := filter.Decode(name, data, p)
if err != nil {
return nil, fmt.Errorf("pdfdisassembler: stream %d %d R filter %q: %w", s.objNumber, s.objGeneration, name, err)
}
data = out
}
return data, nil
}
// streamFilterChain returns the ordered filter names and per-filter params
// for a stream dict. Both /Filter and /F (abbreviation) are accepted.
func (r *Reader) streamFilterChain(d *Dict) ([]string, []filter.Params, error) {
v, ok := d.Get("Filter")
if !ok {
v, ok = d.Get("F")
}
if !ok {
return nil, nil, nil
}
v, err := r.Resolve(v)
if err != nil {
return nil, nil, err
}
var names []string
switch t := v.(type) {
case Name:
names = []string{string(t)}
case Array:
for _, e := range t {
e, err := r.Resolve(e)
if err != nil {
return nil, nil, err
}
n, ok := e.(Name)
if !ok {
return nil, nil, fmt.Errorf("/Filter entry is %T, want Name", e)
}
names = append(names, string(n))
}
default:
return nil, nil, fmt.Errorf("/Filter is %T", v)
}
pv, _ := d.Get("DecodeParms")
if pv == nil {
pv, _ = d.Get("DP")
}
if pv != nil {
pv, err = r.Resolve(pv)
if err != nil {
return nil, nil, err
}
}
params := make([]filter.Params, len(names))
switch t := pv.(type) {
case nil, Null:
// nothing
case *Dict:
if len(names) >= 1 {
params[0] = paramsFromDict(t)
}
case Array:
for i, e := range t {
if i >= len(params) {
break
}
e, err := r.Resolve(e)
if err != nil {
return nil, nil, err
}
if d, ok := e.(*Dict); ok {
params[i] = paramsFromDict(d)
}
}
}
return names, params, nil
}
func paramsFromDict(d *Dict) filter.Params {
var p filter.Params
if n, ok := d.Int("Predictor"); ok {
p.Predictor = int(n)
}
if n, ok := d.Int("Columns"); ok {
p.Columns = int(n)
}
if n, ok := d.Int("Colors"); ok {
p.Colors = int(n)
}
if n, ok := d.Int("BitsPerComponent"); ok {
p.BitsPerComponent = int(n)
}
if n, ok := d.Int("EarlyChange"); ok && n == 0 {
p.NoEarlyChange = true
}
return p
}