github.com/unidoc/unidoc@v2.2.0+incompatible/pdf/core/parser_test.go (about)

     1  /*
     2   * This file is subject to the terms and conditions defined in
     3   * file 'LICENSE.md', which is part of this source code package.
     4   */
     5  
     6  package core
     7  
     8  import (
     9  	"bufio"
    10  	"bytes"
    11  	"encoding/hex"
    12  	//"fmt"
    13  	"io"
    14  	//"os"
    15  	"testing"
    16  
    17  	"github.com/unidoc/unidoc/common"
    18  )
    19  
    20  func init() {
    21  	common.SetLogger(common.ConsoleLogger{})
    22  }
    23  
    24  func makeReaderForText(txt string) (*bytes.Reader, *bufio.Reader, int64) {
    25  	buf := []byte(txt)
    26  	bufReader := bytes.NewReader(buf)
    27  	bufferedReader := bufio.NewReader(bufReader)
    28  	return bufReader, bufferedReader, int64(len(txt))
    29  }
    30  
    31  func makeParserForText(txt string) *PdfParser {
    32  	rs, reader, fileSize := makeReaderForText(txt)
    33  	return &PdfParser{rs: rs, reader: reader, fileSize: fileSize}
    34  }
    35  
    36  func BenchmarkSkipSpaces(b *testing.B) {
    37  	parser := makeParserForText("       \t\t    \tABC")
    38  	for n := 0; n < b.N; n++ {
    39  		parser.skipSpaces()
    40  		parser.SetFileOffset(0)
    41  	}
    42  }
    43  
    44  var namePairs = map[string]string{
    45  	"/Name1":                             "Name1",
    46  	"/ASomewhatLongerName":               "ASomewhatLongerName",
    47  	"/A;Name_With-Various***Characters?": "A;Name_With-Various***Characters?",
    48  	"/1.2":                     "1.2",
    49  	"/$$":                      "$$",
    50  	"/@pattern":                "@pattern",
    51  	"/.notdef":                 ".notdef",
    52  	"/Lime#20Green":            "Lime Green",
    53  	"/paired#28#29parentheses": "paired()parentheses",
    54  	"/The_Key_of_F#23_Minor":   "The_Key_of_F#_Minor",
    55  	"/A#42":                    "AB",
    56  	"/":                        "",
    57  	"/ ":                       "",
    58  	"/#3CBC88#3E#3CC5ED#3E#3CD544#3E#3CC694#3E": "<BC88><C5ED><D544><C694>",
    59  }
    60  
    61  func BenchmarkNameParsing(b *testing.B) {
    62  	for n := 0; n < b.N; n++ {
    63  		for str, name := range namePairs {
    64  			parser := makeParserForText(str)
    65  			o, err := parser.parseName()
    66  			if err != nil && err != io.EOF {
    67  				b.Errorf("Unable to parse name string, error: %s", err)
    68  			}
    69  			if string(o) != name {
    70  				b.Errorf("Mismatch %s != %s", o, name)
    71  			}
    72  		}
    73  	}
    74  }
    75  
    76  func TestNameParsing(t *testing.T) {
    77  	for str, name := range namePairs {
    78  		parser := makeParserForText(str)
    79  		o, err := parser.parseName()
    80  		if err != nil && err != io.EOF {
    81  			t.Errorf("Unable to parse name string, error: %s", err)
    82  		}
    83  		if string(o) != name {
    84  			t.Errorf("Mismatch %s != %s", o, name)
    85  		}
    86  	}
    87  
    88  	// Should fail (require starting with '/')
    89  	parser := makeParserForText(" /Name")
    90  	_, err := parser.parseName()
    91  	if err == nil || err == io.EOF {
    92  		t.Errorf("Should be invalid name")
    93  	}
    94  }
    95  
    96  type testStringEntry struct {
    97  	raw      string
    98  	expected string
    99  }
   100  
   101  func BenchmarkStringParsing(b *testing.B) {
   102  	entry := "(Strings may contain balanced parenthesis () and\nspecial characters (*!&}^% and so on).)"
   103  	parser := makeParserForText(entry)
   104  	for n := 0; n < b.N; n++ {
   105  		_, err := parser.parseString()
   106  		if err != nil && err != io.EOF {
   107  			b.Errorf("Unable to parse string, error: %s", err)
   108  		}
   109  		parser.SetFileOffset(0)
   110  	}
   111  }
   112  
   113  var stringPairs = map[string]string{
   114  	"(This is a string)":                                                                        "This is a string",
   115  	"(Strings may contain\n newlines and such)":                                                 "Strings may contain\n newlines and such",
   116  	"(Strings may contain balanced parenthesis () and\nspecial characters (*!&}^% and so on).)": "Strings may contain balanced parenthesis () and\nspecial characters (*!&}^% and so on).",
   117  	"(These \\\ntwo strings \\\nare the same.)":                                                 "These two strings are the same.",
   118  	"(These two strings are the same.)":                                                         "These two strings are the same.",
   119  	"(\\\\)": "\\",
   120  	"(This string has an end-of-line at the end of it.\n)": "This string has an end-of-line at the end of it.\n",
   121  	"(So does this one.\\n)":                               "So does this one.\n",
   122  	"(\\0053)":                                             "\0053",
   123  	"(\\53)":                                               "\053",
   124  	"(\\053)":                                              "+",
   125  	"(\\53\\101)":                                          "+A",
   126  }
   127  
   128  func TestStringParsing(t *testing.T) {
   129  	for raw, expected := range stringPairs {
   130  		parser := makeParserForText(raw)
   131  		o, err := parser.parseString()
   132  		if err != nil && err != io.EOF {
   133  			t.Errorf("Unable to parse string, error: %s", err)
   134  		}
   135  		if string(o) != expected {
   136  			t.Errorf("String Mismatch %s: \"%s\" != \"%s\"", raw, o, expected)
   137  		}
   138  	}
   139  }
   140  
   141  func TestReadTextLine(t *testing.T) {
   142  	// reading text ling + rewinding should be idempotent, that is:
   143  	// if we rewind back len(str) bytes after reading string str we should arrive at beginning of str
   144  	rawText := "abc\xb0cde"
   145  	parser := makeParserForText(rawText)
   146  	s, err := parser.readTextLine()
   147  	if err != nil && err != io.EOF {
   148  		t.Errorf("Unable to parse string, error: %s", err)
   149  	}
   150  	if parser.GetFileOffset() != int64(len(s)) {
   151  		t.Errorf("File offset after reading string of length %d is %d", len(s), parser.GetFileOffset())
   152  	}
   153  }
   154  
   155  func TestBinStringParsing(t *testing.T) {
   156  	// From an example O entry in Encrypt dictionary.
   157  	rawText1 := "(\xE6\x00\xEC\xC2\x02\x88\xAD\x8B\\r\x64\xA9" +
   158  		"\\)\xC6\xA8\x3E\xE2\x51\x76\x79\xAA\x02\x18\xBE\xCE\xEA" +
   159  		"\x8B\x79\x86\x72\x6A\x8C\xDB)"
   160  
   161  	parser := PdfParser{}
   162  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText1)
   163  	o, err := parser.parseString()
   164  	if err != nil && err != io.EOF {
   165  		t.Errorf("Unable to parse string, error: %s", err)
   166  	}
   167  	if len(string(o)) != 32 {
   168  		t.Errorf("Wrong length, should be 32 (got %d)", len(string(o)))
   169  	}
   170  }
   171  
   172  // Main challenge in the text is "\\278A" which is "\\27" octal and 8A
   173  func TestStringParsing2(t *testing.T) {
   174  	rawText := "[(\\227\\224`\\274\\31W\\216\\276\\23\\231\\246U\\33\\317\\6-)(\\210S\\377:\\322\\278A\\200$*/e]\\371|)]"
   175  
   176  	parser := PdfParser{}
   177  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   178  	list, err := parser.parseArray()
   179  	if err != nil {
   180  		t.Errorf("Failed to parse string list (%s)", err)
   181  		return
   182  	}
   183  	if len(list) != 2 {
   184  		t.Errorf("Length of list should be 2 (%d)", len(list))
   185  		return
   186  	}
   187  }
   188  
   189  func TestBoolParsing(t *testing.T) {
   190  	// 7.3.2
   191  	testEntries := map[string]bool{}
   192  	testEntries["false"] = false
   193  	testEntries["true"] = true
   194  
   195  	for key, expected := range testEntries {
   196  		parser := PdfParser{}
   197  		parser.rs, parser.reader, parser.fileSize = makeReaderForText(key)
   198  		val, err := parser.parseBool()
   199  		if err != nil {
   200  			t.Errorf("Error parsing bool: %s", err)
   201  			return
   202  		}
   203  		if bool(val) != expected {
   204  			t.Errorf("bool not as expected (got %t, expected %t)", bool(val), expected)
   205  			return
   206  		}
   207  	}
   208  }
   209  
   210  func BenchmarkNumbericParsing(b *testing.B) {
   211  	txt1 := "[34.5 -3.62 1 +123.6 4. -.002 0.0]"
   212  	parser := PdfParser{}
   213  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(txt1)
   214  
   215  	for n := 0; n < b.N; n++ {
   216  		_, err := parser.parseArray()
   217  		if err != nil {
   218  			b.Errorf("Error parsing array")
   219  			return
   220  		}
   221  		parser.SetFileOffset(0)
   222  	}
   223  }
   224  
   225  func TestNumericParsing1(t *testing.T) {
   226  	// 7.3.3
   227  	txt1 := "[34.5 -3.62 1 +123.6 4. -.002 0.0]"
   228  	parser := PdfParser{}
   229  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(txt1)
   230  	list, err := parser.parseArray()
   231  	if err != nil {
   232  		t.Errorf("Error parsing array")
   233  		return
   234  	}
   235  	if len(list) != 7 {
   236  		t.Errorf("Len list != 7 (%d)", len(list))
   237  		return
   238  	}
   239  
   240  	expectedFloats := map[int]float32{
   241  		0: 34.5,
   242  		1: -3.62,
   243  		3: 123.6,
   244  		4: 4.0,
   245  		5: -0.002,
   246  		6: 0.0,
   247  	}
   248  
   249  	for idx, val := range expectedFloats {
   250  		num, ok := list[idx].(*PdfObjectFloat)
   251  		if !ok {
   252  			t.Errorf("Idx %d not float (%f)", idx, val)
   253  			return
   254  		}
   255  		if float32(*num) != val {
   256  			t.Errorf("Idx %d, value incorrect (%f)", idx, val)
   257  		}
   258  	}
   259  
   260  	inum, ok := list[2].(*PdfObjectInteger)
   261  	if !ok {
   262  		t.Errorf("Number 3 not int")
   263  		return
   264  	}
   265  	if *inum != 1 {
   266  		t.Errorf("Number 3, val != 1")
   267  		return
   268  	}
   269  }
   270  
   271  func TestNumericParsing2(t *testing.T) {
   272  	// 7.3.3
   273  	txt1 := "[+4.-.002]" // 4.0 and -0.002
   274  	parser := PdfParser{}
   275  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(txt1)
   276  	list, err := parser.parseArray()
   277  	if err != nil {
   278  		t.Errorf("Error parsing array")
   279  		return
   280  	}
   281  	if len(list) != 2 {
   282  		t.Errorf("Len list != 2 (%d)", len(list))
   283  		return
   284  	}
   285  
   286  	expectedFloats := map[int]float32{
   287  		0: 4.0,
   288  		1: -0.002,
   289  	}
   290  
   291  	for idx, val := range expectedFloats {
   292  		num, ok := list[idx].(*PdfObjectFloat)
   293  		if !ok {
   294  			t.Errorf("Idx %d not float (%f)", idx, val)
   295  			return
   296  		}
   297  		if float32(*num) != val {
   298  			t.Errorf("Idx %d, value incorrect (%f)", idx, val)
   299  		}
   300  	}
   301  }
   302  
   303  // Includes exponential numbers.
   304  func TestNumericParsing3(t *testing.T) {
   305  	// 7.3.3
   306  	txt1 := "[+4.-.002+3e-2-2e0]" // 4.0, -0.002, 1e-2, -2.0
   307  	parser := PdfParser{}
   308  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(txt1)
   309  	list, err := parser.parseArray()
   310  	if err != nil {
   311  		t.Errorf("Error parsing array (%s)", err)
   312  		return
   313  	}
   314  	if len(list) != 4 {
   315  		t.Errorf("Len list != 2 (%d)", len(list))
   316  		return
   317  	}
   318  
   319  	expectedFloats := map[int]float32{
   320  		0: 4.0,
   321  		1: -0.002,
   322  		2: 0.03,
   323  		3: -2.0,
   324  	}
   325  
   326  	for idx, val := range expectedFloats {
   327  		num, ok := list[idx].(*PdfObjectFloat)
   328  		if !ok {
   329  			t.Errorf("Idx %d not float (%f)", idx, val)
   330  			return
   331  		}
   332  		if float32(*num) != val {
   333  			t.Errorf("Idx %d, value incorrect (%f)", idx, val)
   334  		}
   335  	}
   336  }
   337  
   338  func BenchmarkHexStringParsing(b *testing.B) {
   339  	var ref bytes.Buffer
   340  	for i := 0; i < 0xff; i++ {
   341  		ref.WriteByte(byte(i))
   342  	}
   343  	parser := makeParserForText("<" + hex.EncodeToString(ref.Bytes()) + ">")
   344  	for n := 0; n < b.N; n++ {
   345  		hs, err := parser.parseHexString()
   346  		if err != nil {
   347  			b.Errorf("Error parsing hex string: %s", err.Error())
   348  			return
   349  		}
   350  		if string(hs) != ref.String() {
   351  			b.Errorf("Reference and parsed hex strings mismatch")
   352  		}
   353  		parser.SetFileOffset(0)
   354  	}
   355  }
   356  
   357  func TestHexStringParsing(t *testing.T) {
   358  	// 7.3.4.3
   359  }
   360  
   361  // TODO.
   362  // Test reference to object outside of cross-ref table - should be 0
   363  // Test xref object with offset 0, should be treated as 'f'ree.
   364  // (compatibility with malformed writers).
   365  
   366  func TestDictParsing1(t *testing.T) {
   367  	txt1 := "<<\n\t/Name /Game /key/val/data\t[0 1 2 3.14 5]\t\n\n>>"
   368  	parser := PdfParser{}
   369  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(txt1)
   370  	dict, err := parser.ParseDict()
   371  	if err != nil {
   372  		t.Errorf("Error parsing dict")
   373  	}
   374  
   375  	if len(dict.Keys()) != 3 {
   376  		t.Errorf("Length of dict != 3")
   377  	}
   378  
   379  	name, ok := dict.Get("Name").(*PdfObjectName)
   380  	if !ok || *name != "Game" {
   381  		t.Errorf("Value error")
   382  	}
   383  
   384  	key, ok := dict.Get("key").(*PdfObjectName)
   385  	if !ok || *key != "val" {
   386  		t.Errorf("Value error")
   387  	}
   388  
   389  	data, ok := dict.Get("data").(*PdfObjectArray)
   390  	if !ok {
   391  		t.Errorf("Invalid data")
   392  	}
   393  	integer, ok := (*data)[2].(*PdfObjectInteger)
   394  	if !ok || *integer != 2 {
   395  		t.Errorf("Wrong data")
   396  	}
   397  
   398  	float, ok := (*data)[3].(*PdfObjectFloat)
   399  	if !ok || *float != 3.14 {
   400  		t.Error("Wrong data")
   401  	}
   402  }
   403  
   404  func TestDictParsing2(t *testing.T) {
   405  	rawText := "<< /Type /Example\n" +
   406  		"/Subtype /DictionaryExample /Version 0.01\n" +
   407  		"/IntegerItem 12 \n" +
   408  		"/StringItem (a string) /Subdictionary << /Item1 0.4\n" +
   409  		"/Item2 true /LastItem (not!) /VeryLastItem (OK)\n" +
   410  		">>\n >>"
   411  
   412  	parser := PdfParser{}
   413  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   414  	dict, err := parser.ParseDict()
   415  	if err != nil {
   416  		t.Errorf("Error parsing dict")
   417  	}
   418  
   419  	if len(dict.Keys()) != 6 {
   420  		t.Errorf("Length of dict != 6")
   421  	}
   422  
   423  	typeName, ok := dict.Get("Type").(*PdfObjectName)
   424  	if !ok || *typeName != "Example" {
   425  		t.Errorf("Wrong type")
   426  	}
   427  
   428  	str, ok := dict.Get("StringItem").(*PdfObjectString)
   429  	if !ok || *str != "a string" {
   430  		t.Errorf("Invalid string item")
   431  	}
   432  
   433  	subDict, ok := dict.Get("Subdictionary").(*PdfObjectDictionary)
   434  	if !ok {
   435  		t.Errorf("Invalid sub dictionary")
   436  	}
   437  	item2, ok := subDict.Get("Item2").(*PdfObjectBool)
   438  	if !ok || *item2 != true {
   439  		t.Errorf("Invalid bool item")
   440  	}
   441  	realnum, ok := subDict.Get("Item1").(*PdfObjectFloat)
   442  	if !ok || *realnum != 0.4 {
   443  		t.Errorf("Invalid real number")
   444  	}
   445  }
   446  
   447  func TestDictParsing3(t *testing.T) {
   448  	rawText := "<<>>"
   449  
   450  	parser := PdfParser{}
   451  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   452  	dict, err := parser.ParseDict()
   453  	if err != nil {
   454  		t.Errorf("Error parsing dict")
   455  	}
   456  
   457  	if len(dict.Keys()) != 0 {
   458  		t.Errorf("Length of dict != 0")
   459  	}
   460  }
   461  
   462  /*
   463  func TestDictParsing4(t *testing.T) {
   464  	rawText := "<</Key>>"
   465  
   466  	parser := PdfParser{}
   467  	parser.rs, parser.reader = makeReaderForText(rawText)
   468  	dict, err := parser.ParseDict()
   469  	if err != nil {
   470  		t.Errorf("Error parsing dict (%s)", err)
   471  		return
   472  	}
   473  
   474  	if len(*dict) != 1 {
   475  		t.Errorf("Length of dict != 1")
   476  		return
   477  	}
   478  
   479  	_, ok := (*dict)["Key"].(*PdfObjectNull)
   480  	if !ok {
   481  		t.Errorf("Invalid object (should be PDF null)")
   482  		return
   483  	}
   484  }
   485  */
   486  
   487  func TestArrayParsing(t *testing.T) {
   488  	// 7.3.7.
   489  }
   490  
   491  func TestReferenceParsing(t *testing.T) {
   492  	// TODO
   493  }
   494  
   495  func TestNullParsing(t *testing.T) {
   496  	// TODO
   497  }
   498  
   499  func TestStreamParsing(t *testing.T) {
   500  	// TODO
   501  }
   502  
   503  func TestIndirectObjParsing1(t *testing.T) {
   504  	rawText := `1 0 obj
   505  <<
   506  /Names 2 0 R
   507  /Pages 3 0 R
   508  /Metadata 4 0 R
   509  /ViewerPreferences
   510  <<
   511  /Rights
   512  <<
   513  /Document [/FullSave]
   514  /TimeOfUbiquitization (D:20071210131309Z)
   515  /RightsID [(x\\Ä-z<80><83>ã[W< b<99>\rhvèC©ðFüE^TN£^\jó]ç=çø\n<8f>:˹\(<9a>\r=§^\~CÌÁxîÚð^V/=Î|Q\r<99>¢ ) (#$ÐJ^C<98>^ZX­<86>^TÞ¿ø¸^N]ú<8f>^N×2<9f>§ø±D^Q\r!'¡<8a>dp°,l¿<9d>É<82>«eæ§B­}«Ç8p·<97>\fl¿²G/x¹>) (kc2²µ^?-©¸þ$åiØ.Aé7^P½ÒÏð^S^^Y×rùç^O̵¶¿Hp^?*NËwóúËo§ü1ª<97>îFÜ\\<8f>OÚ^P[¸<93>0^)]
   516  /Version 1
   517  /Msg (This form has document rights applied to it.  These rights allow anyone completing this form, with the free Adobe Reader, to save their filled-in form locally.)
   518  /Form [/Import /Export /SubmitStandalone /SpawnTemplate]
   519  >>
   520  >>
   521  /AcroForm 5 0 R
   522  /Type /Catalog
   523  >>
   524  endobj
   525  3 0 obj
   526  `
   527  	parser := PdfParser{}
   528  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   529  
   530  	obj, err := parser.ParseIndirectObject()
   531  	if err != nil {
   532  		t.Errorf("Failed to parse indirect obj (%s)", err)
   533  		return
   534  	}
   535  
   536  	common.Log.Debug("Parsed obj: %s", obj)
   537  }
   538  
   539  // Test /Prev and xref tables.  Check if the priority order is right.
   540  // Test recovering xref tables. Refactor to recovery.go ?
   541  
   542  func TestXrefStreamParse(t *testing.T) {
   543  	rawText := `99 0 obj
   544  <<  /Type /XRef
   545      /Index [0 5]
   546      /W [1 2 2]
   547      /Filter /ASCIIHexDecode
   548      /Size 5
   549      /Length 65
   550  >>
   551  stream
   552  00 0000 FFFF
   553  02 000F 0000
   554  02 000F 0001
   555  02 000F 0002
   556  01 BA5E 0000>
   557  endstream
   558  endobj`
   559  	parser := PdfParser{}
   560  	parser.xrefs = make(XrefTable)
   561  	parser.objstms = make(ObjectStreams)
   562  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   563  
   564  	xrefDict, err := parser.parseXrefStream(nil)
   565  	if err != nil {
   566  		t.Errorf("Invalid xref stream object (%s)", err)
   567  		return
   568  	}
   569  
   570  	typeName, ok := xrefDict.Get("Type").(*PdfObjectName)
   571  	if !ok || *typeName != "XRef" {
   572  		t.Errorf("Invalid Type != XRef")
   573  		return
   574  	}
   575  
   576  	if len(parser.xrefs) != 4 {
   577  		t.Errorf("Wrong length (%d)", len(parser.xrefs))
   578  		return
   579  	}
   580  
   581  	if parser.xrefs[3].xtype != XREF_OBJECT_STREAM {
   582  		t.Errorf("Invalid type")
   583  		return
   584  	}
   585  	if parser.xrefs[3].osObjNumber != 15 {
   586  		t.Errorf("Wrong object stream obj number")
   587  		return
   588  	}
   589  	if parser.xrefs[3].osObjIndex != 2 {
   590  		t.Errorf("Wrong object stream obj index")
   591  		return
   592  	}
   593  
   594  	common.Log.Debug("Xref dict: %s", xrefDict)
   595  }
   596  
   597  func TestObjectParse(t *testing.T) {
   598  	parser := PdfParser{}
   599  
   600  	// Test object detection.
   601  	// Invalid object type.
   602  	rawText := " \t9 0 false"
   603  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   604  	obj, err := parser.parseObject()
   605  	if err != nil {
   606  		t.Error("Should ignore tab/space")
   607  		return
   608  	}
   609  
   610  	// Integer
   611  	rawText = "9 0 false"
   612  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   613  	obj, err = parser.parseObject()
   614  
   615  	if err != nil {
   616  		t.Errorf("Error parsing object")
   617  		return
   618  	}
   619  	nump, ok := obj.(*PdfObjectInteger)
   620  	if !ok {
   621  		t.Errorf("Unable to identify integer")
   622  		return
   623  	}
   624  	if *nump != 9 {
   625  		t.Errorf("Wrong value, expecting 9 (%d)", *nump)
   626  		return
   627  	}
   628  
   629  	// Reference
   630  	rawText = "9 0 R false"
   631  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   632  	obj, err = parser.parseObject()
   633  	if err != nil {
   634  		t.Errorf("Error parsing object")
   635  		return
   636  	}
   637  	refp, ok := obj.(*PdfObjectReference)
   638  	if !ok {
   639  		t.Errorf("Unable to identify reference")
   640  		return
   641  	}
   642  	if (*refp).ObjectNumber != 9 {
   643  		t.Errorf("Wrong value, expecting object number 9")
   644  		return
   645  	}
   646  
   647  	// Reference
   648  	rawText = "909 0 R false"
   649  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   650  	obj, err = parser.parseObject()
   651  	if err != nil {
   652  		t.Errorf("Error parsing object")
   653  		return
   654  	}
   655  	refp, ok = obj.(*PdfObjectReference)
   656  	if !ok {
   657  		t.Errorf("Unable to identify reference")
   658  		return
   659  	}
   660  	if (*refp).ObjectNumber != 909 {
   661  		t.Errorf("Wrong value, expecting object number 9")
   662  		return
   663  	}
   664  
   665  	// Bool
   666  	rawText = "false 9 0 R"
   667  	parser.rs, parser.reader, parser.fileSize = makeReaderForText(rawText)
   668  	obj, err = parser.parseObject()
   669  	if err != nil {
   670  		t.Errorf("Error parsing object")
   671  		return
   672  	}
   673  	boolp, ok := obj.(*PdfObjectBool)
   674  	if !ok {
   675  		t.Errorf("Unable to identify bool object")
   676  		return
   677  	}
   678  	if *boolp != false {
   679  		t.Errorf("Wrong value, expecting false")
   680  		return
   681  	}
   682  }
   683  
   684  /*
   685  var file1 = "../testfiles/minimal.pdf"
   686  
   687  func TestMinimalPDFFile(t *testing.T) {
   688  	file, err := os.Open(file1)
   689  	if err != nil {
   690  		t.Errorf("Unable to open minimal test file (%s)", err)
   691  		return
   692  	}
   693  	defer file.Close()
   694  
   695  	reader, err := NewPdfReader(file)
   696  	if err != nil {
   697  		t.Errorf("Unable to read test file (%s)", err)
   698  		return
   699  	}
   700  
   701  	numPages, err := reader.GetNumPages()
   702  	if err != nil {
   703  		t.Error("Unable to get number of pages")
   704  	}
   705  
   706  	fmt.Printf("Num pages: %d\n", numPages)
   707  	if numPages != 1 {
   708  		t.Error("Wrong number of pages")
   709  	}
   710  
   711  	parser := reader.parser
   712  	if len(parser.xrefs) != 4 {
   713  		t.Errorf("Wrong number of xrefs %d != 4", len(parser.xrefs))
   714  	}
   715  
   716  	if parser.xrefs[1].objectNumber != 1 {
   717  		t.Errorf("Invalid xref0 object number != 1 (%d)", parser.xrefs[0].objectNumber)
   718  	}
   719  	if parser.xrefs[1].offset != 18 {
   720  		t.Errorf("Invalid offset != 18 (%d)", parser.xrefs[0].offset)
   721  	}
   722  	if parser.xrefs[1].xtype != XREF_TABLE_ENTRY {
   723  		t.Errorf("Invalid xref type")
   724  	}
   725  	if parser.xrefs[3].objectNumber != 3 {
   726  		t.Errorf("Invalid xref object number != 3 (%d)", parser.xrefs[2].objectNumber)
   727  	}
   728  	if parser.xrefs[3].offset != 178 {
   729  		t.Errorf("Invalid offset != 178")
   730  	}
   731  	if parser.xrefs[3].xtype != XREF_TABLE_ENTRY {
   732  		t.Errorf("Invalid xref type")
   733  	}
   734  
   735  	// Check catalog object.
   736  	catalogObj, err := parser.LookupByNumber(1)
   737  	if err != nil {
   738  		t.Error("Unable to look up catalog object")
   739  	}
   740  	catalog, ok := catalogObj.(*PdfIndirectObject)
   741  	if !ok {
   742  		t.Error("Unable to look up catalog object")
   743  	}
   744  	catalogDict, ok := catalog.PdfObject.(*PdfObjectDictionary)
   745  	if !ok {
   746  		t.Error("Unable to find dictionary")
   747  	}
   748  	typename, ok := (*catalogDict)["Type"].(*PdfObjectName)
   749  	if !ok {
   750  		t.Error("Unable to check type")
   751  	}
   752  	if *typename != "Catalog" {
   753  		t.Error("Wrong type name (%s != Catalog)", *typename)
   754  	}
   755  
   756  	// Check Page object.
   757  	pageObj, err := parser.LookupByNumber(3)
   758  	if err != nil {
   759  		t.Error("Unable to look up Page")
   760  	}
   761  	page, ok := pageObj.(*PdfIndirectObject)
   762  	if !ok {
   763  		t.Error("Unable to look up Page")
   764  	}
   765  	pageDict, ok := page.PdfObject.(*PdfObjectDictionary)
   766  	if !ok {
   767  		t.Error("Unable to load Page dictionary")
   768  	}
   769  	if len(*pageDict) != 4 {
   770  		t.Error("Page dict should have 4 objects (%d)", len(*pageDict))
   771  	}
   772  	resourcesDict, ok := (*pageDict)["Resources"].(*PdfObjectDictionary)
   773  	if !ok {
   774  		t.Error("Unable to load Resources dictionary")
   775  	}
   776  	if len(*resourcesDict) != 1 {
   777  		t.Error("Page Resources dict should have 1 member (%d)", len(*resourcesDict))
   778  	}
   779  	fontDict, ok := (*resourcesDict)["Font"].(*PdfObjectDictionary)
   780  	if !ok {
   781  		t.Error("Unable to load font")
   782  	}
   783  	f1Dict, ok := (*fontDict)["F1"].(*PdfObjectDictionary)
   784  	if !ok {
   785  		t.Error("Unable to load F1 dict")
   786  	}
   787  	if len(*f1Dict) != 3 {
   788  		t.Error("Invalid F1 dict length 3 != %d", len(*f1Dict))
   789  	}
   790  	baseFont, ok := (*f1Dict)["BaseFont"].(*PdfObjectName)
   791  	if !ok {
   792  		t.Error("Unable to load base font")
   793  	}
   794  	if *baseFont != "Times-Roman" {
   795  		t.Error("Invalid base font (should be Times-Roman not %s)", *baseFont)
   796  	}
   797  }
   798  */