github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/archive/zip/reader_test.go (about)

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package zip
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/binary"
    10  	"encoding/hex"
    11  	"internal/obscuretestdata"
    12  	"io"
    13  	"io/fs"
    14  	"os"
    15  	"path/filepath"
    16  	"reflect"
    17  	"regexp"
    18  	"strings"
    19  	"testing"
    20  	"testing/fstest"
    21  	"time"
    22  )
    23  
    24  type ZipTest struct {
    25  	Name     string
    26  	Source   func() (r io.ReaderAt, size int64) // if non-nil, used instead of testdata/<Name> file
    27  	Comment  string
    28  	File     []ZipTestFile
    29  	Obscured bool  // needed for Apple notarization (golang.org/issue/34986)
    30  	Error    error // the error that Opening this file should return
    31  }
    32  
    33  type ZipTestFile struct {
    34  	Name     string
    35  	Mode     fs.FileMode
    36  	NonUTF8  bool
    37  	ModTime  time.Time
    38  	Modified time.Time
    39  
    40  	// Information describing expected zip file content.
    41  	// First, reading the entire content should produce the error ContentErr.
    42  	// Second, if ContentErr==nil, the content should match Content.
    43  	// If content is large, an alternative to setting Content is to set File,
    44  	// which names a file in the testdata/ directory containing the
    45  	// uncompressed expected content.
    46  	// If content is very large, an alternative to setting Content or File
    47  	// is to set Size, which will then be checked against the header-reported size
    48  	// but will bypass the decompressing of the actual data.
    49  	// This last option is used for testing very large (multi-GB) compressed files.
    50  	ContentErr error
    51  	Content    []byte
    52  	File       string
    53  	Size       uint64
    54  }
    55  
    56  var tests = []ZipTest{
    57  	{
    58  		Name:    "test.zip",
    59  		Comment: "This is a zipfile comment.",
    60  		File: []ZipTestFile{
    61  			{
    62  				Name:     "test.txt",
    63  				Content:  []byte("This is a test text file.\n"),
    64  				Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)),
    65  				Mode:     0644,
    66  			},
    67  			{
    68  				Name:     "gophercolor16x16.png",
    69  				File:     "gophercolor16x16.png",
    70  				Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)),
    71  				Mode:     0644,
    72  			},
    73  		},
    74  	},
    75  	{
    76  		Name:    "test-trailing-junk.zip",
    77  		Comment: "This is a zipfile comment.",
    78  		File: []ZipTestFile{
    79  			{
    80  				Name:     "test.txt",
    81  				Content:  []byte("This is a test text file.\n"),
    82  				Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)),
    83  				Mode:     0644,
    84  			},
    85  			{
    86  				Name:     "gophercolor16x16.png",
    87  				File:     "gophercolor16x16.png",
    88  				Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)),
    89  				Mode:     0644,
    90  			},
    91  		},
    92  	},
    93  	{
    94  		Name:    "test-prefix.zip",
    95  		Comment: "This is a zipfile comment.",
    96  		File: []ZipTestFile{
    97  			{
    98  				Name:     "test.txt",
    99  				Content:  []byte("This is a test text file.\n"),
   100  				Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)),
   101  				Mode:     0644,
   102  			},
   103  			{
   104  				Name:     "gophercolor16x16.png",
   105  				File:     "gophercolor16x16.png",
   106  				Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)),
   107  				Mode:     0644,
   108  			},
   109  		},
   110  	},
   111  	{
   112  		Name:    "test-baddirsz.zip",
   113  		Comment: "This is a zipfile comment.",
   114  		File: []ZipTestFile{
   115  			{
   116  				Name:     "test.txt",
   117  				Content:  []byte("This is a test text file.\n"),
   118  				Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)),
   119  				Mode:     0644,
   120  			},
   121  			{
   122  				Name:     "gophercolor16x16.png",
   123  				File:     "gophercolor16x16.png",
   124  				Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)),
   125  				Mode:     0644,
   126  			},
   127  		},
   128  	},
   129  	{
   130  		Name:   "r.zip",
   131  		Source: returnRecursiveZip,
   132  		File: []ZipTestFile{
   133  			{
   134  				Name:     "r/r.zip",
   135  				Content:  rZipBytes(),
   136  				Modified: time.Date(2010, 3, 4, 0, 24, 16, 0, time.UTC),
   137  				Mode:     0666,
   138  			},
   139  		},
   140  	},
   141  	{
   142  		Name: "symlink.zip",
   143  		File: []ZipTestFile{
   144  			{
   145  				Name:     "symlink",
   146  				Content:  []byte("../target"),
   147  				Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)),
   148  				Mode:     0777 | fs.ModeSymlink,
   149  			},
   150  		},
   151  	},
   152  	{
   153  		Name: "readme.zip",
   154  	},
   155  	{
   156  		Name:  "readme.notzip",
   157  		Error: ErrFormat,
   158  	},
   159  	{
   160  		Name: "dd.zip",
   161  		File: []ZipTestFile{
   162  			{
   163  				Name:     "filename",
   164  				Content:  []byte("This is a test textfile.\n"),
   165  				Modified: time.Date(2011, 2, 2, 13, 6, 20, 0, time.UTC),
   166  				Mode:     0666,
   167  			},
   168  		},
   169  	},
   170  	{
   171  		// created in windows XP file manager.
   172  		Name: "winxp.zip",
   173  		File: []ZipTestFile{
   174  			{
   175  				Name:     "hello",
   176  				Content:  []byte("world \r\n"),
   177  				Modified: time.Date(2011, 12, 8, 10, 4, 24, 0, time.UTC),
   178  				Mode:     0666,
   179  			},
   180  			{
   181  				Name:     "dir/bar",
   182  				Content:  []byte("foo \r\n"),
   183  				Modified: time.Date(2011, 12, 8, 10, 4, 50, 0, time.UTC),
   184  				Mode:     0666,
   185  			},
   186  			{
   187  				Name:     "dir/empty/",
   188  				Content:  []byte{},
   189  				Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC),
   190  				Mode:     fs.ModeDir | 0777,
   191  			},
   192  			{
   193  				Name:     "readonly",
   194  				Content:  []byte("important \r\n"),
   195  				Modified: time.Date(2011, 12, 8, 10, 6, 8, 0, time.UTC),
   196  				Mode:     0444,
   197  			},
   198  		},
   199  	},
   200  	{
   201  		// created by Zip 3.0 under Linux
   202  		Name: "unix.zip",
   203  		File: []ZipTestFile{
   204  			{
   205  				Name:     "hello",
   206  				Content:  []byte("world \r\n"),
   207  				Modified: time.Date(2011, 12, 8, 10, 4, 24, 0, timeZone(0)),
   208  				Mode:     0666,
   209  			},
   210  			{
   211  				Name:     "dir/bar",
   212  				Content:  []byte("foo \r\n"),
   213  				Modified: time.Date(2011, 12, 8, 10, 4, 50, 0, timeZone(0)),
   214  				Mode:     0666,
   215  			},
   216  			{
   217  				Name:     "dir/empty/",
   218  				Content:  []byte{},
   219  				Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)),
   220  				Mode:     fs.ModeDir | 0777,
   221  			},
   222  			{
   223  				Name:     "readonly",
   224  				Content:  []byte("important \r\n"),
   225  				Modified: time.Date(2011, 12, 8, 10, 6, 8, 0, timeZone(0)),
   226  				Mode:     0444,
   227  			},
   228  		},
   229  	},
   230  	{
   231  		// created by Go, before we wrote the "optional" data
   232  		// descriptor signatures (which are required by macOS).
   233  		// Use obscured file to avoid Apple’s notarization service
   234  		// rejecting the toolchain due to an inability to unzip this archive.
   235  		// See golang.org/issue/34986
   236  		Name:     "go-no-datadesc-sig.zip.base64",
   237  		Obscured: true,
   238  		File: []ZipTestFile{
   239  			{
   240  				Name:     "foo.txt",
   241  				Content:  []byte("foo\n"),
   242  				Modified: time.Date(2012, 3, 8, 16, 59, 10, 0, timeZone(-8*time.Hour)),
   243  				Mode:     0644,
   244  			},
   245  			{
   246  				Name:     "bar.txt",
   247  				Content:  []byte("bar\n"),
   248  				Modified: time.Date(2012, 3, 8, 16, 59, 12, 0, timeZone(-8*time.Hour)),
   249  				Mode:     0644,
   250  			},
   251  		},
   252  	},
   253  	{
   254  		// created by Go, after we wrote the "optional" data
   255  		// descriptor signatures (which are required by macOS)
   256  		Name: "go-with-datadesc-sig.zip",
   257  		File: []ZipTestFile{
   258  			{
   259  				Name:     "foo.txt",
   260  				Content:  []byte("foo\n"),
   261  				Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC),
   262  				Mode:     0666,
   263  			},
   264  			{
   265  				Name:     "bar.txt",
   266  				Content:  []byte("bar\n"),
   267  				Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC),
   268  				Mode:     0666,
   269  			},
   270  		},
   271  	},
   272  	{
   273  		Name:   "Bad-CRC32-in-data-descriptor",
   274  		Source: returnCorruptCRC32Zip,
   275  		File: []ZipTestFile{
   276  			{
   277  				Name:       "foo.txt",
   278  				Content:    []byte("foo\n"),
   279  				Modified:   time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC),
   280  				Mode:       0666,
   281  				ContentErr: ErrChecksum,
   282  			},
   283  			{
   284  				Name:     "bar.txt",
   285  				Content:  []byte("bar\n"),
   286  				Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC),
   287  				Mode:     0666,
   288  			},
   289  		},
   290  	},
   291  	// Tests that we verify (and accept valid) crc32s on files
   292  	// with crc32s in their file header (not in data descriptors)
   293  	{
   294  		Name: "crc32-not-streamed.zip",
   295  		File: []ZipTestFile{
   296  			{
   297  				Name:     "foo.txt",
   298  				Content:  []byte("foo\n"),
   299  				Modified: time.Date(2012, 3, 8, 16, 59, 10, 0, timeZone(-8*time.Hour)),
   300  				Mode:     0644,
   301  			},
   302  			{
   303  				Name:     "bar.txt",
   304  				Content:  []byte("bar\n"),
   305  				Modified: time.Date(2012, 3, 8, 16, 59, 12, 0, timeZone(-8*time.Hour)),
   306  				Mode:     0644,
   307  			},
   308  		},
   309  	},
   310  	// Tests that we verify (and reject invalid) crc32s on files
   311  	// with crc32s in their file header (not in data descriptors)
   312  	{
   313  		Name:   "crc32-not-streamed.zip",
   314  		Source: returnCorruptNotStreamedZip,
   315  		File: []ZipTestFile{
   316  			{
   317  				Name:       "foo.txt",
   318  				Content:    []byte("foo\n"),
   319  				Modified:   time.Date(2012, 3, 8, 16, 59, 10, 0, timeZone(-8*time.Hour)),
   320  				Mode:       0644,
   321  				ContentErr: ErrChecksum,
   322  			},
   323  			{
   324  				Name:     "bar.txt",
   325  				Content:  []byte("bar\n"),
   326  				Modified: time.Date(2012, 3, 8, 16, 59, 12, 0, timeZone(-8*time.Hour)),
   327  				Mode:     0644,
   328  			},
   329  		},
   330  	},
   331  	{
   332  		Name: "zip64.zip",
   333  		File: []ZipTestFile{
   334  			{
   335  				Name:     "README",
   336  				Content:  []byte("This small file is in ZIP64 format.\n"),
   337  				Modified: time.Date(2012, 8, 10, 14, 33, 32, 0, time.UTC),
   338  				Mode:     0644,
   339  			},
   340  		},
   341  	},
   342  	// Another zip64 file with different Extras fields. (golang.org/issue/7069)
   343  	{
   344  		Name: "zip64-2.zip",
   345  		File: []ZipTestFile{
   346  			{
   347  				Name:     "README",
   348  				Content:  []byte("This small file is in ZIP64 format.\n"),
   349  				Modified: time.Date(2012, 8, 10, 14, 33, 32, 0, timeZone(-4*time.Hour)),
   350  				Mode:     0644,
   351  			},
   352  		},
   353  	},
   354  	// Largest possible non-zip64 file, with no zip64 header.
   355  	{
   356  		Name:   "big.zip",
   357  		Source: returnBigZipBytes,
   358  		File: []ZipTestFile{
   359  			{
   360  				Name:     "big.file",
   361  				Content:  nil,
   362  				Size:     1<<32 - 1,
   363  				Modified: time.Date(1979, 11, 30, 0, 0, 0, 0, time.UTC),
   364  				Mode:     0666,
   365  			},
   366  		},
   367  	},
   368  	{
   369  		Name: "utf8-7zip.zip",
   370  		File: []ZipTestFile{
   371  			{
   372  				Name:     "世界",
   373  				Content:  []byte{},
   374  				Mode:     0666,
   375  				Modified: time.Date(2017, 11, 6, 13, 9, 27, 867862500, timeZone(-8*time.Hour)),
   376  			},
   377  		},
   378  	},
   379  	{
   380  		Name: "utf8-infozip.zip",
   381  		File: []ZipTestFile{
   382  			{
   383  				Name:    "世界",
   384  				Content: []byte{},
   385  				Mode:    0644,
   386  				// Name is valid UTF-8, but format does not have UTF-8 flag set.
   387  				// We don't do UTF-8 detection for multi-byte runes due to
   388  				// false-positives with other encodings (e.g., Shift-JIS).
   389  				// Format says encoding is not UTF-8, so we trust it.
   390  				NonUTF8:  true,
   391  				Modified: time.Date(2017, 11, 6, 13, 9, 27, 0, timeZone(-8*time.Hour)),
   392  			},
   393  		},
   394  	},
   395  	{
   396  		Name: "utf8-osx.zip",
   397  		File: []ZipTestFile{
   398  			{
   399  				Name:    "世界",
   400  				Content: []byte{},
   401  				Mode:    0644,
   402  				// Name is valid UTF-8, but format does not have UTF-8 set.
   403  				NonUTF8:  true,
   404  				Modified: time.Date(2017, 11, 6, 13, 9, 27, 0, timeZone(-8*time.Hour)),
   405  			},
   406  		},
   407  	},
   408  	{
   409  		Name: "utf8-winrar.zip",
   410  		File: []ZipTestFile{
   411  			{
   412  				Name:     "世界",
   413  				Content:  []byte{},
   414  				Mode:     0666,
   415  				Modified: time.Date(2017, 11, 6, 13, 9, 27, 867862500, timeZone(-8*time.Hour)),
   416  			},
   417  		},
   418  	},
   419  	{
   420  		Name: "utf8-winzip.zip",
   421  		File: []ZipTestFile{
   422  			{
   423  				Name:     "世界",
   424  				Content:  []byte{},
   425  				Mode:     0666,
   426  				Modified: time.Date(2017, 11, 6, 13, 9, 27, 867000000, timeZone(-8*time.Hour)),
   427  			},
   428  		},
   429  	},
   430  	{
   431  		Name: "time-7zip.zip",
   432  		File: []ZipTestFile{
   433  			{
   434  				Name:     "test.txt",
   435  				Content:  []byte{},
   436  				Size:     1<<32 - 1,
   437  				Modified: time.Date(2017, 10, 31, 21, 11, 57, 244817900, timeZone(-7*time.Hour)),
   438  				Mode:     0666,
   439  			},
   440  		},
   441  	},
   442  	{
   443  		Name: "time-infozip.zip",
   444  		File: []ZipTestFile{
   445  			{
   446  				Name:     "test.txt",
   447  				Content:  []byte{},
   448  				Size:     1<<32 - 1,
   449  				Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)),
   450  				Mode:     0644,
   451  			},
   452  		},
   453  	},
   454  	{
   455  		Name: "time-osx.zip",
   456  		File: []ZipTestFile{
   457  			{
   458  				Name:     "test.txt",
   459  				Content:  []byte{},
   460  				Size:     1<<32 - 1,
   461  				Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)),
   462  				Mode:     0644,
   463  			},
   464  		},
   465  	},
   466  	{
   467  		Name: "time-win7.zip",
   468  		File: []ZipTestFile{
   469  			{
   470  				Name:     "test.txt",
   471  				Content:  []byte{},
   472  				Size:     1<<32 - 1,
   473  				Modified: time.Date(2017, 10, 31, 21, 11, 58, 0, time.UTC),
   474  				Mode:     0666,
   475  			},
   476  		},
   477  	},
   478  	{
   479  		Name: "time-winrar.zip",
   480  		File: []ZipTestFile{
   481  			{
   482  				Name:     "test.txt",
   483  				Content:  []byte{},
   484  				Size:     1<<32 - 1,
   485  				Modified: time.Date(2017, 10, 31, 21, 11, 57, 244817900, timeZone(-7*time.Hour)),
   486  				Mode:     0666,
   487  			},
   488  		},
   489  	},
   490  	{
   491  		Name: "time-winzip.zip",
   492  		File: []ZipTestFile{
   493  			{
   494  				Name:     "test.txt",
   495  				Content:  []byte{},
   496  				Size:     1<<32 - 1,
   497  				Modified: time.Date(2017, 10, 31, 21, 11, 57, 244000000, timeZone(-7*time.Hour)),
   498  				Mode:     0666,
   499  			},
   500  		},
   501  	},
   502  	{
   503  		Name: "time-go.zip",
   504  		File: []ZipTestFile{
   505  			{
   506  				Name:     "test.txt",
   507  				Content:  []byte{},
   508  				Size:     1<<32 - 1,
   509  				Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)),
   510  				Mode:     0666,
   511  			},
   512  		},
   513  	},
   514  	{
   515  		Name: "time-22738.zip",
   516  		File: []ZipTestFile{
   517  			{
   518  				Name:     "file",
   519  				Content:  []byte{},
   520  				Mode:     0666,
   521  				Modified: time.Date(1999, 12, 31, 19, 0, 0, 0, timeZone(-5*time.Hour)),
   522  				ModTime:  time.Date(1999, 12, 31, 19, 0, 0, 0, time.UTC),
   523  			},
   524  		},
   525  	},
   526  	{
   527  		Name: "dupdir.zip",
   528  		File: []ZipTestFile{
   529  			{
   530  				Name:     "a/",
   531  				Content:  []byte{},
   532  				Mode:     fs.ModeDir | 0666,
   533  				Modified: time.Date(2021, 12, 29, 0, 0, 0, 0, timeZone(0)),
   534  			},
   535  			{
   536  				Name:     "a/b",
   537  				Content:  []byte{},
   538  				Mode:     0666,
   539  				Modified: time.Date(2021, 12, 29, 0, 0, 0, 0, timeZone(0)),
   540  			},
   541  			{
   542  				Name:     "a/b/",
   543  				Content:  []byte{},
   544  				Mode:     fs.ModeDir | 0666,
   545  				Modified: time.Date(2021, 12, 29, 0, 0, 0, 0, timeZone(0)),
   546  			},
   547  			{
   548  				Name:     "a/b/c",
   549  				Content:  []byte{},
   550  				Mode:     0666,
   551  				Modified: time.Date(2021, 12, 29, 0, 0, 0, 0, timeZone(0)),
   552  			},
   553  		},
   554  	},
   555  }
   556  
   557  func TestReader(t *testing.T) {
   558  	for _, zt := range tests {
   559  		t.Run(zt.Name, func(t *testing.T) {
   560  			readTestZip(t, zt)
   561  		})
   562  	}
   563  }
   564  
   565  func readTestZip(t *testing.T, zt ZipTest) {
   566  	var z *Reader
   567  	var err error
   568  	var raw []byte
   569  	if zt.Source != nil {
   570  		rat, size := zt.Source()
   571  		z, err = NewReader(rat, size)
   572  		raw = make([]byte, size)
   573  		if _, err := rat.ReadAt(raw, 0); err != nil {
   574  			t.Errorf("ReadAt error=%v", err)
   575  			return
   576  		}
   577  	} else {
   578  		path := filepath.Join("testdata", zt.Name)
   579  		if zt.Obscured {
   580  			tf, err := obscuretestdata.DecodeToTempFile(path)
   581  			if err != nil {
   582  				t.Errorf("obscuretestdata.DecodeToTempFile(%s): %v", path, err)
   583  				return
   584  			}
   585  			defer os.Remove(tf)
   586  			path = tf
   587  		}
   588  		var rc *ReadCloser
   589  		rc, err = OpenReader(path)
   590  		if err == nil {
   591  			defer rc.Close()
   592  			z = &rc.Reader
   593  		}
   594  		var err2 error
   595  		raw, err2 = os.ReadFile(path)
   596  		if err2 != nil {
   597  			t.Errorf("ReadFile(%s) error=%v", path, err2)
   598  			return
   599  		}
   600  	}
   601  	if err != zt.Error {
   602  		t.Errorf("error=%v, want %v", err, zt.Error)
   603  		return
   604  	}
   605  
   606  	// bail if file is not zip
   607  	if err == ErrFormat {
   608  		return
   609  	}
   610  
   611  	// bail here if no Files expected to be tested
   612  	// (there may actually be files in the zip, but we don't care)
   613  	if zt.File == nil {
   614  		return
   615  	}
   616  
   617  	if z.Comment != zt.Comment {
   618  		t.Errorf("comment=%q, want %q", z.Comment, zt.Comment)
   619  	}
   620  	if len(z.File) != len(zt.File) {
   621  		t.Fatalf("file count=%d, want %d", len(z.File), len(zt.File))
   622  	}
   623  
   624  	// test read of each file
   625  	for i, ft := range zt.File {
   626  		readTestFile(t, zt, ft, z.File[i], raw)
   627  	}
   628  	if t.Failed() {
   629  		return
   630  	}
   631  
   632  	// test simultaneous reads
   633  	n := 0
   634  	done := make(chan bool)
   635  	for i := 0; i < 5; i++ {
   636  		for j, ft := range zt.File {
   637  			go func(j int, ft ZipTestFile) {
   638  				readTestFile(t, zt, ft, z.File[j], raw)
   639  				done <- true
   640  			}(j, ft)
   641  			n++
   642  		}
   643  	}
   644  	for ; n > 0; n-- {
   645  		<-done
   646  	}
   647  }
   648  
   649  func equalTimeAndZone(t1, t2 time.Time) bool {
   650  	name1, offset1 := t1.Zone()
   651  	name2, offset2 := t2.Zone()
   652  	return t1.Equal(t2) && name1 == name2 && offset1 == offset2
   653  }
   654  
   655  func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File, raw []byte) {
   656  	if f.Name != ft.Name {
   657  		t.Errorf("name=%q, want %q", f.Name, ft.Name)
   658  	}
   659  	if !ft.Modified.IsZero() && !equalTimeAndZone(f.Modified, ft.Modified) {
   660  		t.Errorf("%s: Modified=%s, want %s", f.Name, f.Modified, ft.Modified)
   661  	}
   662  	if !ft.ModTime.IsZero() && !equalTimeAndZone(f.ModTime(), ft.ModTime) {
   663  		t.Errorf("%s: ModTime=%s, want %s", f.Name, f.ModTime(), ft.ModTime)
   664  	}
   665  
   666  	testFileMode(t, f, ft.Mode)
   667  
   668  	size := uint64(f.UncompressedSize)
   669  	if size == uint32max {
   670  		size = f.UncompressedSize64
   671  	} else if size != f.UncompressedSize64 {
   672  		t.Errorf("%v: UncompressedSize=%#x does not match UncompressedSize64=%#x", f.Name, size, f.UncompressedSize64)
   673  	}
   674  
   675  	// Check that OpenRaw returns the correct byte segment
   676  	rw, err := f.OpenRaw()
   677  	if err != nil {
   678  		t.Errorf("%v: OpenRaw error=%v", f.Name, err)
   679  		return
   680  	}
   681  	start, err := f.DataOffset()
   682  	if err != nil {
   683  		t.Errorf("%v: DataOffset error=%v", f.Name, err)
   684  		return
   685  	}
   686  	got, err := io.ReadAll(rw)
   687  	if err != nil {
   688  		t.Errorf("%v: OpenRaw ReadAll error=%v", f.Name, err)
   689  		return
   690  	}
   691  	end := uint64(start) + f.CompressedSize64
   692  	want := raw[start:end]
   693  	if !bytes.Equal(got, want) {
   694  		t.Logf("got %q", got)
   695  		t.Logf("want %q", want)
   696  		t.Errorf("%v: OpenRaw returned unexpected bytes", f.Name)
   697  		return
   698  	}
   699  
   700  	r, err := f.Open()
   701  	if err != nil {
   702  		t.Errorf("%v", err)
   703  		return
   704  	}
   705  
   706  	// For very large files, just check that the size is correct.
   707  	// The content is expected to be all zeros.
   708  	// Don't bother uncompressing: too big.
   709  	if ft.Content == nil && ft.File == "" && ft.Size > 0 {
   710  		if size != ft.Size {
   711  			t.Errorf("%v: uncompressed size %#x, want %#x", ft.Name, size, ft.Size)
   712  		}
   713  		r.Close()
   714  		return
   715  	}
   716  
   717  	var b bytes.Buffer
   718  	_, err = io.Copy(&b, r)
   719  	if err != ft.ContentErr {
   720  		t.Errorf("copying contents: %v (want %v)", err, ft.ContentErr)
   721  	}
   722  	if err != nil {
   723  		return
   724  	}
   725  	r.Close()
   726  
   727  	if g := uint64(b.Len()); g != size {
   728  		t.Errorf("%v: read %v bytes but f.UncompressedSize == %v", f.Name, g, size)
   729  	}
   730  
   731  	var c []byte
   732  	if ft.Content != nil {
   733  		c = ft.Content
   734  	} else if c, err = os.ReadFile("testdata/" + ft.File); err != nil {
   735  		t.Error(err)
   736  		return
   737  	}
   738  
   739  	if b.Len() != len(c) {
   740  		t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c))
   741  		return
   742  	}
   743  
   744  	for i, b := range b.Bytes() {
   745  		if b != c[i] {
   746  			t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i])
   747  			return
   748  		}
   749  	}
   750  }
   751  
   752  func testFileMode(t *testing.T, f *File, want fs.FileMode) {
   753  	mode := f.Mode()
   754  	if want == 0 {
   755  		t.Errorf("%s mode: got %v, want none", f.Name, mode)
   756  	} else if mode != want {
   757  		t.Errorf("%s mode: want %v, got %v", f.Name, want, mode)
   758  	}
   759  }
   760  
   761  func TestInvalidFiles(t *testing.T) {
   762  	const size = 1024 * 70 // 70kb
   763  	b := make([]byte, size)
   764  
   765  	// zeroes
   766  	_, err := NewReader(bytes.NewReader(b), size)
   767  	if err != ErrFormat {
   768  		t.Errorf("zeroes: error=%v, want %v", err, ErrFormat)
   769  	}
   770  
   771  	// repeated directoryEndSignatures
   772  	sig := make([]byte, 4)
   773  	binary.LittleEndian.PutUint32(sig, directoryEndSignature)
   774  	for i := 0; i < size-4; i += 4 {
   775  		copy(b[i:i+4], sig)
   776  	}
   777  	_, err = NewReader(bytes.NewReader(b), size)
   778  	if err != ErrFormat {
   779  		t.Errorf("sigs: error=%v, want %v", err, ErrFormat)
   780  	}
   781  
   782  	// negative size
   783  	_, err = NewReader(bytes.NewReader([]byte("foobar")), -1)
   784  	if err == nil {
   785  		t.Errorf("archive/zip.NewReader: expected error when negative size is passed")
   786  	}
   787  }
   788  
   789  func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) {
   790  	data, err := os.ReadFile(filepath.Join("testdata", fileName))
   791  	if err != nil {
   792  		panic("Error reading " + fileName + ": " + err.Error())
   793  	}
   794  	corrupter(data)
   795  	return bytes.NewReader(data), int64(len(data))
   796  }
   797  
   798  func returnCorruptCRC32Zip() (r io.ReaderAt, size int64) {
   799  	return messWith("go-with-datadesc-sig.zip", func(b []byte) {
   800  		// Corrupt one of the CRC32s in the data descriptor:
   801  		b[0x2d]++
   802  	})
   803  }
   804  
   805  func returnCorruptNotStreamedZip() (r io.ReaderAt, size int64) {
   806  	return messWith("crc32-not-streamed.zip", func(b []byte) {
   807  		// Corrupt foo.txt's final crc32 byte, in both
   808  		// the file header and TOC. (0x7e -> 0x7f)
   809  		b[0x11]++
   810  		b[0x9d]++
   811  
   812  		// TODO(bradfitz): add a new test that only corrupts
   813  		// one of these values, and verify that that's also an
   814  		// error. Currently, the reader code doesn't verify the
   815  		// fileheader and TOC's crc32 match if they're both
   816  		// non-zero and only the second line above, the TOC,
   817  		// is what matters.
   818  	})
   819  }
   820  
   821  // rZipBytes returns the bytes of a recursive zip file, without
   822  // putting it on disk and triggering certain virus scanners.
   823  func rZipBytes() []byte {
   824  	s := `
   825  0000000 50 4b 03 04 14 00 00 00 08 00 08 03 64 3c f9 f4
   826  0000010 89 64 48 01 00 00 b8 01 00 00 07 00 00 00 72 2f
   827  0000020 72 2e 7a 69 70 00 25 00 da ff 50 4b 03 04 14 00
   828  0000030 00 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00
   829  0000040 b8 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00
   830  0000050 2f 00 d0 ff 00 25 00 da ff 50 4b 03 04 14 00 00
   831  0000060 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00 b8
   832  0000070 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00 2f
   833  0000080 00 d0 ff c2 54 8e 57 39 00 05 00 fa ff c2 54 8e
   834  0000090 57 39 00 05 00 fa ff 00 05 00 fa ff 00 14 00 eb
   835  00000a0 ff c2 54 8e 57 39 00 05 00 fa ff 00 05 00 fa ff
   836  00000b0 00 14 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42
   837  00000c0 88 21 c4 00 00 14 00 eb ff 42 88 21 c4 00 00 14
   838  00000d0 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42 88 21
   839  00000e0 c4 00 00 00 00 ff ff 00 00 00 ff ff 00 34 00 cb
   840  00000f0 ff 42 88 21 c4 00 00 00 00 ff ff 00 00 00 ff ff
   841  0000100 00 34 00 cb ff 42 e8 21 5e 0f 00 00 00 ff ff 0a
   842  0000110 f0 66 64 12 61 c0 15 dc e8 a0 48 bf 48 af 2a b3
   843  0000120 20 c0 9b 95 0d c4 67 04 42 53 06 06 06 40 00 06
   844  0000130 00 f9 ff 6d 01 00 00 00 00 42 e8 21 5e 0f 00 00
   845  0000140 00 ff ff 0a f0 66 64 12 61 c0 15 dc e8 a0 48 bf
   846  0000150 48 af 2a b3 20 c0 9b 95 0d c4 67 04 42 53 06 06
   847  0000160 06 40 00 06 00 f9 ff 6d 01 00 00 00 00 50 4b 01
   848  0000170 02 14 00 14 00 00 00 08 00 08 03 64 3c f9 f4 89
   849  0000180 64 48 01 00 00 b8 01 00 00 07 00 00 00 00 00 00
   850  0000190 00 00 00 00 00 00 00 00 00 00 00 72 2f 72 2e 7a
   851  00001a0 69 70 50 4b 05 06 00 00 00 00 01 00 01 00 35 00
   852  00001b0 00 00 6d 01 00 00 00 00`
   853  	s = regexp.MustCompile(`[0-9a-f]{7}`).ReplaceAllString(s, "")
   854  	s = regexp.MustCompile(`\s+`).ReplaceAllString(s, "")
   855  	b, err := hex.DecodeString(s)
   856  	if err != nil {
   857  		panic(err)
   858  	}
   859  	return b
   860  }
   861  
   862  func returnRecursiveZip() (r io.ReaderAt, size int64) {
   863  	b := rZipBytes()
   864  	return bytes.NewReader(b), int64(len(b))
   865  }
   866  
   867  // biggestZipBytes returns the bytes of a zip file biggest.zip
   868  // that contains a zip file bigger.zip that contains a zip file
   869  // big.zip that contains big.file, which contains 2³²-1 zeros.
   870  // The big.zip file is interesting because it has no zip64 header,
   871  // much like the innermost zip files in the well-known 42.zip.
   872  //
   873  // biggest.zip was generated by changing isZip64 to use > uint32max
   874  // instead of >= uint32max and then running this program:
   875  //
   876  //	package main
   877  //
   878  //	import (
   879  //		"archive/zip"
   880  //		"bytes"
   881  //		"io"
   882  //		"log"
   883  //		"os"
   884  //	)
   885  //
   886  //	type zeros struct{}
   887  //
   888  //	func (zeros) Read(b []byte) (int, error) {
   889  //		for i := range b {
   890  //			b[i] = 0
   891  //		}
   892  //		return len(b), nil
   893  //	}
   894  //
   895  //	func main() {
   896  //		bigZip := makeZip("big.file", io.LimitReader(zeros{}, 1<<32-1))
   897  //		if err := os.WriteFile("/tmp/big.zip", bigZip, 0666); err != nil {
   898  //			log.Fatal(err)
   899  //		}
   900  //
   901  //		biggerZip := makeZip("big.zip", bytes.NewReader(bigZip))
   902  //		if err := os.WriteFile("/tmp/bigger.zip", biggerZip, 0666); err != nil {
   903  //			log.Fatal(err)
   904  //		}
   905  //
   906  //		biggestZip := makeZip("bigger.zip", bytes.NewReader(biggerZip))
   907  //		if err := os.WriteFile("/tmp/biggest.zip", biggestZip, 0666); err != nil {
   908  //			log.Fatal(err)
   909  //		}
   910  //	}
   911  //
   912  //	func makeZip(name string, r io.Reader) []byte {
   913  //		var buf bytes.Buffer
   914  //		w := zip.NewWriter(&buf)
   915  //		wf, err := w.Create(name)
   916  //		if err != nil {
   917  //			log.Fatal(err)
   918  //		}
   919  //		if _, err = io.Copy(wf, r); err != nil {
   920  //			log.Fatal(err)
   921  //		}
   922  //		if err := w.Close(); err != nil {
   923  //			log.Fatal(err)
   924  //		}
   925  //		return buf.Bytes()
   926  //	}
   927  //
   928  // The 4 GB of zeros compresses to 4 MB, which compresses to 20 kB,
   929  // which compresses to 1252 bytes (in the hex dump below).
   930  //
   931  // It's here in hex for the same reason as rZipBytes above: to avoid
   932  // problems with on-disk virus scanners or other zip processors.
   933  func biggestZipBytes() []byte {
   934  	s := `
   935  0000000 50 4b 03 04 14 00 08 00 08 00 00 00 00 00 00 00
   936  0000010 00 00 00 00 00 00 00 00 00 00 0a 00 00 00 62 69
   937  0000020 67 67 65 72 2e 7a 69 70 ec dc 6b 4c 53 67 18 07
   938  0000030 f0 16 c5 ca 65 2e cb b8 94 20 61 1f 44 33 c7 cd
   939  0000040 c0 86 4a b5 c0 62 8a 61 05 c6 cd 91 b2 54 8c 1b
   940  0000050 63 8b 03 9c 1b 95 52 5a e3 a0 19 6c b2 05 59 44
   941  0000060 64 9d 73 83 71 11 46 61 14 b9 1d 14 09 4a c3 60
   942  0000070 2e 4c 6e a5 60 45 02 62 81 95 b6 94 9e 9e 77 e7
   943  0000080 d0 43 b6 f8 71 df 96 3c e7 a4 69 ce bf cf e9 79
   944  0000090 ce ef 79 3f bf f1 31 db b6 bb 31 76 92 e7 f3 07
   945  00000a0 8b fc 9c ca cc 08 cc cb cc 5e d2 1c 88 d9 7e bb
   946  00000b0 4f bb 3a 3f 75 f1 5d 7f 8f c2 68 67 77 8f 25 ff
   947  00000c0 84 e2 93 2d ef a4 95 3d 71 4e 2c b9 b0 87 c3 be
   948  00000d0 3d f8 a7 60 24 61 c5 ef ae 9e c8 6c 6d 4e 69 c8
   949  00000e0 67 65 34 f8 37 76 2d 76 5c 54 f3 95 65 49 c7 0f
   950  00000f0 18 71 4b 7e 5b 6a d1 79 47 61 41 b0 4e 2a 74 45
   951  0000100 43 58 12 b2 5a a5 c6 7d 68 55 88 d4 98 75 18 6d
   952  0000110 08 d1 1f 8f 5a 9e 96 ee 45 cf a4 84 4e 4b e8 50
   953  0000120 a7 13 d9 06 de 52 81 97 36 b2 d7 b8 fc 2b 5f 55
   954  0000130 23 1f 32 59 cf 30 27 fb e2 8a b9 de 45 dd 63 9c
   955  0000140 4b b5 8b 96 4c 7a 62 62 cc a1 a7 cf fa f1 fe dd
   956  0000150 54 62 11 bf 36 78 b3 c7 b1 b5 f2 61 4d 4e dd 66
   957  0000160 32 2e e6 70 34 5f f4 c9 e6 6c 43 6f da 6b c6 c3
   958  0000170 09 2c ce 09 57 7f d2 7e b4 23 ba 7c 1b 99 bc 22
   959  0000180 3e f1 de 91 2f e3 9c 1b 82 cc c2 84 39 aa e6 de
   960  0000190 b4 69 fc cc cb 72 a6 61 45 f0 d3 1d 26 19 7c 8d
   961  00001a0 29 c8 66 02 be 77 6a f9 3d 34 79 17 19 c8 96 24
   962  00001b0 a3 ac e4 dd 3b 1a 8e c6 fe 96 38 6b bf 67 5a 23
   963  00001c0 f4 16 f4 e6 8a b4 fc c2 cd bf 95 66 1d bb 35 aa
   964  00001d0 92 7d 66 d8 08 8d a5 1f 54 2a af 09 cf 61 ff d2
   965  00001e0 85 9d 8f b6 d7 88 07 4a 86 03 db 64 f3 d9 92 73
   966  00001f0 df ec a7 fc 23 4c 8d 83 79 63 2a d9 fd 8d b3 c8
   967  0000200 8f 7e d4 19 85 e6 8d 1c 76 f0 8b 58 32 fd 9a d6
   968  0000210 85 e2 48 ad c3 d5 60 6f 7e 22 dd ef 09 49 7c 7f
   969  0000220 3a 45 c3 71 b7 df f3 4c 63 fb b5 d9 31 5f 6e d6
   970  0000230 24 1d a4 4a fe 32 a7 5c 16 48 5c 3e 08 6b 8a d3
   971  0000240 25 1d a2 12 a5 59 24 ea 20 5f 52 6d ad 94 db 6b
   972  0000250 94 b9 5d eb 4b a7 5c 44 bb 1e f2 3c 6b cf 52 c9
   973  0000260 e9 e5 ba 06 b9 c4 e5 0a d0 00 0d d0 00 0d d0 00
   974  0000270 0d d0 00 0d d0 00 0d d0 00 0d d0 00 0d d0 00 0d
   975  0000280 d0 00 0d d0 00 0d d0 00 0d d0 00 0d d0 00 0d d0
   976  0000290 00 0d d0 00 0d d0 00 0d d0 00 0d d0 00 0d d0 00
   977  00002a0 0d d0 00 cd ff 9e 46 86 fa a7 7d 3a 43 d7 8e 10
   978  00002b0 52 e9 be e6 6e cf eb 9e 85 4d 65 ce cc 30 c1 44
   979  00002c0 c0 4e af bc 9c 6c 4b a0 d7 54 ff 1d d5 5c 89 fb
   980  00002d0 b5 34 7e c4 c2 9e f5 a0 f6 5b 7e 6e ca 73 c7 ef
   981  00002e0 5d be de f9 e8 81 eb a5 0a a5 63 54 2c d7 1c d1
   982  00002f0 89 17 85 f8 16 94 f2 8a b2 a3 f5 b6 6d df 75 cd
   983  0000300 90 dd 64 bd 5d 55 4e f2 55 19 1b b7 cc ef 1b ea
   984  0000310 2e 05 9c f4 aa 1e a8 cd a6 82 c7 59 0f 5e 9d e0
   985  0000320 bb fc 6c d6 99 23 eb 36 ad c6 c5 e1 d8 e1 e2 3e
   986  0000330 d9 90 5a f7 91 5d 6f bc 33 6d 98 47 d2 7c 2e 2f
   987  0000340 99 a4 25 72 85 49 2c be 0b 5b af 8f e5 6e 81 a6
   988  0000350 a3 5a 6f 39 53 3a ab 7a 8b 1e 26 f7 46 6c 7d 26
   989  0000360 53 b3 22 31 94 d3 83 f2 18 4d f5 92 33 27 53 97
   990  0000370 0f d3 e6 55 9c a6 c5 31 87 6f d3 f3 ae 39 6f 56
   991  0000380 10 7b ab 7e d0 b4 ca f2 b8 05 be 3f 0e 6e 5a 75
   992  0000390 ab 0c f5 37 0e ba 8e 75 71 7a aa ed 7a dd 6a 63
   993  00003a0 be 9b a0 97 27 6a 6f e7 d3 8b c4 7c ec d3 91 56
   994  00003b0 d9 ac 5e bf 16 42 2f 00 1f 93 a2 23 87 bd e2 59
   995  00003c0 a0 de 1a 66 c8 62 eb 55 8f 91 17 b4 61 42 7a 50
   996  00003d0 40 03 34 40 03 34 40 03 34 40 03 34 40 03 34 40
   997  00003e0 03 34 40 03 34 40 03 34 40 03 34 40 03 34 40 03
   998  00003f0 34 40 03 34 40 03 34 ff 85 86 90 8b ea 67 90 0d
   999  0000400 e1 42 1b d2 61 d6 79 ec fd 3e 44 28 a4 51 6c 5c
  1000  0000410 fc d2 72 ca ba 82 18 46 16 61 cd 93 a9 0f d1 24
  1001  0000420 17 99 e2 2c 71 16 84 0c c8 7a 13 0f 9a 5e c5 f0
  1002  0000430 79 64 e2 12 4d c8 82 a1 81 19 2d aa 44 6d 87 54
  1003  0000440 84 71 c1 f6 d4 ca 25 8c 77 b9 08 c7 c8 5e 10 8a
  1004  0000450 8f 61 ed 8c ba 30 1f 79 9a c7 60 34 2b b9 8c f8
  1005  0000460 18 a6 83 1b e3 9f ad 79 fe fd 1b 8b f1 fc 41 6f
  1006  0000470 d4 13 1f e3 b8 83 ba 64 92 e7 eb e4 77 05 8f ba
  1007  0000480 fa 3b 00 00 ff ff 50 4b 07 08 a6 18 b1 91 5e 04
  1008  0000490 00 00 e4 47 00 00 50 4b 01 02 14 00 14 00 08 00
  1009  00004a0 08 00 00 00 00 00 a6 18 b1 91 5e 04 00 00 e4 47
  1010  00004b0 00 00 0a 00 00 00 00 00 00 00 00 00 00 00 00 00
  1011  00004c0 00 00 00 00 62 69 67 67 65 72 2e 7a 69 70 50 4b
  1012  00004d0 05 06 00 00 00 00 01 00 01 00 38 00 00 00 96 04
  1013  00004e0 00 00 00 00`
  1014  	s = regexp.MustCompile(`[0-9a-f]{7}`).ReplaceAllString(s, "")
  1015  	s = regexp.MustCompile(`\s+`).ReplaceAllString(s, "")
  1016  	b, err := hex.DecodeString(s)
  1017  	if err != nil {
  1018  		panic(err)
  1019  	}
  1020  	return b
  1021  }
  1022  
  1023  func returnBigZipBytes() (r io.ReaderAt, size int64) {
  1024  	b := biggestZipBytes()
  1025  	for i := 0; i < 2; i++ {
  1026  		r, err := NewReader(bytes.NewReader(b), int64(len(b)))
  1027  		if err != nil {
  1028  			panic(err)
  1029  		}
  1030  		f, err := r.File[0].Open()
  1031  		if err != nil {
  1032  			panic(err)
  1033  		}
  1034  		b, err = io.ReadAll(f)
  1035  		if err != nil {
  1036  			panic(err)
  1037  		}
  1038  	}
  1039  	return bytes.NewReader(b), int64(len(b))
  1040  }
  1041  
  1042  func TestIssue8186(t *testing.T) {
  1043  	// Directory headers & data found in the TOC of a JAR file.
  1044  	dirEnts := []string{
  1045  		"PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\xaa\x1b\x06\xf0\x81\x02\x00\x00\x81\x02\x00\x00-\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00res/drawable-xhdpi-v4/ic_actionbar_accept.png\xfe\xca\x00\x00\x00",
  1046  		"PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\x90K\x89\xc7t\n\x00\x00t\n\x00\x00\x0e\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x02\x00\x00resources.arsc\x00\x00\x00",
  1047  		"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xff$\x18\xed3\x03\x00\x00\xb4\b\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\r\x00\x00AndroidManifest.xml",
  1048  		"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\x14\xc5K\xab\x192\x02\x00\xc8\xcd\x04\x00\v\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x10\x00\x00classes.dex",
  1049  		"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?E\x96\nD\xac\x01\x00\x00P\x03\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:C\x02\x00res/layout/actionbar_set_wallpaper.xml",
  1050  		"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?Ļ\x14\xe3\xd8\x01\x00\x00\xd8\x03\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:E\x02\x00res/layout/wallpaper_cropper.xml",
  1051  		"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?}\xc1\x15\x9eZ\x01\x00\x00!\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`G\x02\x00META-INF/MANIFEST.MF",
  1052  		"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xe6\x98Ьo\x01\x00\x00\x84\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcH\x02\x00META-INF/CERT.SF",
  1053  		"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xbfP\x96b\x86\x04\x00\x00\xb2\x06\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9J\x02\x00META-INF/CERT.RSA",
  1054  	}
  1055  	for i, s := range dirEnts {
  1056  		var f File
  1057  		err := readDirectoryHeader(&f, strings.NewReader(s))
  1058  		if err != nil {
  1059  			t.Errorf("error reading #%d: %v", i, err)
  1060  		}
  1061  	}
  1062  }
  1063  
  1064  // Verify we return ErrUnexpectedEOF when length is short.
  1065  func TestIssue10957(t *testing.T) {
  1066  	data := []byte("PK\x03\x040000000PK\x01\x0200000" +
  1067  		"0000000000000000000\x00" +
  1068  		"\x00\x00\x00\x00\x00000000000000PK\x01" +
  1069  		"\x020000000000000000000" +
  1070  		"00000\v\x00\x00\x00\x00\x00000000000" +
  1071  		"00000000000000PK\x01\x0200" +
  1072  		"00000000000000000000" +
  1073  		"00\v\x00\x00\x00\x00\x00000000000000" +
  1074  		"00000000000PK\x01\x020000<" +
  1075  		"0\x00\x0000000000000000\v\x00\v" +
  1076  		"\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00000" +
  1077  		"00000000PK\x01\x0200000000" +
  1078  		"0000000000000000\v\x00\x00\x00" +
  1079  		"\x00\x0000PK\x05\x06000000\x05\x00\xfd\x00\x00\x00" +
  1080  		"\v\x00\x00\x00\x00\x00")
  1081  	z, err := NewReader(bytes.NewReader(data), int64(len(data)))
  1082  	if err != nil {
  1083  		t.Fatal(err)
  1084  	}
  1085  	for i, f := range z.File {
  1086  		r, err := f.Open()
  1087  		if err != nil {
  1088  			continue
  1089  		}
  1090  		if f.UncompressedSize64 < 1e6 {
  1091  			n, err := io.Copy(io.Discard, r)
  1092  			if i == 3 && err != io.ErrUnexpectedEOF {
  1093  				t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
  1094  			}
  1095  			if err == nil && uint64(n) != f.UncompressedSize64 {
  1096  				t.Errorf("file %d: bad size: copied=%d; want=%d", i, n, f.UncompressedSize64)
  1097  			}
  1098  		}
  1099  		r.Close()
  1100  	}
  1101  }
  1102  
  1103  // Verify that this particular malformed zip file is rejected.
  1104  func TestIssue10956(t *testing.T) {
  1105  	data := []byte("PK\x06\x06PK\x06\a0000\x00\x00\x00\x00\x00\x00\x00\x00" +
  1106  		"0000PK\x05\x06000000000000" +
  1107  		"0000\v\x00000\x00\x00\x00\x00\x00\x00\x000")
  1108  	r, err := NewReader(bytes.NewReader(data), int64(len(data)))
  1109  	if err == nil {
  1110  		t.Errorf("got nil error, want ErrFormat")
  1111  	}
  1112  	if r != nil {
  1113  		t.Errorf("got non-nil Reader, want nil")
  1114  	}
  1115  }
  1116  
  1117  // Verify we return ErrUnexpectedEOF when reading truncated data descriptor.
  1118  func TestIssue11146(t *testing.T) {
  1119  	data := []byte("PK\x03\x040000000000000000" +
  1120  		"000000\x01\x00\x00\x000\x01\x00\x00\xff\xff0000" +
  1121  		"0000000000000000PK\x01\x02" +
  1122  		"0000\b0\b\x00000000000000" +
  1123  		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000PK\x05\x06\x00\x00" +
  1124  		"\x00\x0000\x01\x00\x26\x00\x00\x008\x00\x00\x00\x00\x00")
  1125  	z, err := NewReader(bytes.NewReader(data), int64(len(data)))
  1126  	if err != nil {
  1127  		t.Fatal(err)
  1128  	}
  1129  	r, err := z.File[0].Open()
  1130  	if err != nil {
  1131  		t.Fatal(err)
  1132  	}
  1133  	_, err = io.ReadAll(r)
  1134  	if err != io.ErrUnexpectedEOF {
  1135  		t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err)
  1136  	}
  1137  	r.Close()
  1138  }
  1139  
  1140  // Verify we do not treat non-zip64 archives as zip64
  1141  func TestIssue12449(t *testing.T) {
  1142  	data := []byte{
  1143  		0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00,
  1144  		0x00, 0x00, 0x6b, 0xb4, 0xba, 0x46, 0x00, 0x00,
  1145  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1146  		0x00, 0x00, 0x03, 0x00, 0x18, 0x00, 0xca, 0x64,
  1147  		0x55, 0x75, 0x78, 0x0b, 0x00, 0x50, 0x4b, 0x05,
  1148  		0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
  1149  		0x00, 0x49, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00,
  1150  		0x00, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x0a,
  1151  		0x50, 0x4b, 0x07, 0x08, 0x1d, 0x88, 0x77, 0xb0,
  1152  		0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
  1153  		0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00,
  1154  		0x08, 0x00, 0x00, 0x00, 0x6b, 0xb4, 0xba, 0x46,
  1155  		0x1d, 0x88, 0x77, 0xb0, 0x07, 0x00, 0x00, 0x00,
  1156  		0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x18, 0x00,
  1157  		0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1158  		0xa0, 0x81, 0x00, 0x00, 0x00, 0x00, 0xca, 0x64,
  1159  		0x55, 0x75, 0x78, 0x0b, 0x00, 0x50, 0x4b, 0x05,
  1160  		0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
  1161  		0x00, 0x49, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00,
  1162  		0x00, 0x97, 0x2b, 0x49, 0x23, 0x05, 0xc5, 0x0b,
  1163  		0xa7, 0xd1, 0x52, 0xa2, 0x9c, 0x50, 0x4b, 0x06,
  1164  		0x07, 0xc8, 0x19, 0xc1, 0xaf, 0x94, 0x9c, 0x61,
  1165  		0x44, 0xbe, 0x94, 0x19, 0x42, 0x58, 0x12, 0xc6,
  1166  		0x5b, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00,
  1167  		0x00, 0x01, 0x00, 0x01, 0x00, 0x69, 0x00, 0x00,
  1168  		0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
  1169  	}
  1170  	// Read in the archive.
  1171  	_, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data)))
  1172  	if err != nil {
  1173  		t.Errorf("Error reading the archive: %v", err)
  1174  	}
  1175  }
  1176  
  1177  func TestFS(t *testing.T) {
  1178  	for _, test := range []struct {
  1179  		file string
  1180  		want []string
  1181  	}{
  1182  		{
  1183  			"testdata/unix.zip",
  1184  			[]string{"hello", "dir/bar", "readonly"},
  1185  		},
  1186  		{
  1187  			"testdata/subdir.zip",
  1188  			[]string{"a/b/c"},
  1189  		},
  1190  	} {
  1191  		test := test
  1192  		t.Run(test.file, func(t *testing.T) {
  1193  			t.Parallel()
  1194  			z, err := OpenReader(test.file)
  1195  			if err != nil {
  1196  				t.Fatal(err)
  1197  			}
  1198  			defer z.Close()
  1199  			if err := fstest.TestFS(z, test.want...); err != nil {
  1200  				t.Error(err)
  1201  			}
  1202  		})
  1203  	}
  1204  }
  1205  
  1206  func TestFSWalk(t *testing.T) {
  1207  	for _, test := range []struct {
  1208  		file    string
  1209  		want    []string
  1210  		wantErr bool
  1211  	}{
  1212  		{
  1213  			file: "testdata/unix.zip",
  1214  			want: []string{".", "dir", "dir/bar", "dir/empty", "hello", "readonly"},
  1215  		},
  1216  		{
  1217  			file: "testdata/subdir.zip",
  1218  			want: []string{".", "a", "a/b", "a/b/c"},
  1219  		},
  1220  		{
  1221  			file:    "testdata/dupdir.zip",
  1222  			wantErr: true,
  1223  		},
  1224  	} {
  1225  		test := test
  1226  		t.Run(test.file, func(t *testing.T) {
  1227  			t.Parallel()
  1228  			z, err := OpenReader(test.file)
  1229  			if err != nil {
  1230  				t.Fatal(err)
  1231  			}
  1232  			var files []string
  1233  			sawErr := false
  1234  			err = fs.WalkDir(z, ".", func(path string, d fs.DirEntry, err error) error {
  1235  				if err != nil {
  1236  					if !test.wantErr {
  1237  						t.Errorf("%s: %v", path, err)
  1238  					}
  1239  					sawErr = true
  1240  					return nil
  1241  				}
  1242  				files = append(files, path)
  1243  				return nil
  1244  			})
  1245  			if err != nil {
  1246  				t.Errorf("fs.WalkDir error: %v", err)
  1247  			}
  1248  			if test.wantErr && !sawErr {
  1249  				t.Error("succeeded but want error")
  1250  			} else if !test.wantErr && sawErr {
  1251  				t.Error("unexpected error")
  1252  			}
  1253  			if test.want != nil && !reflect.DeepEqual(files, test.want) {
  1254  				t.Errorf("got %v want %v", files, test.want)
  1255  			}
  1256  		})
  1257  	}
  1258  }
  1259  
  1260  func TestFSModTime(t *testing.T) {
  1261  	t.Parallel()
  1262  	z, err := OpenReader("testdata/subdir.zip")
  1263  	if err != nil {
  1264  		t.Fatal(err)
  1265  	}
  1266  	defer z.Close()
  1267  
  1268  	for _, test := range []struct {
  1269  		name string
  1270  		want time.Time
  1271  	}{
  1272  		{
  1273  			"a",
  1274  			time.Date(2021, 4, 19, 12, 29, 56, 0, timeZone(-7*time.Hour)).UTC(),
  1275  		},
  1276  		{
  1277  			"a/b/c",
  1278  			time.Date(2021, 4, 19, 12, 29, 59, 0, timeZone(-7*time.Hour)).UTC(),
  1279  		},
  1280  	} {
  1281  		fi, err := fs.Stat(z, test.name)
  1282  		if err != nil {
  1283  			t.Errorf("%s: %v", test.name, err)
  1284  			continue
  1285  		}
  1286  		if got := fi.ModTime(); !got.Equal(test.want) {
  1287  			t.Errorf("%s: got modtime %v, want %v", test.name, got, test.want)
  1288  		}
  1289  	}
  1290  }
  1291  
  1292  func TestCVE202127919(t *testing.T) {
  1293  	// Archive containing only the file "../test.txt"
  1294  	data := []byte{
  1295  		0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00,
  1296  		0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1297  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1298  		0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x2e,
  1299  		0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78,
  1300  		0x74, 0x0a, 0xc9, 0xc8, 0x2c, 0x56, 0xc8, 0x2c,
  1301  		0x56, 0x48, 0x54, 0x28, 0x49, 0x2d, 0x2e, 0x51,
  1302  		0x28, 0x49, 0xad, 0x28, 0x51, 0x48, 0xcb, 0xcc,
  1303  		0x49, 0xd5, 0xe3, 0x02, 0x04, 0x00, 0x00, 0xff,
  1304  		0xff, 0x50, 0x4b, 0x07, 0x08, 0xc0, 0xd7, 0xed,
  1305  		0xc3, 0x20, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00,
  1306  		0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14,
  1307  		0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
  1308  		0x00, 0xc0, 0xd7, 0xed, 0xc3, 0x20, 0x00, 0x00,
  1309  		0x00, 0x1a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00,
  1310  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1311  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e,
  1312  		0x2e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74,
  1313  		0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00,
  1314  		0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x39, 0x00,
  1315  		0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00,
  1316  	}
  1317  	r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data)))
  1318  	if err != nil {
  1319  		t.Fatalf("Error reading the archive: %v", err)
  1320  	}
  1321  	_, err = r.Open("test.txt")
  1322  	if err != nil {
  1323  		t.Errorf("Error reading file: %v", err)
  1324  	}
  1325  	if len(r.File) != 1 {
  1326  		t.Fatalf("No entries in the file list")
  1327  	}
  1328  	if r.File[0].Name != "../test.txt" {
  1329  		t.Errorf("Unexpected entry name: %s", r.File[0].Name)
  1330  	}
  1331  	if _, err := r.File[0].Open(); err != nil {
  1332  		t.Errorf("Error opening file: %v", err)
  1333  	}
  1334  }
  1335  
  1336  func TestCVE202133196(t *testing.T) {
  1337  	// Archive that indicates it has 1 << 128 -1 files,
  1338  	// this would previously cause a panic due to attempting
  1339  	// to allocate a slice with 1 << 128 -1 elements.
  1340  	data := []byte{
  1341  		0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08,
  1342  		0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1343  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1344  		0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02,
  1345  		0x03, 0x62, 0x61, 0x65, 0x03, 0x04, 0x00, 0x00,
  1346  		0xff, 0xff, 0x50, 0x4b, 0x07, 0x08, 0xbe, 0x20,
  1347  		0x5c, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00,
  1348  		0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00,
  1349  		0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
  1350  		0x00, 0x00, 0xbe, 0x20, 0x5c, 0x6c, 0x09, 0x00,
  1351  		0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00,
  1352  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1353  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1354  		0x01, 0x02, 0x03, 0x50, 0x4b, 0x06, 0x06, 0x2c,
  1355  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
  1356  		0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1357  		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
  1358  		0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
  1359  		0xff, 0xff, 0xff, 0x31, 0x00, 0x00, 0x00, 0x00,
  1360  		0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00,
  1361  		0x00, 0x00, 0x00, 0x50, 0x4b, 0x06, 0x07, 0x00,
  1362  		0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00,
  1363  		0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50,
  1364  		0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff,
  1365  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  1366  		0xff, 0xff, 0xff, 0x00, 0x00,
  1367  	}
  1368  	_, err := NewReader(bytes.NewReader(data), int64(len(data)))
  1369  	if err != ErrFormat {
  1370  		t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
  1371  	}
  1372  
  1373  	// Also check that an archive containing a handful of empty
  1374  	// files doesn't cause an issue
  1375  	b := bytes.NewBuffer(nil)
  1376  	w := NewWriter(b)
  1377  	for i := 0; i < 5; i++ {
  1378  		_, err := w.Create("")
  1379  		if err != nil {
  1380  			t.Fatalf("Writer.Create failed: %s", err)
  1381  		}
  1382  	}
  1383  	if err := w.Close(); err != nil {
  1384  		t.Fatalf("Writer.Close failed: %s", err)
  1385  	}
  1386  	r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len()))
  1387  	if err != nil {
  1388  		t.Fatalf("NewReader failed: %s", err)
  1389  	}
  1390  	if len(r.File) != 5 {
  1391  		t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File))
  1392  	}
  1393  }
  1394  
  1395  func TestCVE202139293(t *testing.T) {
  1396  	// directory size is so large, that the check in Reader.init
  1397  	// overflows when subtracting from the archive size, causing
  1398  	// the pre-allocation check to be bypassed.
  1399  	data := []byte{
  1400  		0x50, 0x4b, 0x06, 0x06, 0x05, 0x06, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b,
  1401  		0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  1402  		0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b,
  1403  		0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  1404  		0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
  1405  		0xff, 0x50, 0xfe, 0x00, 0xff, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xff,
  1406  	}
  1407  	_, err := NewReader(bytes.NewReader(data), int64(len(data)))
  1408  	if err != ErrFormat {
  1409  		t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
  1410  	}
  1411  }
  1412  
  1413  func TestCVE202141772(t *testing.T) {
  1414  	// Archive contains a file whose name is exclusively made up of '/', '\'
  1415  	// characters, or "../", "..\" paths, which would previously cause a panic.
  1416  	//
  1417  	//  Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
  1418  	// --------  ------  ------- ---- ---------- ----- --------  ----
  1419  	//        0  Stored        0   0% 08-05-2021 18:32 00000000  /
  1420  	//        0  Stored        0   0% 09-14-2021 12:59 00000000  //
  1421  	//        0  Stored        0   0% 09-14-2021 12:59 00000000  \
  1422  	//       11  Stored       11   0% 09-14-2021 13:04 0d4a1185  /test.txt
  1423  	// --------          -------  ---                            -------
  1424  	//       11               11   0%                            4 files
  1425  	data := []byte{
  1426  		0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x08,
  1427  		0x00, 0x00, 0x06, 0x94, 0x05, 0x53, 0x00, 0x00,
  1428  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1429  		0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x50,
  1430  		0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
  1431  		0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
  1432  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1433  		0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x50,
  1434  		0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
  1435  		0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
  1436  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1437  		0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x50, 0x4b,
  1438  		0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
  1439  		0x91, 0x68, 0x2e, 0x53, 0x85, 0x11, 0x4a, 0x0d,
  1440  		0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
  1441  		0x09, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
  1442  		0x74, 0x2e, 0x74, 0x78, 0x74, 0x68, 0x65, 0x6c,
  1443  		0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
  1444  		0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x0a, 0x00,
  1445  		0x00, 0x08, 0x00, 0x00, 0x06, 0x94, 0x05, 0x53,
  1446  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1447  		0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  1448  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
  1449  		0xed, 0x41, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x50,
  1450  		0x4b, 0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00,
  1451  		0x00, 0x00, 0x00, 0x78, 0x67, 0x2e, 0x53, 0x00,
  1452  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1453  		0x00, 0x00, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00,
  1454  		0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
  1455  		0x00, 0x1f, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x0a,
  1456  		0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  1457  		0x00, 0x18, 0x00, 0x93, 0x98, 0x25, 0x57, 0x25,
  1458  		0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
  1459  		0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
  1460  		0xa9, 0xd7, 0x01, 0x50, 0x4b, 0x01, 0x02, 0x3f,
  1461  		0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
  1462  		0x67, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
  1463  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  1464  		0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1465  		0x00, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00,
  1466  		0x00, 0x5c, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00,
  1467  		0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x93, 0x98,
  1468  		0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
  1469  		0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
  1470  		0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x50, 0x4b,
  1471  		0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00,
  1472  		0x00, 0x00, 0x91, 0x68, 0x2e, 0x53, 0x85, 0x11,
  1473  		0x4a, 0x0d, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00,
  1474  		0x00, 0x00, 0x09, 0x00, 0x24, 0x00, 0x00, 0x00,
  1475  		0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
  1476  		0x5e, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
  1477  		0x74, 0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20,
  1478  		0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18,
  1479  		0x00, 0xa9, 0x80, 0x51, 0x01, 0x26, 0xa9, 0xd7,
  1480  		0x01, 0x31, 0xd1, 0x57, 0x01, 0x26, 0xa9, 0xd7,
  1481  		0x01, 0xdf, 0x48, 0x85, 0xf9, 0x25, 0xa9, 0xd7,
  1482  		0x01, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00,
  1483  		0x00, 0x04, 0x00, 0x04, 0x00, 0x31, 0x01, 0x00,
  1484  		0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
  1485  	}
  1486  	r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data)))
  1487  	if err != nil {
  1488  		t.Fatalf("Error reading the archive: %v", err)
  1489  	}
  1490  	entryNames := []string{`/`, `//`, `\`, `/test.txt`}
  1491  	var names []string
  1492  	for _, f := range r.File {
  1493  		names = append(names, f.Name)
  1494  		if _, err := f.Open(); err != nil {
  1495  			t.Errorf("Error opening %q: %v", f.Name, err)
  1496  		}
  1497  		if _, err := r.Open(f.Name); err == nil {
  1498  			t.Errorf("Opening %q with fs.FS API succeeded", f.Name)
  1499  		}
  1500  	}
  1501  	if !reflect.DeepEqual(names, entryNames) {
  1502  		t.Errorf("Unexpected file entries: %q", names)
  1503  	}
  1504  	if _, err := r.Open(""); err == nil {
  1505  		t.Errorf("Opening %q with fs.FS API succeeded", "")
  1506  	}
  1507  	if _, err := r.Open("test.txt"); err != nil {
  1508  		t.Errorf("Error opening %q with fs.FS API: %v", "test.txt", err)
  1509  	}
  1510  	dirEntries, err := fs.ReadDir(r, ".")
  1511  	if err != nil {
  1512  		t.Fatalf("Error reading the root directory: %v", err)
  1513  	}
  1514  	if len(dirEntries) != 1 || dirEntries[0].Name() != "test.txt" {
  1515  		t.Errorf("Unexpected directory entries")
  1516  		for _, dirEntry := range dirEntries {
  1517  			_, err := r.Open(dirEntry.Name())
  1518  			t.Logf("%q (Open error: %v)", dirEntry.Name(), err)
  1519  		}
  1520  		t.FailNow()
  1521  	}
  1522  	info, err := dirEntries[0].Info()
  1523  	if err != nil {
  1524  		t.Fatalf("Error reading info entry: %v", err)
  1525  	}
  1526  	if name := info.Name(); name != "test.txt" {
  1527  		t.Errorf("Inconsistent name in info entry: %v", name)
  1528  	}
  1529  }
  1530  
  1531  func TestUnderSize(t *testing.T) {
  1532  	z, err := OpenReader("testdata/readme.zip")
  1533  	if err != nil {
  1534  		t.Fatal(err)
  1535  	}
  1536  	defer z.Close()
  1537  
  1538  	for _, f := range z.File {
  1539  		f.UncompressedSize64 = 1
  1540  	}
  1541  
  1542  	for _, f := range z.File {
  1543  		t.Run(f.Name, func(t *testing.T) {
  1544  			rd, err := f.Open()
  1545  			if err != nil {
  1546  				t.Fatal(err)
  1547  			}
  1548  			defer rd.Close()
  1549  
  1550  			_, err = io.Copy(io.Discard, rd)
  1551  			if err != ErrFormat {
  1552  				t.Fatalf("Error mismatch\n\tGot:  %v\n\tWant: %v", err, ErrFormat)
  1553  			}
  1554  		})
  1555  	}
  1556  }