From 4ead944ad71398931b70a09ea40ba9ce742f4bf7 Mon Sep 17 00:00:00 2001 From: Matt Dainty Date: Tue, 12 Dec 2023 09:27:38 +0000 Subject: [PATCH] fix: Handle lack of CRC digests (#143) * test: Add test case for lack of CRC digests * fix: Handle lack of CRC digests Also handle optional booleans correctly. --- reader_test.go | 10 ++++++ struct.go | 19 ++++++------ testdata/file_and_empty.7z | Bin 0 -> 109 bytes types.go | 61 ++++++++++++++++++++++--------------- 4 files changed, 55 insertions(+), 35 deletions(-) create mode 100644 testdata/file_and_empty.7z diff --git a/reader_test.go b/reader_test.go index b3fe8f7..406f1ed 100644 --- a/reader_test.go +++ b/reader_test.go @@ -35,6 +35,12 @@ func readArchive(t *testing.T, r *sevenzip.ReadCloser) { rc.Close() + if f.UncompressedSize > 0 && f.CRC32 == 0 { + t.Log("archive member", f.Name, "has no CRC") + + continue + } + if !util.CRC32Equal(h.Sum(nil), f.CRC32) { t.Fatal(errors.New("CRC doesn't match")) } @@ -142,6 +148,10 @@ func TestOpenReader(t *testing.T) { name: "issue 87", file: "issue87.7z", }, + { + name: "issue 112", + file: "file_and_empty.7z", + }, { name: "issue 113", file: "COMPRESS-492.7z", diff --git a/struct.go b/struct.go index 9f4d77b..f95a6ea 100644 --- a/struct.go +++ b/struct.go @@ -39,7 +39,6 @@ type packInfo struct { streams uint64 size []uint64 digest []uint32 - defined []bool } type coder struct { @@ -174,16 +173,14 @@ func (f *folder) unpackSize() uint64 { } type unpackInfo struct { - folder []*folder - digest []uint32 - defined []bool + folder []*folder + digest []uint32 } type subStreamsInfo struct { streams []uint64 size []uint64 digest []uint32 - defined []bool } type streamsInfo struct { @@ -205,13 +202,15 @@ func (si *streamsInfo) FileFolderAndSize(file int) (int, uint64) { var ( folder int - streams uint64 + streams uint64 = 1 ) - for folder, streams = range si.subStreamsInfo.streams { - total += streams - if uint64(file) < total { - break + if si.subStreamsInfo != nil { + for folder, streams = range si.subStreamsInfo.streams { + total += streams + if uint64(file) < total { + break + } } } diff --git a/testdata/file_and_empty.7z b/testdata/file_and_empty.7z new file mode 100644 index 0000000000000000000000000000000000000000..a94a9f7e7adc5df73ea5a8506403b817251a3671 GIT binary patch literal 109 zcmXr7+Ou9=hJnSvzGagr0|Zz=Y5pd|>mH>*ke;fLmYI{Pker`alA2di%*evVz{n}e wz|PIcz{tqJ1JuaM#K-8s&)6U+$&ka4$WX+P&X5W;CY2$Vp@5-;p%QE)0M$zq&j0`b literal 0 HcmV?d00001 diff --git a/types.go b/types.go index 51cb7d2..fb5c4d0 100644 --- a/types.go +++ b/types.go @@ -132,24 +132,23 @@ func readSizes(r io.ByteReader, count uint64) ([]uint64, error) { return sizes, nil } -func readCRC(r util.Reader, count uint64) ([]uint32, []bool, error) { +func readCRC(r util.Reader, count uint64) ([]uint32, error) { defined, err := readOptionalBool(r, count) if err != nil { - return nil, nil, err + return nil, err } crcs := make([]uint32, count) - for i := uint64(0); i < count; i++ { - var crc uint32 - if err := binary.Read(r, binary.LittleEndian, &crc); err != nil { - return nil, nil, fmt.Errorf("readCRC: Read error: %w", err) + for i := range defined { + if defined[i] { + if err := binary.Read(r, binary.LittleEndian, &crcs[i]); err != nil { + return nil, fmt.Errorf("readCRC: Read error: %w", err) + } } - - crcs[i] = crc } - return crcs, defined, nil + return crcs, nil } //nolint:cyclop @@ -185,7 +184,7 @@ func readPackInfo(r util.Reader) (*packInfo, error) { } if id == idCRC { - if p.digest, p.defined, err = readCRC(r, p.streams); err != nil { + if p.digest, err = readCRC(r, p.streams); err != nil { return nil, err } @@ -385,7 +384,7 @@ func readUnpackInfo(r util.Reader) (*unpackInfo, error) { } if id == idCRC { - if u.digest, u.defined, err = readCRC(r, folders); err != nil { + if u.digest, err = readCRC(r, folders); err != nil { return nil, err } @@ -462,7 +461,7 @@ func readSubStreamsInfo(r util.Reader, folder []*folder) (*subStreamsInfo, error } if id == idCRC { - if s.digest, s.defined, err = readCRC(r, files); err != nil { + if s.digest, err = readCRC(r, files); err != nil { return nil, err } @@ -533,7 +532,7 @@ func readStreamsInfo(r util.Reader) (*streamsInfo, error) { } func readTimes(r util.Reader, count uint64) ([]time.Time, error) { - _, err := readOptionalBool(r, count) + defined, err := readOptionalBool(r, count) if err != nil { return nil, err } @@ -555,15 +554,17 @@ func readTimes(r util.Reader, count uint64) ([]time.Time, error) { return nil, errors.New("sevenzip: TODO readTimes external") //nolint:goerr113 } - times := make([]time.Time, 0, count) + times := make([]time.Time, count) - for i := uint64(0); i < count; i++ { - var ft windows.Filetime - if err := binary.Read(r, binary.LittleEndian, &ft); err != nil { - return nil, fmt.Errorf("readTimes: Read error: %w", err) - } + for i := range defined { + if defined[i] { + var ft windows.Filetime + if err := binary.Read(r, binary.LittleEndian, &ft); err != nil { + return nil, fmt.Errorf("readTimes: Read error: %w", err) + } - times = append(times, time.Unix(0, ft.Nanoseconds()).UTC()) + times[i] = time.Unix(0, ft.Nanoseconds()).UTC() + } } return times, nil @@ -625,7 +626,7 @@ func readNames(r util.Reader, count, length uint64) ([]string, error) { } func readAttributes(r util.Reader, count uint64) ([]uint32, error) { - _, err := readOptionalBool(r, count) + defined, err := readOptionalBool(r, count) if err != nil { return nil, err } @@ -648,9 +649,12 @@ func readAttributes(r util.Reader, count uint64) ([]uint32, error) { } attributes := make([]uint32, count) - for i := uint64(0); i < count; i++ { - if err := binary.Read(r, binary.LittleEndian, &attributes[i]); err != nil { - return nil, fmt.Errorf("readAttributes: Read error: %w", err) + + for i := range defined { + if defined[i] { + if err := binary.Read(r, binary.LittleEndian, &attributes[i]); err != nil { + return nil, fmt.Errorf("readAttributes: Read error: %w", err) + } } } @@ -827,6 +831,10 @@ func readHeader(r util.Reader) (*header, error) { return nil, errUnexpectedID } + if h.streamsInfo == nil || h.filesInfo == nil { + return h, nil + } + j := 0 for i := range h.filesInfo.file { @@ -834,7 +842,10 @@ func readHeader(r util.Reader) (*header, error) { continue } - h.filesInfo.file[i].CRC32 = h.streamsInfo.subStreamsInfo.digest[j] + if h.streamsInfo.subStreamsInfo != nil { + h.filesInfo.file[i].CRC32 = h.streamsInfo.subStreamsInfo.digest[j] + } + _, h.filesInfo.file[i].UncompressedSize = h.streamsInfo.FileFolderAndSize(j) j++ }