Skip to content

Commit 967c250

Browse files
committed
Correct name parsing (#69)
1 parent 067897d commit 967c250

File tree

11 files changed

+84
-25
lines changed

11 files changed

+84
-25
lines changed

pkg/pdfcpu/parse.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package pdfcpu
1818

1919
import (
20+
"encoding/hex"
2021
"strconv"
2122
"strings"
2223
"unicode"
@@ -432,6 +433,34 @@ func parseHexLiteral(line *string) (Object, error) {
432433
return HexLiteral(*hexStr), nil
433434
}
434435

436+
func validateNameHexSequence(s string) error {
437+
438+
for i := 0; i < len(s); {
439+
c := s[i]
440+
if c != '#' {
441+
i++
442+
continue
443+
}
444+
445+
// # detected, next 2 chars have to exist.
446+
if len(s) < i+3 {
447+
return errNameObjectCorrupt
448+
}
449+
450+
s1 := s[i+1 : i+3]
451+
452+
// And they have to be hex characters.
453+
_, err := hex.DecodeString(s1)
454+
if err != nil {
455+
return errNameObjectCorrupt
456+
}
457+
458+
i += 3
459+
}
460+
461+
return nil
462+
}
463+
435464
func parseName(line *string) (*Name, error) {
436465

437466
// see 7.3.5
@@ -461,6 +490,12 @@ func parseName(line *string) (*Name, error) {
461490
l = l[:eok]
462491
}
463492

493+
// Validate optional #xx sequences
494+
err := validateNameHexSequence(l)
495+
if err != nil {
496+
return nil, err
497+
}
498+
464499
nameObj := Name(l)
465500
return &nameObj, nil
466501
}

pkg/pdfcpu/parse_common_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ func TestParseObject(t *testing.T) {
6161
doTestParseObjectOK("<</Key/Value>>", t)
6262
doTestParseObjectOK("<</Key[/Val1/Val2\x0d%gopher\x0atrue]>>", t)
6363
doTestParseObjectOK("[<</k1[/name1]>><</k1[false true null]>>]", t)
64-
doTestParseObjectOK("/Name", t)
64+
doTestParseObjectOK("/Name ", t)
65+
doTestParseObjectFail("/Na#me", t)
66+
doTestParseObjectFail("/Na#2me", t)
67+
doTestParseObjectOK("/Na#20me", t)
6568
doTestParseObjectOK("[null]abc", t)
6669

6770
doTestParseObjectFail("/", t)

pkg/pdfcpu/read.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ func buildFilterPipeline(ctx *Context, filterArray, decodeParmsArr Array, decode
12861286
return nil, errors.New("buildFilterPipeline: FilterArray elements corrupt")
12871287
}
12881288
if decodeParms == nil || decodeParmsArr[i] == nil {
1289-
filterPipeline = append(filterPipeline, PDFFilter{Name: filterName.String(), DecodeParms: nil})
1289+
filterPipeline = append(filterPipeline, PDFFilter{Name: filterName.Value(), DecodeParms: nil})
12901290
continue
12911291
}
12921292

pkg/pdfcpu/resources.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (fo FontObject) Encoding() string {
7171
if found {
7272
switch enc := pdfObject.(type) {
7373
case Name:
74-
encoding = enc.String()
74+
encoding = enc.Value()
7575
default:
7676
encoding = "Custom"
7777
}

pkg/pdfcpu/types.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package pdfcpu
1818

1919
import (
20+
"bytes"
2021
"encoding/hex"
2122
"fmt"
2223
"io"
@@ -228,7 +229,27 @@ func (nameObject Name) PDFString() string {
228229

229230
// Value returns a string value for this PDF object.
230231
func (nameObject Name) Value() string {
231-
return string(nameObject)
232+
233+
s := string(nameObject)
234+
var b bytes.Buffer
235+
236+
for i := 0; i < len(s); {
237+
c := s[i]
238+
if c != '#' {
239+
b.WriteByte(c)
240+
i++
241+
continue
242+
}
243+
244+
// # detected, next 2 chars have to exist.
245+
// This gets checked during parsing.
246+
s1 := s[i+1 : i+3]
247+
b1, _ := hex.DecodeString(s1)
248+
b.WriteByte(b1[0])
249+
i += 3
250+
}
251+
252+
return b.String()
232253
}
233254

234255
///////////////////////////////////////////////////////////////////////////////////

pkg/pdfcpu/validate/colorspace.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ func validateColorSpace(xRefTable *pdf.XRefTable, o pdf.Object, excludePatternCS
571571

572572
case pdf.Name:
573573
validateSpecialColorSpaceName := func(s string) bool { return pdf.MemberOf(s, []string{"Pattern"}) }
574-
if ok := validateDeviceColorSpaceName(o.String()) || validateSpecialColorSpaceName(o.String()); !ok {
574+
if ok := validateDeviceColorSpaceName(o.Value()) || validateSpecialColorSpaceName(o.Value()); !ok {
575575
err = errors.Errorf("validateColorSpace: invalid device color space name: %v\n", o)
576576
}
577577

@@ -596,8 +596,8 @@ func validateColorSpaceEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName stri
596596
switch o := o.(type) {
597597

598598
case pdf.Name:
599-
if ok := validateDeviceColorSpaceName(o.String()); !ok {
600-
err = errors.Errorf("validateColorSpaceEntry: Name:%s\n", o.String())
599+
if ok := validateDeviceColorSpaceName(o.Value()); !ok {
600+
err = errors.Errorf("validateColorSpaceEntry: Name:%s\n", o.Value())
601601
}
602602

603603
case pdf.Array:

pkg/pdfcpu/validate/extGState.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func validateBG2Entry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, ent
5959
switch o := o.(type) {
6060

6161
case pdf.Name:
62-
s := o.String()
62+
s := o.Value()
6363
if s != "Default" {
6464
err = errors.New("writeBG2Entry: corrupt name")
6565
}
@@ -88,7 +88,7 @@ func validateUCR2Entry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string, en
8888
switch o := o.(type) {
8989

9090
case pdf.Name:
91-
s := o.String()
91+
s := o.Value()
9292
if s != "Default" {
9393
err = errors.New("writeUCR2Entry: corrupt name")
9494
}
@@ -112,7 +112,7 @@ func validateTransferFunction(xRefTable *pdf.XRefTable, o pdf.Object) (err error
112112
switch o := o.(type) {
113113

114114
case pdf.Name:
115-
s := o.String()
115+
s := o.Value()
116116
if s != "Identity" {
117117
return errors.New("validateTransferFunction: corrupt name")
118118
}
@@ -169,7 +169,7 @@ func validateTR2(xRefTable *pdf.XRefTable, o pdf.Object) (err error) {
169169
switch o := o.(type) {
170170

171171
case pdf.Name:
172-
s := o.String()
172+
s := o.Value()
173173
if s != "Identity" && s != "Default" {
174174
return errors.Errorf("validateTR2: corrupt name\n")
175175
}
@@ -238,7 +238,7 @@ func validateSpotFunctionEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName st
238238
"Double", "InvertedDouble", "Line", "LineX", "LineY", "Round", "Ellipse", "EllipseA",
239239
"InvertedEllipseA", "EllipseB", "EllipseC", "InvertedEllipseC", "Square", "Cross", "Rhomboid"})
240240
}
241-
s := o.String()
241+
s := o.Value()
242242
if !validateSpotFunctionName(s) {
243243
return errors.Errorf("validateSpotFunctionEntry: corrupt name\n")
244244
}
@@ -470,7 +470,7 @@ func validateHalfToneEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string
470470
switch o := o.(type) {
471471

472472
case pdf.Name:
473-
if o.String() != "Default" {
473+
if o.Value() != "Default" {
474474
return errors.Errorf("validateHalfToneEntry: undefined name: %s\n", o)
475475
}
476476

@@ -528,7 +528,7 @@ func validateSoftMaskTransferFunctionEntry(xRefTable *pdf.XRefTable, d pdf.Dict,
528528
switch o := o.(type) {
529529

530530
case pdf.Name:
531-
s := o.String()
531+
s := o.Value()
532532
if s != "Identity" {
533533
return errors.New("validateSoftMaskTransferFunctionEntry: corrupt name")
534534
}
@@ -609,7 +609,7 @@ func validateSoftMaskEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string
609609
switch o := o.(type) {
610610

611611
case pdf.Name:
612-
s := o.String()
612+
s := o.Value()
613613
if !validateBlendMode(s) {
614614
return errors.Errorf("validateSoftMaskEntry: invalid soft mask: %s\n", s)
615615
}

pkg/pdfcpu/validate/font.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ func validateFontEncoding(xRefTable *pdf.XRefTable, d pdf.Dict, dictName string,
342342
switch o := o.(type) {
343343

344344
case pdf.Name:
345-
s := o.String()
345+
s := o.Value()
346346
validateFontEncodingName := func(s string) bool {
347347
return pdf.MemberOf(s, []string{"MacRomanEncoding", "MacExpertEncoding", "WinAnsiEncoding"})
348348
}
@@ -436,7 +436,7 @@ func validateCIDToGIDMap(xRefTable *pdf.XRefTable, o pdf.Object) error {
436436
switch o := o.(type) {
437437

438438
case pdf.Name:
439-
s := o.String()
439+
s := o.Value()
440440
if s != "Identity" {
441441
return errors.Errorf("validateCIDToGIDMap: invalid name: %s - must be \"Identity\"\n", s)
442442
}
@@ -660,9 +660,9 @@ func validateType1FontDict(xRefTable *pdf.XRefTable, d pdf.Dict) error {
660660
return err
661661
}
662662

663-
required := xRefTable.Version() >= pdf.V15 || !validateStandardType1Font((*fontName).String())
663+
required := xRefTable.Version() >= pdf.V15 || !validateStandardType1Font((*fontName).Value())
664664
if xRefTable.ValidationMode == pdf.ValidationRelaxed {
665-
required = !validateStandardType1Font((*fontName).String())
665+
required = !validateStandardType1Font((*fontName).Value())
666666
}
667667
// FirstChar, required except for standard 14 fonts. since 1.5 always required, integer
668668
fc, err := validateIntegerEntry(xRefTable, d, dictName, "FirstChar", required, pdf.V10, nil)

pkg/pdfcpu/validate/objects.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ func validateName(xRefTable *pdf.XRefTable, o pdf.Object, validate func(string)
639639
}
640640

641641
// Validation
642-
if validate != nil && !validate(name.String()) {
642+
if validate != nil && !validate(name.Value()) {
643643
return nil, errors.Errorf("validateName: invalid name: %s\n", name)
644644
}
645645

@@ -681,8 +681,8 @@ func validateNameEntry(xRefTable *pdf.XRefTable, d pdf.Dict, dictName, entryName
681681
}
682682

683683
// Validation
684-
if validate != nil && !validate(name.String()) {
685-
return nil, errors.Errorf("validateNameEntry: dict=%s entry=%s invalid dict entry: %s", dictName, entryName, name.String())
684+
if validate != nil && !validate(name.Value()) {
685+
return nil, errors.Errorf("validateNameEntry: dict=%s entry=%s invalid dict entry: %s", dictName, entryName, name.Value())
686686
}
687687

688688
log.Validate.Printf("validateNameEntry end: entry=%s\n", entryName)

pkg/pdfcpu/validate/optionalContent.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,15 +337,15 @@ func validateOptionalContentConfigurationDict(xRefTable *pdf.XRefTable, d pdf.Di
337337

338338
if baseState != nil {
339339

340-
if baseState.String() != "ON" {
340+
if baseState.Value() != "ON" {
341341
// ON, optional, content group array
342342
err = validateOptionalContentGroupArray(xRefTable, d, dictName, "ON", sinceVersion)
343343
if err != nil {
344344
return err
345345
}
346346
}
347347

348-
if baseState.String() != "OFF" {
348+
if baseState.Value() != "OFF" {
349349
// OFF, optional, content group array
350350
err = validateOptionalContentGroupArray(xRefTable, d, dictName, "OFF", sinceVersion)
351351
if err != nil {

0 commit comments

Comments
 (0)