Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aafa89a703 | ||
|
|
ef0778c8b3 |
@@ -19,22 +19,22 @@ type Logger interface {
|
|||||||
// Dummy Logger does nothing.
|
// Dummy Logger does nothing.
|
||||||
type DummyLogger struct{}
|
type DummyLogger struct{}
|
||||||
|
|
||||||
func (this DummyLogger) Error(format string, args ...any) {
|
func (DummyLogger) Error(format string, args ...any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this DummyLogger) Warning(format string, args ...any) {
|
func (DummyLogger) Warning(format string, args ...any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this DummyLogger) Notice(format string, args ...any) {
|
func (DummyLogger) Notice(format string, args ...any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this DummyLogger) Info(format string, args ...any) {
|
func (DummyLogger) Info(format string, args ...any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this DummyLogger) Debug(format string, args ...any) {
|
func (DummyLogger) Debug(format string, args ...any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this DummyLogger) Trace(format string, args ...any) {
|
func (DummyLogger) Trace(format string, args ...any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple Console Logger that the tests use.
|
// Simple Console Logger that the tests use.
|
||||||
@@ -59,45 +59,39 @@ func NewConsoleLogger(logLevel LogLevel) *ConsoleLogger {
|
|||||||
return &logger
|
return &logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this ConsoleLogger) Error(format string, args ...any) {
|
func (cL ConsoleLogger) Error(format string, args ...any) {
|
||||||
if this.LogLevel >= LogLevelError {
|
if cL.LogLevel >= LogLevelError {
|
||||||
prefix := "[ERROR] "
|
cL.output(os.Stdout, "[ERROR] ", format, args...)
|
||||||
this.output(os.Stdout, prefix, format, args...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this ConsoleLogger) Warning(format string, args ...any) {
|
func (cL ConsoleLogger) Warning(format string, args ...any) {
|
||||||
if this.LogLevel >= LogLevelWarning {
|
if cL.LogLevel >= LogLevelWarning {
|
||||||
prefix := "[WARNING] "
|
cL.output(os.Stdout, "[WARNING] ", format, args...)
|
||||||
this.output(os.Stdout, prefix, format, args...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this ConsoleLogger) Notice(format string, args ...any) {
|
func (cL ConsoleLogger) Notice(format string, args ...any) {
|
||||||
if this.LogLevel >= LogLevelNotice {
|
if cL.LogLevel >= LogLevelNotice {
|
||||||
prefix := "[NOTICE] "
|
cL.output(os.Stdout, "[NOTICE] ", format, args...)
|
||||||
this.output(os.Stdout, prefix, format, args...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this ConsoleLogger) Info(format string, args ...any) {
|
func (cL ConsoleLogger) Info(format string, args ...any) {
|
||||||
if this.LogLevel >= LogLevelInfo {
|
if cL.LogLevel >= LogLevelInfo {
|
||||||
prefix := "[INFO] "
|
cL.output(os.Stdout, "[INFO] ", format, args...)
|
||||||
this.output(os.Stdout, prefix, format, args...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this ConsoleLogger) Debug(format string, args ...any) {
|
func (cL ConsoleLogger) Debug(format string, args ...any) {
|
||||||
if this.LogLevel >= LogLevelDebug {
|
if cL.LogLevel >= LogLevelDebug {
|
||||||
prefix := "[DEBUG] "
|
cL.output(os.Stdout, "[DEBUG] ", format, args...)
|
||||||
this.output(os.Stdout, prefix, format, args...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this ConsoleLogger) Trace(format string, args ...any) {
|
func (cL ConsoleLogger) Trace(format string, args ...any) {
|
||||||
if this.LogLevel >= LogLevelTrace {
|
if cL.LogLevel >= LogLevelTrace {
|
||||||
prefix := "[TRACE] "
|
cL.output(os.Stdout, "[TRACE] ", format, args...)
|
||||||
this.output(os.Stdout, prefix, format, args...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +102,7 @@ func SetLogger(logger Logger) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// output writes `format`, `args` log message prefixed by the source file name, line and `prefix`
|
// output writes `format`, `args` log message prefixed by the source file name, line and `prefix`
|
||||||
func (this ConsoleLogger) output(f *os.File, prefix string, format string, args ...any) {
|
func (ConsoleLogger) output(f *os.File, prefix string, format string, args ...any) {
|
||||||
_, file, line, ok := runtime.Caller(3)
|
_, file, line, ok := runtime.Caller(3)
|
||||||
if !ok {
|
if !ok {
|
||||||
file = "???"
|
file = "???"
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const timeFormat = "2 January 2006 at 15:04"
|
|
||||||
|
|
||||||
func UtcTimeFormat(t time.Time) string {
|
|
||||||
return t.Format(timeFormat) + " UTC"
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// Package common contains common properties used by the subpackages.
|
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const releaseYear = 2018
|
|
||||||
const releaseMonth = 11
|
|
||||||
const releaseDay = 17
|
|
||||||
const releaseHour = 11
|
|
||||||
const releaseMin = 30
|
|
||||||
|
|
||||||
// Holds version information, when bumping this make sure to bump the released at stamp also.
|
|
||||||
const Version = "2.2.0"
|
|
||||||
|
|
||||||
var ReleasedAt = time.Date(releaseYear, releaseMonth, releaseDay, releaseHour, releaseMin, 0, 0, time.UTC)
|
|
||||||
@@ -3,6 +3,7 @@ package contentstream
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/core"
|
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/core"
|
||||||
)
|
)
|
||||||
@@ -111,7 +112,7 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
|
|||||||
}
|
}
|
||||||
inText := false
|
inText := false
|
||||||
xPos, yPos := float64(-1), float64(-1)
|
xPos, yPos := float64(-1), float64(-1)
|
||||||
txt := ""
|
var txt strings.Builder
|
||||||
for _, op := range *operations {
|
for _, op := range *operations {
|
||||||
switch op.Operand {
|
switch op.Operand {
|
||||||
case "BT":
|
case "BT":
|
||||||
@@ -122,7 +123,7 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
|
|||||||
|
|
||||||
if op.Operand == "Td" || op.Operand == "TD" || op.Operand == "T*" {
|
if op.Operand == "Td" || op.Operand == "TD" || op.Operand == "T*" {
|
||||||
// Move to next line...
|
// Move to next line...
|
||||||
txt += "\n"
|
txt.WriteString("\n")
|
||||||
}
|
}
|
||||||
if op.Operand == "Tm" {
|
if op.Operand == "Tm" {
|
||||||
if len(op.Params) != 6 {
|
if len(op.Params) != 6 {
|
||||||
@@ -147,7 +148,7 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
|
|||||||
if yPos == -1 {
|
if yPos == -1 {
|
||||||
yPos = float64(*yfloat)
|
yPos = float64(*yfloat)
|
||||||
} else if yPos > float64(*yfloat) {
|
} else if yPos > float64(*yfloat) {
|
||||||
txt += "\n"
|
txt.WriteString("\n")
|
||||||
xPos = float64(*xfloat)
|
xPos = float64(*xfloat)
|
||||||
yPos = float64(*yfloat)
|
yPos = float64(*yfloat)
|
||||||
continue
|
continue
|
||||||
@@ -155,7 +156,7 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
|
|||||||
if xPos == -1 {
|
if xPos == -1 {
|
||||||
xPos = float64(*xfloat)
|
xPos = float64(*xfloat)
|
||||||
} else if xPos < float64(*xfloat) {
|
} else if xPos < float64(*xfloat) {
|
||||||
txt += "\t"
|
txt.WriteString("\t")
|
||||||
xPos = float64(*xfloat)
|
xPos = float64(*xfloat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,14 +171,14 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
|
|||||||
for _, obj := range *paramList {
|
for _, obj := range *paramList {
|
||||||
switch v := obj.(type) {
|
switch v := obj.(type) {
|
||||||
case *core.PdfObjectString:
|
case *core.PdfObjectString:
|
||||||
txt += string(*v)
|
txt.WriteString(string(*v))
|
||||||
case *core.PdfObjectFloat:
|
case *core.PdfObjectFloat:
|
||||||
if *v < -100 {
|
if *v < -100 {
|
||||||
txt += " "
|
txt.WriteString(" ")
|
||||||
}
|
}
|
||||||
case *core.PdfObjectInteger:
|
case *core.PdfObjectInteger:
|
||||||
if *v < -100 {
|
if *v < -100 {
|
||||||
txt += " "
|
txt.WriteString(" ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,9 +190,9 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("invalid parameter type, not string (%T)", op.Params[0])
|
return "", fmt.Errorf("invalid parameter type, not string (%T)", op.Params[0])
|
||||||
}
|
}
|
||||||
txt += string(*param)
|
txt.WriteString(string(*param))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return txt, nil
|
return txt.String(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,9 +89,9 @@ func NewCubicBezierPath() CubicBezierPath {
|
|||||||
return bpath
|
return bpath
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this CubicBezierPath) AppendCurve(curve CubicBezierCurve) CubicBezierPath {
|
func (c CubicBezierPath) AppendCurve(curve CubicBezierCurve) CubicBezierPath {
|
||||||
this.Curves = append(this.Curves, curve)
|
c.Curves = append(c.Curves, curve)
|
||||||
return this
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bpath CubicBezierPath) Copy() CubicBezierPath {
|
func (bpath CubicBezierPath) Copy() CubicBezierPath {
|
||||||
|
|||||||
@@ -11,36 +11,36 @@ func NewPath() Path {
|
|||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this Path) AppendPoint(point Point) Path {
|
func (p Path) AppendPoint(point Point) Path {
|
||||||
this.Points = append(this.Points, point)
|
p.Points = append(p.Points, point)
|
||||||
return this
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this Path) RemovePoint(number int) Path {
|
func (p Path) RemovePoint(number int) Path {
|
||||||
if number < 1 || number > len(this.Points) {
|
if number < 1 || number > len(p.Points) {
|
||||||
return this
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
idx := number - 1
|
idx := number - 1
|
||||||
this.Points = append(this.Points[:idx], this.Points[idx+1:]...)
|
p.Points = append(p.Points[:idx], p.Points[idx+1:]...)
|
||||||
return this
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this Path) Length() int {
|
func (p Path) Length() int {
|
||||||
return len(this.Points)
|
return len(p.Points)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this Path) GetPointNumber(number int) Point {
|
func (p Path) GetPointNumber(number int) Point {
|
||||||
if number < 1 || number > len(this.Points) {
|
if number < 1 || number > len(p.Points) {
|
||||||
return Point{}
|
return Point{}
|
||||||
}
|
}
|
||||||
return this.Points[number-1]
|
return p.Points[number-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (path Path) Copy() Path {
|
func (p Path) Copy() Path {
|
||||||
pathcopy := Path{}
|
pathcopy := Path{}
|
||||||
pathcopy.Points = []Point{}
|
pathcopy.Points = []Point{}
|
||||||
for _, p := range path.Points {
|
for _, p := range p.Points {
|
||||||
pathcopy.Points = append(pathcopy.Points, p)
|
pathcopy.Points = append(pathcopy.Points, p)
|
||||||
}
|
}
|
||||||
return pathcopy
|
return pathcopy
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ func (p Point) Add(dx, dy float64) Point {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add vector to a point.
|
// Add vector to a point.
|
||||||
func (this Point) AddVector(v Vector) Point {
|
func (p Point) AddVector(v Vector) Point {
|
||||||
this.X += v.Dx
|
p.X += v.Dx
|
||||||
this.Y += v.Dy
|
p.Y += v.Dy
|
||||||
return this
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Point) String() string {
|
func (p Point) String() string {
|
||||||
|
|||||||
@@ -43,13 +43,13 @@ func (v Vector) Rotate(phi float64) Vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Change the sign of the vector: -vector.
|
// Change the sign of the vector: -vector.
|
||||||
func (this Vector) Flip() Vector {
|
func (v Vector) Flip() Vector {
|
||||||
mag := this.Magnitude()
|
mag := v.Magnitude()
|
||||||
theta := this.GetPolarAngle()
|
theta := v.GetPolarAngle()
|
||||||
|
|
||||||
this.Dx = mag * math.Cos(theta+math.Pi)
|
v.Dx = mag * math.Cos(theta+math.Pi)
|
||||||
this.Dy = mag * math.Sin(theta+math.Pi)
|
v.Dy = mag * math.Sin(theta+math.Pi)
|
||||||
return this
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Vector) FlipY() Vector {
|
func (v Vector) FlipY() Vector {
|
||||||
@@ -62,19 +62,19 @@ func (v Vector) FlipX() Vector {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this Vector) Scale(factor float64) Vector {
|
func (v Vector) Scale(factor float64) Vector {
|
||||||
mag := this.Magnitude()
|
mag := v.Magnitude()
|
||||||
theta := this.GetPolarAngle()
|
theta := v.GetPolarAngle()
|
||||||
|
|
||||||
this.Dx = factor * mag * math.Cos(theta)
|
v.Dx = factor * mag * math.Cos(theta)
|
||||||
this.Dy = factor * mag * math.Sin(theta)
|
v.Dy = factor * mag * math.Sin(theta)
|
||||||
return this
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this Vector) Magnitude() float64 {
|
func (v Vector) Magnitude() float64 {
|
||||||
return math.Sqrt(math.Pow(this.Dx, 2.0) + math.Pow(this.Dy, 2.0))
|
return math.Sqrt(math.Pow(v.Dx, 2.0) + math.Pow(v.Dy, 2.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this Vector) GetPolarAngle() float64 {
|
func (v Vector) GetPolarAngle() float64 {
|
||||||
return math.Atan2(this.Dy, this.Dx)
|
return math.Atan2(v.Dy, v.Dx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,21 +10,18 @@ import (
|
|||||||
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common"
|
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO (v3): Create a new type xrefType which can be an integer and can be used for improved type checking.
|
|
||||||
// TODO (v3): Unexport these constants and rename with camelCase.
|
|
||||||
const (
|
const (
|
||||||
// XREF_TABLE_ENTRY indicates a normal xref table entry.
|
// xRefTableEntry indicates a normal xref table entry.
|
||||||
XREF_TABLE_ENTRY = iota
|
xRefTableEntry = iota
|
||||||
|
|
||||||
// XREF_OBJECT_STREAM indicates an xref entry in an xref object stream.
|
// xRefObjectStream indicates an xref entry in an xref object stream.
|
||||||
XREF_OBJECT_STREAM = iota
|
xRefObjectStream = iota
|
||||||
)
|
)
|
||||||
|
|
||||||
// XrefObject defines a cross reference entry which is a map between object number (with generation number) and the
|
// XrefObject defines a cross reference entry which is a map between object number (with generation number) and the
|
||||||
// location of the actual object, either as a file offset (xref table entry), or as a location within an xref
|
// location of the actual object, either as a file offset (xref table entry), or as a location within an xref
|
||||||
// stream object (xref object stream).
|
// stream object (xref object stream).
|
||||||
// TODO (v3): Unexport.
|
type xRefObject struct {
|
||||||
type XrefObject struct {
|
|
||||||
xtype int
|
xtype int
|
||||||
objectNumber int
|
objectNumber int
|
||||||
generation int
|
generation int
|
||||||
@@ -36,32 +33,28 @@ type XrefObject struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XrefTable is a map between object number and corresponding XrefObject.
|
// XrefTable is a map between object number and corresponding XrefObject.
|
||||||
// TODO (v3): Unexport.
|
type xRefTable map[int]xRefObject
|
||||||
// TODO: Consider changing to a slice, so can maintain the object order without sorting when analyzing.
|
|
||||||
type XrefTable map[int]XrefObject
|
|
||||||
|
|
||||||
// ObjectStream represents an object stream's information which can contain multiple indirect objects.
|
// ObjectStream represents an object stream's information which can contain multiple indirect objects.
|
||||||
// The information specifies the number of objects and has information about offset locations for
|
// The information specifies the number of objects and has information about offset locations for
|
||||||
// each object.
|
// each object.
|
||||||
// TODO (v3): Unexport.
|
type objectStream struct {
|
||||||
type ObjectStream struct {
|
n int
|
||||||
N int // TODO (v3): Unexport.
|
|
||||||
ds []byte
|
ds []byte
|
||||||
offsets map[int]int64
|
offsets map[int]int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectStreams defines a map between object numbers (object streams only) and underlying ObjectStream information.
|
// ObjectStreams defines a map between object numbers (object streams only) and underlying ObjectStream information.
|
||||||
type ObjectStreams map[int]ObjectStream
|
type ObjectStreams map[int]objectStream
|
||||||
|
|
||||||
// ObjectCache defines a map between object numbers and corresponding PdfObject. Serves as a cache for PdfObjects that
|
// ObjectCache defines a map between object numbers and corresponding PdfObject. Serves as a cache for PdfObjects that
|
||||||
// have already been parsed.
|
// have already been parsed.
|
||||||
// TODO (v3): Unexport.
|
type objectCache map[int]PdfObject
|
||||||
type ObjectCache map[int]PdfObject
|
|
||||||
|
|
||||||
// Get an object from an object stream.
|
// Get an object from an object stream.
|
||||||
func (parser *PdfParser) lookupObjectViaOS(sobjNumber int, objNum int) (PdfObject, error) {
|
func (parser *PdfParser) lookupObjectViaOS(sobjNumber int, objNum int) (PdfObject, error) {
|
||||||
var bufReader *bytes.Reader
|
var bufReader *bytes.Reader
|
||||||
var objstm ObjectStream
|
var objstm objectStream
|
||||||
var cached bool
|
var cached bool
|
||||||
|
|
||||||
objstm, cached = parser.objstms[sobjNumber]
|
objstm, cached = parser.objstms[sobjNumber]
|
||||||
@@ -149,7 +142,7 @@ func (parser *PdfParser) lookupObjectViaOS(sobjNumber int, objNum int) (PdfObjec
|
|||||||
offsets[int(*onum)] = int64(*firstOffset + *offset)
|
offsets[int(*onum)] = int64(*firstOffset + *offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
objstm = ObjectStream{N: int(*N), ds: ds, offsets: offsets}
|
objstm = objectStream{n: int(*N), ds: ds, offsets: offsets}
|
||||||
parser.objstms[sobjNumber] = objstm
|
parser.objstms[sobjNumber] = objstm
|
||||||
} else {
|
} else {
|
||||||
// Temporarily change the reader object to this decoded buffer.
|
// Temporarily change the reader object to this decoded buffer.
|
||||||
@@ -246,7 +239,7 @@ func (parser *PdfParser) lookupByNumber(objNumber int, attemptRepairs bool) (Pdf
|
|||||||
|
|
||||||
common.Log.Trace("Lookup obj number %d", objNumber)
|
common.Log.Trace("Lookup obj number %d", objNumber)
|
||||||
switch xref.xtype {
|
switch xref.xtype {
|
||||||
case XREF_TABLE_ENTRY:
|
case xRefTableEntry:
|
||||||
common.Log.Trace("xrefobj obj num %d", xref.objectNumber)
|
common.Log.Trace("xrefobj obj num %d", xref.objectNumber)
|
||||||
common.Log.Trace("xrefobj gen %d", xref.generation)
|
common.Log.Trace("xrefobj gen %d", xref.generation)
|
||||||
common.Log.Trace("xrefobj offset %d", xref.offset)
|
common.Log.Trace("xrefobj offset %d", xref.offset)
|
||||||
@@ -283,7 +276,7 @@ func (parser *PdfParser) lookupByNumber(objNumber int, attemptRepairs bool) (Pdf
|
|||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
// Empty the cache.
|
// Empty the cache.
|
||||||
parser.ObjCache = ObjectCache{}
|
parser.ObjCache = objectCache{}
|
||||||
// Try looking up again and return.
|
// Try looking up again and return.
|
||||||
return parser.lookupByNumberWrapper(objNumber, false)
|
return parser.lookupByNumberWrapper(objNumber, false)
|
||||||
}
|
}
|
||||||
@@ -292,7 +285,7 @@ func (parser *PdfParser) lookupByNumber(objNumber int, attemptRepairs bool) (Pdf
|
|||||||
common.Log.Trace("Returning obj")
|
common.Log.Trace("Returning obj")
|
||||||
parser.ObjCache[objNumber] = obj
|
parser.ObjCache[objNumber] = obj
|
||||||
return obj, false, nil
|
return obj, false, nil
|
||||||
case XREF_OBJECT_STREAM:
|
case xRefObjectStream:
|
||||||
common.Log.Trace("xref from object stream!")
|
common.Log.Trace("xref from object stream!")
|
||||||
common.Log.Trace(">Load via OS!")
|
common.Log.Trace(">Load via OS!")
|
||||||
common.Log.Trace("Object stream available in object %d/%d", xref.osObjNumber, xref.osObjIndex)
|
common.Log.Trace("Object stream available in object %d/%d", xref.osObjNumber, xref.osObjIndex)
|
||||||
@@ -361,7 +354,7 @@ func (parser *PdfParser) Trace(obj PdfObject) (PdfObject, error) {
|
|||||||
return o, nil
|
return o, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func printXrefTable(xrefTable XrefTable) {
|
func printXrefTable(xrefTable xRefTable) {
|
||||||
common.Log.Debug("=X=X=X=")
|
common.Log.Debug("=X=X=X=")
|
||||||
common.Log.Debug("Xref table:")
|
common.Log.Debug("Xref table:")
|
||||||
i := 0
|
i := 0
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ type PdfParser struct {
|
|||||||
rs io.ReadSeeker
|
rs io.ReadSeeker
|
||||||
reader *bufio.Reader
|
reader *bufio.Reader
|
||||||
fileSize int64
|
fileSize int64
|
||||||
xrefs XrefTable
|
xrefs xRefTable
|
||||||
objstms ObjectStreams
|
objstms ObjectStreams
|
||||||
trailer *PdfObjectDictionary
|
trailer *PdfObjectDictionary
|
||||||
ObjCache ObjectCache // TODO: Unexport (v3).
|
ObjCache objectCache
|
||||||
crypter *PdfCrypt
|
crypter *PdfCrypt
|
||||||
repairsAttempted bool // Avoid multiple attempts for repair.
|
repairsAttempted bool // Avoid multiple attempts for repair.
|
||||||
|
|
||||||
@@ -740,8 +740,8 @@ func (parser *PdfParser) parseXrefTable() (*PdfObjectDictionary, error) {
|
|||||||
// would be marked as free. But can still happen!
|
// would be marked as free. But can still happen!
|
||||||
x, ok := parser.xrefs[curObjNum]
|
x, ok := parser.xrefs[curObjNum]
|
||||||
if !ok || gen > x.generation {
|
if !ok || gen > x.generation {
|
||||||
obj := XrefObject{objectNumber: curObjNum,
|
obj := xRefObject{objectNumber: curObjNum,
|
||||||
xtype: XREF_TABLE_ENTRY,
|
xtype: xRefTableEntry,
|
||||||
offset: first, generation: gen}
|
offset: first, generation: gen}
|
||||||
parser.xrefs[curObjNum] = obj
|
parser.xrefs[curObjNum] = obj
|
||||||
}
|
}
|
||||||
@@ -1000,16 +1000,16 @@ func (parser *PdfParser) parseXrefStream(xstm *PdfObjectInteger) (*PdfObjectDict
|
|||||||
if xr, ok := parser.xrefs[objNum]; !ok || int(n3) > xr.generation {
|
if xr, ok := parser.xrefs[objNum]; !ok || int(n3) > xr.generation {
|
||||||
// Only overload if not already loaded!
|
// Only overload if not already loaded!
|
||||||
// or has a newer generation number. (should not happen)
|
// or has a newer generation number. (should not happen)
|
||||||
obj := XrefObject{objectNumber: objNum,
|
obj := xRefObject{objectNumber: objNum,
|
||||||
xtype: XREF_TABLE_ENTRY, offset: n2, generation: int(n3)}
|
xtype: xRefTableEntry, offset: n2, generation: int(n3)}
|
||||||
parser.xrefs[objNum] = obj
|
parser.xrefs[objNum] = obj
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
// Object type 2: Compressed object.
|
// Object type 2: Compressed object.
|
||||||
common.Log.Trace("- In use - compressed object")
|
common.Log.Trace("- In use - compressed object")
|
||||||
if _, ok := parser.xrefs[objNum]; !ok {
|
if _, ok := parser.xrefs[objNum]; !ok {
|
||||||
obj := XrefObject{objectNumber: objNum,
|
obj := xRefObject{objectNumber: objNum,
|
||||||
xtype: XREF_OBJECT_STREAM, osObjNumber: int(n2), osObjIndex: int(n3)}
|
xtype: xRefObjectStream, osObjNumber: int(n2), osObjIndex: int(n3)}
|
||||||
parser.xrefs[objNum] = obj
|
parser.xrefs[objNum] = obj
|
||||||
common.Log.Trace("entry: %s", parser.xrefs[objNum])
|
common.Log.Trace("entry: %s", parser.xrefs[objNum])
|
||||||
}
|
}
|
||||||
@@ -1128,7 +1128,7 @@ func (parser *PdfParser) seekToEOFMarker(fSize int64) error {
|
|||||||
// The earlier xrefs have higher precedence. If objects already
|
// The earlier xrefs have higher precedence. If objects already
|
||||||
// loaded will ignore older versions.
|
// loaded will ignore older versions.
|
||||||
func (parser *PdfParser) loadXrefs() (*PdfObjectDictionary, error) {
|
func (parser *PdfParser) loadXrefs() (*PdfObjectDictionary, error) {
|
||||||
parser.xrefs = make(XrefTable)
|
parser.xrefs = make(xRefTable)
|
||||||
parser.objstms = make(ObjectStreams)
|
parser.objstms = make(ObjectStreams)
|
||||||
|
|
||||||
// Get the file size.
|
// Get the file size.
|
||||||
@@ -1482,30 +1482,13 @@ func (parser *PdfParser) ParseIndirectObject() (PdfObject, error) {
|
|||||||
return &indirect, nil
|
return &indirect, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// For testing purposes.
|
|
||||||
// TODO: Unexport (v3) or move to test files, if needed by external test cases.
|
|
||||||
func NewParserFromString(txt string) *PdfParser {
|
|
||||||
parser := PdfParser{}
|
|
||||||
buf := []byte(txt)
|
|
||||||
|
|
||||||
bufReader := bytes.NewReader(buf)
|
|
||||||
parser.rs = bufReader
|
|
||||||
|
|
||||||
bufferedReader := bufio.NewReader(bufReader)
|
|
||||||
parser.reader = bufferedReader
|
|
||||||
|
|
||||||
parser.fileSize = int64(len(txt))
|
|
||||||
|
|
||||||
return &parser
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewParser creates a new parser for a PDF file via ReadSeeker. Loads the cross reference stream and trailer.
|
// NewParser creates a new parser for a PDF file via ReadSeeker. Loads the cross reference stream and trailer.
|
||||||
// An error is returned on failure.
|
// An error is returned on failure.
|
||||||
func NewParser(rs io.ReadSeeker) (*PdfParser, error) {
|
func NewParser(rs io.ReadSeeker) (*PdfParser, error) {
|
||||||
parser := &PdfParser{}
|
parser := &PdfParser{}
|
||||||
|
|
||||||
parser.rs = rs
|
parser.rs = rs
|
||||||
parser.ObjCache = make(ObjectCache)
|
parser.ObjCache = make(objectCache)
|
||||||
parser.streamLengthReferenceLookupInProgress = map[int64]bool{}
|
parser.streamLengthReferenceLookupInProgress = map[int64]bool{}
|
||||||
|
|
||||||
// Start by reading the xrefs (from bottom).
|
// Start by reading the xrefs (from bottom).
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package core
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common"
|
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common"
|
||||||
)
|
)
|
||||||
@@ -315,15 +316,16 @@ func (array *PdfObjectArray) String() string {
|
|||||||
|
|
||||||
// DefaultWriteString outputs the object as it is to be written to file.
|
// DefaultWriteString outputs the object as it is to be written to file.
|
||||||
func (array *PdfObjectArray) DefaultWriteString() string {
|
func (array *PdfObjectArray) DefaultWriteString() string {
|
||||||
outStr := "["
|
var outStr strings.Builder
|
||||||
|
outStr.WriteString("[")
|
||||||
for ind, o := range *array {
|
for ind, o := range *array {
|
||||||
outStr += o.DefaultWriteString()
|
outStr.WriteString(o.DefaultWriteString())
|
||||||
if ind < (len(*array) - 1) {
|
if ind < (len(*array) - 1) {
|
||||||
outStr += " "
|
outStr.WriteString(" ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outStr += "]"
|
outStr.WriteString("]")
|
||||||
return outStr
|
return outStr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append adds an PdfObject to the array.
|
// Append adds an PdfObject to the array.
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func (parser *PdfParser) repairLocateXref() (int64, error) {
|
|||||||
// Useful when the cross reference is pointing to an object with the wrong number.
|
// Useful when the cross reference is pointing to an object with the wrong number.
|
||||||
// Update the table.
|
// Update the table.
|
||||||
func (parser *PdfParser) rebuildXrefTable() error {
|
func (parser *PdfParser) rebuildXrefTable() error {
|
||||||
newXrefs := XrefTable{}
|
newXrefs := xRefTable{}
|
||||||
for objNum, xref := range parser.xrefs {
|
for objNum, xref := range parser.xrefs {
|
||||||
obj, _, err := parser.lookupByNumberWrapper(objNum, false)
|
obj, _, err := parser.lookupByNumberWrapper(objNum, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -92,7 +92,7 @@ func parseObjectNumberFromString(str string) (int, int, error) {
|
|||||||
// Parse the entire file from top down.
|
// Parse the entire file from top down.
|
||||||
// Goes through the file byte-by-byte looking for "<num> <generation> obj" patterns.
|
// Goes through the file byte-by-byte looking for "<num> <generation> obj" patterns.
|
||||||
// N.B. This collects the XREF_TABLE_ENTRY data only.
|
// N.B. This collects the XREF_TABLE_ENTRY data only.
|
||||||
func (parser *PdfParser) repairRebuildXrefsTopDown() (*XrefTable, error) {
|
func (parser *PdfParser) repairRebuildXrefsTopDown() (*xRefTable, error) {
|
||||||
if parser.repairsAttempted {
|
if parser.repairsAttempted {
|
||||||
// Avoid multiple repairs (only try once).
|
// Avoid multiple repairs (only try once).
|
||||||
return nil, fmt.Errorf("repair failed")
|
return nil, fmt.Errorf("repair failed")
|
||||||
@@ -107,7 +107,7 @@ func (parser *PdfParser) repairRebuildXrefsTopDown() (*XrefTable, error) {
|
|||||||
bufLen := 20
|
bufLen := 20
|
||||||
last := make([]byte, bufLen)
|
last := make([]byte, bufLen)
|
||||||
|
|
||||||
xrefTable := XrefTable{}
|
xrefTable := xRefTable{}
|
||||||
for {
|
for {
|
||||||
b, err := parser.reader.ReadByte()
|
b, err := parser.reader.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -164,8 +164,8 @@ func (parser *PdfParser) repairRebuildXrefsTopDown() (*XrefTable, error) {
|
|||||||
// Create and insert the XREF entry if not existing, or the generation number is higher.
|
// Create and insert the XREF entry if not existing, or the generation number is higher.
|
||||||
if curXref, has := xrefTable[objNum]; !has || curXref.generation < genNum {
|
if curXref, has := xrefTable[objNum]; !has || curXref.generation < genNum {
|
||||||
// Make the entry for the cross ref table.
|
// Make the entry for the cross ref table.
|
||||||
xrefEntry := XrefObject{}
|
xrefEntry := xRefObject{}
|
||||||
xrefEntry.xtype = XREF_TABLE_ENTRY
|
xrefEntry.xtype = xRefTableEntry
|
||||||
xrefEntry.objectNumber = int(objNum)
|
xrefEntry.objectNumber = int(objNum)
|
||||||
xrefEntry.generation = int(genNum)
|
xrefEntry.generation = int(genNum)
|
||||||
xrefEntry.offset = objOffset
|
xrefEntry.offset = objOffset
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ func IsPrintable(char byte) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsDelimiter checks if a character represents a delimiter.
|
// IsDelimiter checks if a character represents a delimiter.
|
||||||
// TODO (v3): Unexport.
|
|
||||||
func IsDelimiter(char byte) bool {
|
func IsDelimiter(char byte) bool {
|
||||||
if char == '(' || char == ')' {
|
if char == '(' || char == ')' {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
package extractor
|
|
||||||
|
|
||||||
var isTesting = false
|
|
||||||
@@ -1619,33 +1619,6 @@ func (pc *PdfColorspaceLab) ImageToRGB(img Image) (Image, error) {
|
|||||||
// ICC Based colors.
|
// ICC Based colors.
|
||||||
// Each component is defined in the range 0.0 - 1.0 where 1.0 is the primary intensity.
|
// Each component is defined in the range 0.0 - 1.0 where 1.0 is the primary intensity.
|
||||||
|
|
||||||
/*
|
|
||||||
type PdfColorICCBased []float64
|
|
||||||
|
|
||||||
func NewPdfColorICCBased(vals []float64) *PdfColorICCBased {
|
|
||||||
color := PdfColorICCBased{}
|
|
||||||
for _, val := range vals {
|
|
||||||
color = append(color, val)
|
|
||||||
}
|
|
||||||
return &color
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *PdfColorICCBased) GetNumComponents() int {
|
|
||||||
return len(*this)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to an integer format.
|
|
||||||
func (this *PdfColorICCBased) ToInteger(bits int) []uint32 {
|
|
||||||
maxVal := math.Pow(2, float64(bits)) - 1
|
|
||||||
ints := []uint32{}
|
|
||||||
for _, val := range *this {
|
|
||||||
ints = append(ints, uint32(maxVal*val))
|
|
||||||
}
|
|
||||||
|
|
||||||
return ints
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// See p. 157 for calculations...
|
// See p. 157 for calculations...
|
||||||
|
|
||||||
// format [/ICCBased stream]
|
// format [/ICCBased stream]
|
||||||
|
|||||||
@@ -157,7 +157,6 @@ func (im *Image) ToGoImage() (goimage.Image, error) {
|
|||||||
aidx := 0
|
aidx := 0
|
||||||
|
|
||||||
samples := im.GetSamples()
|
samples := im.GetSamples()
|
||||||
//bytesPerColor := colorComponents * int(this.BitsPerComponent) / 8
|
|
||||||
bytesPerColor := im.ColorComponents
|
bytesPerColor := im.ColorComponents
|
||||||
for i := 0; i+bytesPerColor-1 < len(samples); i += bytesPerColor {
|
for i := 0; i+bytesPerColor-1 < len(samples); i += bytesPerColor {
|
||||||
var c gocolor.Color
|
var c gocolor.Color
|
||||||
|
|||||||
@@ -37,24 +37,24 @@ func PSObjectArrayToFloat64Array(objects []PSObject) ([]float64, error) {
|
|||||||
return vals, nil
|
return vals, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSExecutor) Execute(objects []PSObject) ([]PSObject, error) {
|
func (pE *PSExecutor) Execute(objects []PSObject) ([]PSObject, error) {
|
||||||
// Add the arguments on stack
|
// Add the arguments on stack
|
||||||
// [obj1 obj2 ...]
|
// [obj1 obj2 ...]
|
||||||
for _, obj := range objects {
|
for _, obj := range objects {
|
||||||
err := this.Stack.Push(obj)
|
err := pE.Stack.Push(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := this.program.Exec(this.Stack)
|
err := pE.program.Exec(pE.Stack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("Exec failed: %v", err)
|
common.Log.Debug("Exec failed: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := []PSObject(*this.Stack)
|
result := []PSObject(*pE.Stack)
|
||||||
this.Stack.Empty()
|
pE.Stack.Empty()
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PSObject interface {
|
type PSObject interface {
|
||||||
@@ -17,18 +18,18 @@ type PSInteger struct {
|
|||||||
Val int
|
Val int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSInteger) Duplicate() PSObject {
|
func (pI *PSInteger) Duplicate() PSObject {
|
||||||
obj := PSInteger{}
|
obj := PSInteger{}
|
||||||
obj.Val = this.Val
|
obj.Val = pI.Val
|
||||||
return &obj
|
return &obj
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSInteger) DebugString() string {
|
func (pI *PSInteger) DebugString() string {
|
||||||
return fmt.Sprintf("int:%d", this.Val)
|
return fmt.Sprintf("int:%d", pI.Val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSInteger) String() string {
|
func (pI *PSInteger) String() string {
|
||||||
return fmt.Sprintf("%d", this.Val)
|
return fmt.Sprintf("%d", pI.Val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Real number.
|
// Real number.
|
||||||
@@ -36,17 +37,17 @@ type PSReal struct {
|
|||||||
Val float64
|
Val float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSReal) DebugString() string {
|
func (pR *PSReal) DebugString() string {
|
||||||
return fmt.Sprintf("real:%.5f", this.Val)
|
return fmt.Sprintf("real:%.5f", pR.Val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSReal) String() string {
|
func (pR *PSReal) String() string {
|
||||||
return fmt.Sprintf("%.5f", this.Val)
|
return fmt.Sprintf("%.5f", pR.Val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSReal) Duplicate() PSObject {
|
func (pR *PSReal) Duplicate() PSObject {
|
||||||
obj := PSReal{}
|
obj := PSReal{}
|
||||||
obj.Val = this.Val
|
obj.Val = pR.Val
|
||||||
return &obj
|
return &obj
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,17 +56,17 @@ type PSBoolean struct {
|
|||||||
Val bool
|
Val bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSBoolean) DebugString() string {
|
func (pB *PSBoolean) DebugString() string {
|
||||||
return fmt.Sprintf("bool:%v", this.Val)
|
return fmt.Sprintf("bool:%v", pB.Val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSBoolean) String() string {
|
func (pB *PSBoolean) String() string {
|
||||||
return fmt.Sprintf("%v", this.Val)
|
return fmt.Sprintf("%v", pB.Val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSBoolean) Duplicate() PSObject {
|
func (pB *PSBoolean) Duplicate() PSObject {
|
||||||
obj := PSBoolean{}
|
obj := PSBoolean{}
|
||||||
obj.Val = this.Val
|
obj.Val = pB.Val
|
||||||
return &obj
|
return &obj
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,42 +77,44 @@ func NewPSProgram() *PSProgram {
|
|||||||
return &PSProgram{}
|
return &PSProgram{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSProgram) Append(obj PSObject) {
|
func (pP *PSProgram) Append(obj PSObject) {
|
||||||
*this = append(*this, obj)
|
*pP = append(*pP, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSProgram) DebugString() string {
|
func (pP *PSProgram) DebugString() string {
|
||||||
s := "{ "
|
var s strings.Builder
|
||||||
for _, obj := range *this {
|
s.WriteString("{ ")
|
||||||
s += obj.DebugString()
|
for _, obj := range *pP {
|
||||||
s += " "
|
s.WriteString(obj.DebugString())
|
||||||
|
s.WriteString(" ")
|
||||||
}
|
}
|
||||||
s += "}"
|
s.WriteString("}")
|
||||||
|
|
||||||
return s
|
return s.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSProgram) String() string {
|
func (pP *PSProgram) String() string {
|
||||||
s := "{ "
|
var s strings.Builder
|
||||||
for _, obj := range *this {
|
s.WriteString("{ ")
|
||||||
s += obj.String()
|
for _, obj := range *pP {
|
||||||
s += " "
|
s.WriteString(obj.String())
|
||||||
|
s.WriteString(" ")
|
||||||
}
|
}
|
||||||
s += "}"
|
s.WriteString("}")
|
||||||
|
|
||||||
return s
|
return s.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSProgram) Duplicate() PSObject {
|
func (pP *PSProgram) Duplicate() PSObject {
|
||||||
prog := &PSProgram{}
|
prog := &PSProgram{}
|
||||||
for _, obj := range *this {
|
for _, obj := range *pP {
|
||||||
prog.Append(obj.Duplicate())
|
prog.Append(obj.Duplicate())
|
||||||
}
|
}
|
||||||
return prog
|
return prog
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSProgram) Exec(stack *PSStack) error {
|
func (pP *PSProgram) Exec(stack *PSStack) error {
|
||||||
for _, obj := range *this {
|
for _, obj := range *pP {
|
||||||
var err error
|
var err error
|
||||||
if number, isInt := obj.(*PSInteger); isInt {
|
if number, isInt := obj.(*PSInteger); isInt {
|
||||||
err = stack.Push(number)
|
err = stack.Push(number)
|
||||||
@@ -136,118 +139,118 @@ func (this *PSProgram) Exec(stack *PSStack) error {
|
|||||||
// Operand.
|
// Operand.
|
||||||
type PSOperand string
|
type PSOperand string
|
||||||
|
|
||||||
func (this *PSOperand) DebugString() string {
|
func (pO *PSOperand) DebugString() string {
|
||||||
return fmt.Sprintf("op:'%s'", *this)
|
return fmt.Sprintf("op:'%s'", *pO)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSOperand) String() string {
|
func (pO *PSOperand) String() string {
|
||||||
return fmt.Sprintf("%s", *this)
|
return fmt.Sprintf("%s", *pO)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSOperand) Duplicate() PSObject {
|
func (pO *PSOperand) Duplicate() PSObject {
|
||||||
s := *this
|
s := *pO
|
||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSOperand) Exec(stack *PSStack) error {
|
func (pO *PSOperand) Exec(stack *PSStack) error {
|
||||||
err := errors.New("Unsupported operand")
|
err := errors.New("Unsupported operand")
|
||||||
switch *this {
|
switch *pO {
|
||||||
case "abs":
|
case "abs":
|
||||||
err = this.Abs(stack)
|
err = pO.Abs(stack)
|
||||||
case "add":
|
case "add":
|
||||||
err = this.Add(stack)
|
err = pO.Add(stack)
|
||||||
case "and":
|
case "and":
|
||||||
err = this.And(stack)
|
err = pO.And(stack)
|
||||||
case "atan":
|
case "atan":
|
||||||
err = this.Atan(stack)
|
err = pO.Atan(stack)
|
||||||
|
|
||||||
case "bitshift":
|
case "bitshift":
|
||||||
err = this.Bitshift(stack)
|
err = pO.Bitshift(stack)
|
||||||
|
|
||||||
case "ceiling":
|
case "ceiling":
|
||||||
err = this.Ceiling(stack)
|
err = pO.Ceiling(stack)
|
||||||
case "copy":
|
case "copy":
|
||||||
err = this.Copy(stack)
|
err = pO.Copy(stack)
|
||||||
case "cos":
|
case "cos":
|
||||||
err = this.Cos(stack)
|
err = pO.Cos(stack)
|
||||||
case "cvi":
|
case "cvi":
|
||||||
err = this.Cvi(stack)
|
err = pO.Cvi(stack)
|
||||||
case "cvr":
|
case "cvr":
|
||||||
err = this.Cvr(stack)
|
err = pO.Cvr(stack)
|
||||||
|
|
||||||
case "div":
|
case "div":
|
||||||
err = this.Div(stack)
|
err = pO.Div(stack)
|
||||||
case "dup":
|
case "dup":
|
||||||
err = this.Dup(stack)
|
err = pO.Dup(stack)
|
||||||
|
|
||||||
case "eq":
|
case "eq":
|
||||||
err = this.Eq(stack)
|
err = pO.Eq(stack)
|
||||||
case "exch":
|
case "exch":
|
||||||
err = this.Exch(stack)
|
err = pO.Exch(stack)
|
||||||
case "exp":
|
case "exp":
|
||||||
err = this.Exp(stack)
|
err = pO.Exp(stack)
|
||||||
|
|
||||||
case "floor":
|
case "floor":
|
||||||
err = this.Floor(stack)
|
err = pO.Floor(stack)
|
||||||
|
|
||||||
case "ge":
|
case "ge":
|
||||||
err = this.Ge(stack)
|
err = pO.Ge(stack)
|
||||||
case "gt":
|
case "gt":
|
||||||
err = this.Gt(stack)
|
err = pO.Gt(stack)
|
||||||
|
|
||||||
case "idiv":
|
case "idiv":
|
||||||
err = this.IDiv(stack)
|
err = pO.IDiv(stack)
|
||||||
case "if":
|
case "if":
|
||||||
err = this.If(stack)
|
err = pO.If(stack)
|
||||||
case "ifelse":
|
case "ifelse":
|
||||||
err = this.IfElse(stack)
|
err = pO.IfElse(stack)
|
||||||
case "index":
|
case "index":
|
||||||
err = this.Index(stack)
|
err = pO.Index(stack)
|
||||||
|
|
||||||
case "le":
|
case "le":
|
||||||
err = this.Le(stack)
|
err = pO.Le(stack)
|
||||||
case "log":
|
case "log":
|
||||||
err = this.Log(stack)
|
err = pO.Log(stack)
|
||||||
case "ln":
|
case "ln":
|
||||||
err = this.Ln(stack)
|
err = pO.Ln(stack)
|
||||||
case "lt":
|
case "lt":
|
||||||
err = this.Lt(stack)
|
err = pO.Lt(stack)
|
||||||
|
|
||||||
case "mod":
|
case "mod":
|
||||||
err = this.Mod(stack)
|
err = pO.Mod(stack)
|
||||||
case "mul":
|
case "mul":
|
||||||
err = this.Mul(stack)
|
err = pO.Mul(stack)
|
||||||
|
|
||||||
case "ne":
|
case "ne":
|
||||||
err = this.Ne(stack)
|
err = pO.Ne(stack)
|
||||||
case "neg":
|
case "neg":
|
||||||
err = this.Neg(stack)
|
err = pO.Neg(stack)
|
||||||
case "not":
|
case "not":
|
||||||
err = this.Not(stack)
|
err = pO.Not(stack)
|
||||||
|
|
||||||
case "or":
|
case "or":
|
||||||
err = this.Or(stack)
|
err = pO.Or(stack)
|
||||||
|
|
||||||
case "pop":
|
case "pop":
|
||||||
err = this.Pop(stack)
|
err = pO.Pop(stack)
|
||||||
|
|
||||||
case "round":
|
case "round":
|
||||||
err = this.Round(stack)
|
err = pO.Round(stack)
|
||||||
case "roll":
|
case "roll":
|
||||||
err = this.Roll(stack)
|
err = pO.Roll(stack)
|
||||||
|
|
||||||
case "sin":
|
case "sin":
|
||||||
err = this.Sin(stack)
|
err = pO.Sin(stack)
|
||||||
case "sqrt":
|
case "sqrt":
|
||||||
err = this.Sqrt(stack)
|
err = pO.Sqrt(stack)
|
||||||
case "sub":
|
case "sub":
|
||||||
err = this.Sub(stack)
|
err = pO.Sub(stack)
|
||||||
|
|
||||||
case "truncate":
|
case "truncate":
|
||||||
err = this.Truncate(stack)
|
err = pO.Truncate(stack)
|
||||||
|
|
||||||
case "xor":
|
case "xor":
|
||||||
err = this.Xor(stack)
|
err = pO.Xor(stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
@@ -257,7 +260,7 @@ func (this *PSOperand) Exec(stack *PSStack) error {
|
|||||||
// Operation implementations
|
// Operation implementations
|
||||||
|
|
||||||
// Absolute value.
|
// Absolute value.
|
||||||
func (this *PSOperand) Abs(stack *PSStack) error {
|
func (*PSOperand) Abs(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -285,7 +288,7 @@ func (this *PSOperand) Abs(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5 27 add -> 32
|
// 5 27 add -> 32
|
||||||
func (this *PSOperand) Add(stack *PSStack) error {
|
func (*PSOperand) Add(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -338,7 +341,7 @@ func (this *PSOperand) Add(stack *PSStack) error {
|
|||||||
// bool1 bool2 and -> bool3
|
// bool1 bool2 and -> bool3
|
||||||
// if int: returns the bitwise "and" of the inputs
|
// if int: returns the bitwise "and" of the inputs
|
||||||
// int1 int2 and -> int3
|
// int1 int2 and -> int3
|
||||||
func (this *PSOperand) And(stack *PSStack) error {
|
func (*PSOperand) And(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -374,7 +377,7 @@ func (this *PSOperand) And(stack *PSStack) error {
|
|||||||
|
|
||||||
// den num atan -> atan(num/den) in degrees.
|
// den num atan -> atan(num/den) in degrees.
|
||||||
// result is a real value.
|
// result is a real value.
|
||||||
func (this *PSOperand) Atan(stack *PSStack) error {
|
func (*PSOperand) Atan(stack *PSStack) error {
|
||||||
// Denominator
|
// Denominator
|
||||||
den, err := stack.PopNumberAsFloat64()
|
den, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -409,7 +412,7 @@ func (this *PSOperand) Atan(stack *PSStack) error {
|
|||||||
|
|
||||||
// bitshift
|
// bitshift
|
||||||
// int1 shift bitshift -> int2
|
// int1 shift bitshift -> int2
|
||||||
func (this *PSOperand) Bitshift(stack *PSStack) error {
|
func (*PSOperand) Bitshift(stack *PSStack) error {
|
||||||
shift, err := stack.PopInteger()
|
shift, err := stack.PopInteger()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -435,7 +438,7 @@ func (this *PSOperand) Bitshift(stack *PSStack) error {
|
|||||||
// Ceiling of number.
|
// Ceiling of number.
|
||||||
// num1 ceiling -> num2
|
// num1 ceiling -> num2
|
||||||
// The type of the result is the same as of the operand.
|
// The type of the result is the same as of the operand.
|
||||||
func (this *PSOperand) Ceiling(stack *PSStack) error {
|
func (*PSOperand) Ceiling(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -454,7 +457,7 @@ func (this *PSOperand) Ceiling(stack *PSStack) error {
|
|||||||
|
|
||||||
// Copy
|
// Copy
|
||||||
// any1 ... anyn n copy -> any1 ... anyn any1 ... anyn
|
// any1 ... anyn n copy -> any1 ... anyn any1 ... anyn
|
||||||
func (this *PSOperand) Copy(stack *PSStack) error {
|
func (*PSOperand) Copy(stack *PSStack) error {
|
||||||
n, err := stack.PopInteger()
|
n, err := stack.PopInteger()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -475,7 +478,7 @@ func (this *PSOperand) Copy(stack *PSStack) error {
|
|||||||
// Cosine
|
// Cosine
|
||||||
// angle cos -> real
|
// angle cos -> real
|
||||||
// Angle is in degrees
|
// Angle is in degrees
|
||||||
func (this *PSOperand) Cos(stack *PSStack) error {
|
func (*PSOperand) Cos(stack *PSStack) error {
|
||||||
angle, err := stack.PopNumberAsFloat64()
|
angle, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -487,7 +490,7 @@ func (this *PSOperand) Cos(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert to integer
|
// Convert to integer
|
||||||
func (this *PSOperand) Cvi(stack *PSStack) error {
|
func (*PSOperand) Cvi(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -507,7 +510,7 @@ func (this *PSOperand) Cvi(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert number tor real
|
// Convert number tor real
|
||||||
func (this *PSOperand) Cvr(stack *PSStack) error {
|
func (*PSOperand) Cvr(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -524,7 +527,7 @@ func (this *PSOperand) Cvr(stack *PSStack) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSOperand) Div(stack *PSStack) error {
|
func (*PSOperand) Div(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -573,7 +576,7 @@ func (this *PSOperand) Div(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Duplicates the top object on the stack (dup)
|
// Duplicates the top object on the stack (dup)
|
||||||
func (this *PSOperand) Dup(stack *PSStack) error {
|
func (*PSOperand) Dup(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -591,7 +594,7 @@ func (this *PSOperand) Dup(stack *PSStack) error {
|
|||||||
|
|
||||||
// Check for equality.
|
// Check for equality.
|
||||||
// any1 any2 eq bool
|
// any1 any2 eq bool
|
||||||
func (this *PSOperand) Eq(stack *PSStack) error {
|
func (*PSOperand) Eq(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -646,7 +649,7 @@ func (this *PSOperand) Eq(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exchange the top two elements of the stack (exch)
|
// Exchange the top two elements of the stack (exch)
|
||||||
func (this *PSOperand) Exch(stack *PSStack) error {
|
func (*PSOperand) Exch(stack *PSStack) error {
|
||||||
top, err := stack.Pop()
|
top, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -669,7 +672,7 @@ func (this *PSOperand) Exch(stack *PSStack) error {
|
|||||||
// base exponent exp -> base^exp
|
// base exponent exp -> base^exp
|
||||||
// Raises base to exponent power.
|
// Raises base to exponent power.
|
||||||
// The result is a real number.
|
// The result is a real number.
|
||||||
func (this *PSOperand) Exp(stack *PSStack) error {
|
func (*PSOperand) Exp(stack *PSStack) error {
|
||||||
exponent, err := stack.PopNumberAsFloat64()
|
exponent, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -691,7 +694,7 @@ func (this *PSOperand) Exp(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Floor of number.
|
// Floor of number.
|
||||||
func (this *PSOperand) Floor(stack *PSStack) error {
|
func (*PSOperand) Floor(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -710,7 +713,7 @@ func (this *PSOperand) Floor(stack *PSStack) error {
|
|||||||
|
|
||||||
// Greater than or equal
|
// Greater than or equal
|
||||||
// num1 num2 ge -> bool; num1 >= num2
|
// num1 num2 ge -> bool; num1 >= num2
|
||||||
func (this *PSOperand) Ge(stack *PSStack) error {
|
func (*PSOperand) Ge(stack *PSStack) error {
|
||||||
num2, err := stack.PopNumberAsFloat64()
|
num2, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -736,7 +739,7 @@ func (this *PSOperand) Ge(stack *PSStack) error {
|
|||||||
|
|
||||||
// Greater than
|
// Greater than
|
||||||
// num1 num2 gt -> bool; num1 > num2
|
// num1 num2 gt -> bool; num1 > num2
|
||||||
func (this *PSOperand) Gt(stack *PSStack) error {
|
func (*PSOperand) Gt(stack *PSStack) error {
|
||||||
num2, err := stack.PopNumberAsFloat64()
|
num2, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -762,7 +765,7 @@ func (this *PSOperand) Gt(stack *PSStack) error {
|
|||||||
|
|
||||||
// Integral division
|
// Integral division
|
||||||
// 25 3 div -> 8
|
// 25 3 div -> 8
|
||||||
func (this *PSOperand) IDiv(stack *PSStack) error {
|
func (*PSOperand) IDiv(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -794,7 +797,7 @@ func (this *PSOperand) IDiv(stack *PSStack) error {
|
|||||||
|
|
||||||
// If conditional
|
// If conditional
|
||||||
// bool proc if -> run proc() if bool is true
|
// bool proc if -> run proc() if bool is true
|
||||||
func (this *PSOperand) If(stack *PSStack) error {
|
func (*PSOperand) If(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -825,7 +828,7 @@ func (this *PSOperand) If(stack *PSStack) error {
|
|||||||
|
|
||||||
// If else conditional
|
// If else conditional
|
||||||
// bool proc1 proc2 ifelse -> execute proc1() if bool is true, otherwise proc2()
|
// bool proc1 proc2 ifelse -> execute proc1() if bool is true, otherwise proc2()
|
||||||
func (this *PSOperand) IfElse(stack *PSStack) error {
|
func (*PSOperand) IfElse(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -866,7 +869,7 @@ func (this *PSOperand) IfElse(stack *PSStack) error {
|
|||||||
// Add a copy of the nth object in the stack to the top.
|
// Add a copy of the nth object in the stack to the top.
|
||||||
// any_n ... any_0 n index -> any_n ... any_0 any_n
|
// any_n ... any_0 n index -> any_n ... any_0 any_n
|
||||||
// index from 0
|
// index from 0
|
||||||
func (this *PSOperand) Index(stack *PSStack) error {
|
func (*PSOperand) Index(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -893,7 +896,7 @@ func (this *PSOperand) Index(stack *PSStack) error {
|
|||||||
|
|
||||||
// Less or equal
|
// Less or equal
|
||||||
// num1 num2 le -> bool; num1 <= num2
|
// num1 num2 le -> bool; num1 <= num2
|
||||||
func (this *PSOperand) Le(stack *PSStack) error {
|
func (*PSOperand) Le(stack *PSStack) error {
|
||||||
num2, err := stack.PopNumberAsFloat64()
|
num2, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -918,7 +921,7 @@ func (this *PSOperand) Le(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// num log -> real
|
// num log -> real
|
||||||
func (this *PSOperand) Log(stack *PSStack) error {
|
func (*PSOperand) Log(stack *PSStack) error {
|
||||||
// Value
|
// Value
|
||||||
val, err := stack.PopNumberAsFloat64()
|
val, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -932,7 +935,7 @@ func (this *PSOperand) Log(stack *PSStack) error {
|
|||||||
|
|
||||||
// num ln -> ln(num)
|
// num ln -> ln(num)
|
||||||
// The result is a real number.
|
// The result is a real number.
|
||||||
func (this *PSOperand) Ln(stack *PSStack) error {
|
func (*PSOperand) Ln(stack *PSStack) error {
|
||||||
// Value
|
// Value
|
||||||
val, err := stack.PopNumberAsFloat64()
|
val, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -946,7 +949,7 @@ func (this *PSOperand) Ln(stack *PSStack) error {
|
|||||||
|
|
||||||
// Less than
|
// Less than
|
||||||
// num1 num2 lt -> bool; num1 < num2
|
// num1 num2 lt -> bool; num1 < num2
|
||||||
func (this *PSOperand) Lt(stack *PSStack) error {
|
func (*PSOperand) Lt(stack *PSStack) error {
|
||||||
num2, err := stack.PopNumberAsFloat64()
|
num2, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -971,7 +974,7 @@ func (this *PSOperand) Lt(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 12 10 mod -> 2
|
// 12 10 mod -> 2
|
||||||
func (this *PSOperand) Mod(stack *PSStack) error {
|
func (*PSOperand) Mod(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1001,7 +1004,7 @@ func (this *PSOperand) Mod(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 6 8 mul -> 48
|
// 6 8 mul -> 48
|
||||||
func (this *PSOperand) Mul(stack *PSStack) error {
|
func (*PSOperand) Mul(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1051,21 +1054,21 @@ func (this *PSOperand) Mul(stack *PSStack) error {
|
|||||||
|
|
||||||
// Not equal (inverse of eq)
|
// Not equal (inverse of eq)
|
||||||
// any1 any2 ne -> bool
|
// any1 any2 ne -> bool
|
||||||
func (this *PSOperand) Ne(stack *PSStack) error {
|
func (pO *PSOperand) Ne(stack *PSStack) error {
|
||||||
// Simply call equate and then negate the result.
|
// Simply call equate and then negate the result.
|
||||||
// Implementing directly could be more efficient, but probably not a big deal in most cases.
|
// Implementing directly could be more efficient, but probably not a big deal in most cases.
|
||||||
err := this.Eq(stack)
|
err := pO.Eq(stack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = this.Not(stack)
|
err = pO.Not(stack)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Negate
|
// Negate
|
||||||
// 6 neg -> -6
|
// 6 neg -> -6
|
||||||
func (this *PSOperand) Neg(stack *PSStack) error {
|
func (*PSOperand) Neg(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1086,7 +1089,7 @@ func (this *PSOperand) Neg(stack *PSStack) error {
|
|||||||
// Logical/bitwise negation
|
// Logical/bitwise negation
|
||||||
// bool1 not -> bool2 (logical)
|
// bool1 not -> bool2 (logical)
|
||||||
// int1 not -> int2 (bitwise)
|
// int1 not -> int2 (bitwise)
|
||||||
func (this *PSOperand) Not(stack *PSStack) error {
|
func (*PSOperand) Not(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1106,7 +1109,7 @@ func (this *PSOperand) Not(stack *PSStack) error {
|
|||||||
// OR logical/bitwise operation.
|
// OR logical/bitwise operation.
|
||||||
// bool1 bool2 or -> bool3 (logical or)
|
// bool1 bool2 or -> bool3 (logical or)
|
||||||
// int1 int2 or -> int3 (bitwise or)
|
// int1 int2 or -> int3 (bitwise or)
|
||||||
func (this *PSOperand) Or(stack *PSStack) error {
|
func (*PSOperand) Or(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1141,7 +1144,7 @@ func (this *PSOperand) Or(stack *PSStack) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove the top element on the stack (pop)
|
// Remove the top element on the stack (pop)
|
||||||
func (this *PSOperand) Pop(stack *PSStack) error {
|
func (*PSOperand) Pop(stack *PSStack) error {
|
||||||
_, err := stack.Pop()
|
_, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1151,7 +1154,7 @@ func (this *PSOperand) Pop(stack *PSStack) error {
|
|||||||
|
|
||||||
// Round number off.
|
// Round number off.
|
||||||
// num1 round -> num2
|
// num1 round -> num2
|
||||||
func (this *PSOperand) Round(stack *PSStack) error {
|
func (*PSOperand) Round(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1173,7 +1176,7 @@ func (this *PSOperand) Round(stack *PSStack) error {
|
|||||||
// 7 8 9 3 1 roll -> 9 7 8
|
// 7 8 9 3 1 roll -> 9 7 8
|
||||||
// 7 8 9 3 -1 roll -> 8 9 7
|
// 7 8 9 3 -1 roll -> 8 9 7
|
||||||
// n j roll
|
// n j roll
|
||||||
func (this *PSOperand) Roll(stack *PSStack) error {
|
func (*PSOperand) Roll(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1228,7 +1231,7 @@ func (this *PSOperand) Roll(stack *PSStack) error {
|
|||||||
// Sine.
|
// Sine.
|
||||||
// angle sin -> real
|
// angle sin -> real
|
||||||
// Angle is in degrees
|
// Angle is in degrees
|
||||||
func (this *PSOperand) Sin(stack *PSStack) error {
|
func (*PSOperand) Sin(stack *PSStack) error {
|
||||||
angle, err := stack.PopNumberAsFloat64()
|
angle, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1242,7 +1245,7 @@ func (this *PSOperand) Sin(stack *PSStack) error {
|
|||||||
// Square root.
|
// Square root.
|
||||||
// num sqrt -> real; real=sqrt(num)
|
// num sqrt -> real; real=sqrt(num)
|
||||||
// The result is a real number.
|
// The result is a real number.
|
||||||
func (this *PSOperand) Sqrt(stack *PSStack) error {
|
func (*PSOperand) Sqrt(stack *PSStack) error {
|
||||||
val, err := stack.PopNumberAsFloat64()
|
val, err := stack.PopNumberAsFloat64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1260,7 +1263,7 @@ func (this *PSOperand) Sqrt(stack *PSStack) error {
|
|||||||
// 8.3 6.6 sub -> 1.7 (real)
|
// 8.3 6.6 sub -> 1.7 (real)
|
||||||
// 8 6.3 sub -> 1.7 (real)
|
// 8 6.3 sub -> 1.7 (real)
|
||||||
// 8 6 sub -> 2 (int)
|
// 8 6 sub -> 2 (int)
|
||||||
func (this *PSOperand) Sub(stack *PSStack) error {
|
func (*PSOperand) Sub(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1311,7 +1314,7 @@ func (this *PSOperand) Sub(stack *PSStack) error {
|
|||||||
// Truncate number.
|
// Truncate number.
|
||||||
// num1 truncate -> num2
|
// num1 truncate -> num2
|
||||||
// The resulting number is the same type as the input.
|
// The resulting number is the same type as the input.
|
||||||
func (this *PSOperand) Truncate(stack *PSStack) error {
|
func (*PSOperand) Truncate(stack *PSStack) error {
|
||||||
obj, err := stack.Pop()
|
obj, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1332,7 +1335,7 @@ func (this *PSOperand) Truncate(stack *PSStack) error {
|
|||||||
// XOR logical/bitwise operation.
|
// XOR logical/bitwise operation.
|
||||||
// bool1 bool2 xor -> bool3 (logical xor)
|
// bool1 bool2 xor -> bool3 (logical xor)
|
||||||
// int1 int2 xor -> int3 (bitwise xor)
|
// int1 int2 xor -> int3 (bitwise xor)
|
||||||
func (this *PSOperand) Xor(stack *PSStack) error {
|
func (*PSOperand) Xor(stack *PSStack) error {
|
||||||
obj1, err := stack.Pop()
|
obj1, err := stack.Pop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ func NewPSParser(content []byte) *PSParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse the postscript and store as a program that can be executed.
|
// Parse the postscript and store as a program that can be executed.
|
||||||
func (this *PSParser) Parse() (*PSProgram, error) {
|
func (pP *PSParser) Parse() (*PSProgram, error) {
|
||||||
this.skipSpaces()
|
pP.skipSpaces()
|
||||||
bb, err := this.reader.Peek(2)
|
bb, err := pP.reader.Peek(2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ func (this *PSParser) Parse() (*PSProgram, error) {
|
|||||||
return nil, fmt.Errorf("invalid PS Program not starting with {")
|
return nil, fmt.Errorf("invalid PS Program not starting with {")
|
||||||
}
|
}
|
||||||
|
|
||||||
program, err := this.parseFunction()
|
program, err := pP.parseFunction()
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -48,8 +48,8 @@ func (this *PSParser) Parse() (*PSProgram, error) {
|
|||||||
|
|
||||||
// Detect the signature at the current parse position and parse
|
// Detect the signature at the current parse position and parse
|
||||||
// the corresponding object.
|
// the corresponding object.
|
||||||
func (this *PSParser) parseFunction() (*PSProgram, error) {
|
func (pP *PSParser) parseFunction() (*PSProgram, error) {
|
||||||
c, _ := this.reader.ReadByte()
|
c, _ := pP.reader.ReadByte()
|
||||||
if c != '{' {
|
if c != '{' {
|
||||||
return nil, errors.New("invalid function")
|
return nil, errors.New("invalid function")
|
||||||
}
|
}
|
||||||
@@ -57,8 +57,8 @@ func (this *PSParser) parseFunction() (*PSProgram, error) {
|
|||||||
function := NewPSProgram()
|
function := NewPSProgram()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
this.skipSpaces()
|
pP.skipSpaces()
|
||||||
bb, err := this.reader.Peek(2)
|
bb, err := pP.reader.Peek(2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
@@ -70,18 +70,18 @@ func (this *PSParser) parseFunction() (*PSProgram, error) {
|
|||||||
// Determine type.
|
// Determine type.
|
||||||
if bb[0] == '}' {
|
if bb[0] == '}' {
|
||||||
common.Log.Trace("EOF function")
|
common.Log.Trace("EOF function")
|
||||||
this.reader.ReadByte()
|
pP.reader.ReadByte()
|
||||||
break
|
break
|
||||||
} else if bb[0] == '{' {
|
} else if bb[0] == '{' {
|
||||||
common.Log.Trace("Function!")
|
common.Log.Trace("Function!")
|
||||||
inlineF, err := this.parseFunction()
|
inlineF, err := pP.parseFunction()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
function.Append(inlineF)
|
function.Append(inlineF)
|
||||||
} else if pdfcore.IsDecimalDigit(bb[0]) || (bb[0] == '-' && pdfcore.IsDecimalDigit(bb[1])) {
|
} else if pdfcore.IsDecimalDigit(bb[0]) || (bb[0] == '-' && pdfcore.IsDecimalDigit(bb[1])) {
|
||||||
common.Log.Trace("->Number!")
|
common.Log.Trace("->Number!")
|
||||||
number, err := this.parseNumber()
|
number, err := pP.parseNumber()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -89,24 +89,24 @@ func (this *PSParser) parseFunction() (*PSProgram, error) {
|
|||||||
} else {
|
} else {
|
||||||
common.Log.Trace("->Operand or bool?")
|
common.Log.Trace("->Operand or bool?")
|
||||||
// Let's peek farther to find out.
|
// Let's peek farther to find out.
|
||||||
bb, _ = this.reader.Peek(5)
|
bb, _ = pP.reader.Peek(5)
|
||||||
peekStr := string(bb)
|
peekStr := string(bb)
|
||||||
common.Log.Trace("Peek str: %s", peekStr)
|
common.Log.Trace("Peek str: %s", peekStr)
|
||||||
|
|
||||||
if (len(peekStr) > 4) && (peekStr[:5] == "false") {
|
if (len(peekStr) > 4) && (peekStr[:5] == "false") {
|
||||||
b, err := this.parseBool()
|
b, err := pP.parseBool()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
function.Append(b)
|
function.Append(b)
|
||||||
} else if (len(peekStr) > 3) && (peekStr[:4] == "true") {
|
} else if (len(peekStr) > 3) && (peekStr[:4] == "true") {
|
||||||
b, err := this.parseBool()
|
b, err := pP.parseBool()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
function.Append(b)
|
function.Append(b)
|
||||||
} else {
|
} else {
|
||||||
operand, err := this.parseOperand()
|
operand, err := pP.parseOperand()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -120,15 +120,15 @@ func (this *PSParser) parseFunction() (*PSProgram, error) {
|
|||||||
|
|
||||||
// Skip over any spaces. Returns the number of spaces skipped and
|
// Skip over any spaces. Returns the number of spaces skipped and
|
||||||
// an error if any.
|
// an error if any.
|
||||||
func (this *PSParser) skipSpaces() (int, error) {
|
func (pP *PSParser) skipSpaces() (int, error) {
|
||||||
cnt := 0
|
cnt := 0
|
||||||
for {
|
for {
|
||||||
bb, err := this.reader.Peek(1)
|
bb, err := pP.reader.Peek(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if pdfcore.IsWhiteSpace(bb[0]) {
|
if pdfcore.IsWhiteSpace(bb[0]) {
|
||||||
this.reader.ReadByte()
|
pP.reader.ReadByte()
|
||||||
cnt++
|
cnt++
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
@@ -140,13 +140,13 @@ func (this *PSParser) skipSpaces() (int, error) {
|
|||||||
|
|
||||||
// Numeric objects.
|
// Numeric objects.
|
||||||
// Integer or Real numbers.
|
// Integer or Real numbers.
|
||||||
func (this *PSParser) parseNumber() (PSObject, error) {
|
func (pP *PSParser) parseNumber() (PSObject, error) {
|
||||||
isFloat := false
|
isFloat := false
|
||||||
allowSigns := true
|
allowSigns := true
|
||||||
numStr := ""
|
numStr := ""
|
||||||
for {
|
for {
|
||||||
common.Log.Trace("Parsing number \"%s\"", numStr)
|
common.Log.Trace("Parsing number \"%s\"", numStr)
|
||||||
bb, err := this.reader.Peek(1)
|
bb, err := pP.reader.Peek(1)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
// GH: EOF handling. Handle EOF like end of line. Can happen with
|
// GH: EOF handling. Handle EOF like end of line. Can happen with
|
||||||
// encoded object streams that the object is at the end.
|
// encoded object streams that the object is at the end.
|
||||||
@@ -159,20 +159,20 @@ func (this *PSParser) parseNumber() (PSObject, error) {
|
|||||||
}
|
}
|
||||||
if allowSigns && (bb[0] == '-' || bb[0] == '+') {
|
if allowSigns && (bb[0] == '-' || bb[0] == '+') {
|
||||||
// Only appear in the beginning, otherwise serves as a delimiter.
|
// Only appear in the beginning, otherwise serves as a delimiter.
|
||||||
b, _ := this.reader.ReadByte()
|
b, _ := pP.reader.ReadByte()
|
||||||
numStr += string(b)
|
numStr += string(b)
|
||||||
allowSigns = false // Only allowed in beginning, and after e (exponential).
|
allowSigns = false // Only allowed in beginning, and after e (exponential).
|
||||||
} else if pdfcore.IsDecimalDigit(bb[0]) {
|
} else if pdfcore.IsDecimalDigit(bb[0]) {
|
||||||
b, _ := this.reader.ReadByte()
|
b, _ := pP.reader.ReadByte()
|
||||||
numStr += string(b)
|
numStr += string(b)
|
||||||
} else if bb[0] == '.' {
|
} else if bb[0] == '.' {
|
||||||
b, _ := this.reader.ReadByte()
|
b, _ := pP.reader.ReadByte()
|
||||||
numStr += string(b)
|
numStr += string(b)
|
||||||
isFloat = true
|
isFloat = true
|
||||||
} else if bb[0] == 'e' {
|
} else if bb[0] == 'e' {
|
||||||
// Exponential number format.
|
// Exponential number format.
|
||||||
// XXX Is this supported in PS?
|
// XXX Is this supported in PS?
|
||||||
b, _ := this.reader.ReadByte()
|
b, _ := pP.reader.ReadByte()
|
||||||
numStr += string(b)
|
numStr += string(b)
|
||||||
isFloat = true
|
isFloat = true
|
||||||
allowSigns = true
|
allowSigns = true
|
||||||
@@ -193,22 +193,22 @@ func (this *PSParser) parseNumber() (PSObject, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse bool object.
|
// Parse bool object.
|
||||||
func (this *PSParser) parseBool() (*PSBoolean, error) {
|
func (pP *PSParser) parseBool() (*PSBoolean, error) {
|
||||||
bb, err := this.reader.Peek(4)
|
bb, err := pP.reader.Peek(4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return MakeBool(false), err
|
return MakeBool(false), err
|
||||||
}
|
}
|
||||||
if (len(bb) >= 4) && (string(bb[:4]) == "true") {
|
if (len(bb) >= 4) && (string(bb[:4]) == "true") {
|
||||||
this.reader.Discard(4)
|
pP.reader.Discard(4)
|
||||||
return MakeBool(true), nil
|
return MakeBool(true), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
bb, err = this.reader.Peek(5)
|
bb, err = pP.reader.Peek(5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return MakeBool(false), err
|
return MakeBool(false), err
|
||||||
}
|
}
|
||||||
if (len(bb) >= 5) && (string(bb[:5]) == "false") {
|
if (len(bb) >= 5) && (string(bb[:5]) == "false") {
|
||||||
this.reader.Discard(5)
|
pP.reader.Discard(5)
|
||||||
return MakeBool(false), nil
|
return MakeBool(false), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,10 +216,10 @@ func (this *PSParser) parseBool() (*PSBoolean, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// An operand is a text command represented by a word.
|
// An operand is a text command represented by a word.
|
||||||
func (this *PSParser) parseOperand() (*PSOperand, error) {
|
func (pP *PSParser) parseOperand() (*PSOperand, error) {
|
||||||
bytes := []byte{}
|
bytes := []byte{}
|
||||||
for {
|
for {
|
||||||
bb, err := this.reader.Peek(1)
|
bb, err := pP.reader.Peek(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
@@ -233,7 +233,7 @@ func (this *PSParser) parseOperand() (*PSOperand, error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
b, _ := this.reader.ReadByte()
|
b, _ := pP.reader.ReadByte()
|
||||||
bytes = append(bytes, b)
|
bytes = append(bytes, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package ps
|
package ps
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
type PSStack []PSObject
|
type PSStack []PSObject
|
||||||
|
|
||||||
func NewPSStack() *PSStack {
|
func NewPSStack() *PSStack {
|
||||||
@@ -60,24 +62,26 @@ func (stack *PSStack) PopNumberAsFloat64() (float64, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSStack) String() string {
|
func (pS *PSStack) String() string {
|
||||||
s := "[ "
|
var s strings.Builder
|
||||||
for _, obj := range *this {
|
s.WriteString("[ ")
|
||||||
s += obj.String()
|
for _, obj := range *pS {
|
||||||
s += " "
|
s.WriteString(obj.String())
|
||||||
|
s.WriteString(" ")
|
||||||
}
|
}
|
||||||
s += "]"
|
s.WriteString("]")
|
||||||
|
|
||||||
return s
|
return s.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *PSStack) DebugString() string {
|
func (pS *PSStack) DebugString() string {
|
||||||
s := "[ "
|
var s strings.Builder
|
||||||
for _, obj := range *this {
|
s.WriteString("[ ")
|
||||||
s += obj.DebugString()
|
for _, obj := range *pS {
|
||||||
s += " "
|
s.WriteString(obj.DebugString())
|
||||||
|
s.WriteString(" ")
|
||||||
}
|
}
|
||||||
s += "]"
|
s.WriteString("]")
|
||||||
|
|
||||||
return s
|
return s.String()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user