-
Notifications
You must be signed in to change notification settings - Fork 0
/
eexec.go
110 lines (96 loc) · 2.36 KB
/
eexec.go
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
// seehuhn.de/go/postscript - a rudimentary PostScript interpreter
// Copyright (C) 2023 Jochen Voss <voss@seehuhn.de>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package postscript
import "io"
func eexec(intp *Interpreter) error {
if len(intp.Stack) < 1 {
return &postScriptError{eStackunderflow, "eexec"}
}
if intp.Stack[len(intp.Stack)-1] != nil {
return &postScriptError{eTypecheck, "eexec"}
}
intp.Stack = intp.Stack[:len(intp.Stack)-1]
k := len(intp.DictStack)
intp.DictStack = append(intp.DictStack, intp.SystemDict)
s := intp.scanners[len(intp.scanners)-1]
err := s.BeginEexec(eexecN)
if err != nil {
return err
}
err = intp.executeScanner(s)
if err != nil && err != io.EOF {
return err
}
s.EndEexec()
intp.DictStack = intp.DictStack[:k]
return nil
}
func (s *scanner) BeginEexec(ivLen int) error {
if s.eexec != 0 {
return &postScriptError{eInvalidaccess, "nested eexec not supported"}
}
for {
b, err := s.Peek()
if err != nil {
return err
}
if b != ' ' && b != '\t' && b != '\r' && b != '\n' {
break
}
s.SkipByte()
}
bb := s.PeekN(ivLen)
if len(bb) < ivLen {
return s.err
}
isBinary := false
for _, b := range bb {
if !('0' <= b && b <= '9' || 'a' <= b && b <= 'f' || 'A' <= b && b <= 'F') {
isBinary = true
break
}
}
if isBinary {
s.eexec = 2 // binary
} else {
s.eexec = 1 // hex
}
s.r = eexecR
// skip the IV
s.regurgitate = true
for i := 0; i < eexecN; i++ {
_, err := s.Next()
if err != nil {
return err
}
}
s.regurgitate = false
return nil
}
func (s *scanner) EndEexec() {
s.eexec = 0
}
func (s *scanner) eexecDecode(b byte) byte {
out := b ^ byte(s.r>>8)
s.r = (uint16(b)+s.r)*eexecC1 + eexecC2
return out
}
const (
eexecN = 4
eexecR = 55665
eexecC1 = 52845
eexecC2 = 22719
)