1
1
mirror of https://github.com/wader/fq.git synced 2024-11-28 11:42:50 +03:00
fq/format/gzip/gzip.go
Mattias Wadman 7b27e506f1 mp4,bitio: Fix broken pssh decoding and add proper reader cloning to bitio
PSSH decoding probably got broken in some refactoring. system id is 16 bytes,
also scalar mapper should use cloned reader to not affect reader which in the case
broke reading system id bytes.

Add test with playread and widevine pssh boxes

Related to #282
2022-05-28 13:42:38 +02:00

126 lines
2.9 KiB
Go

package gz
// https://tools.ietf.org/html/rfc1952
// TODO: test name, comment etc
// TODO: verify isize?
import (
"compress/flate"
"hash/crc32"
"io"
"github.com/wader/fq/format"
"github.com/wader/fq/format/registry"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/scalar"
)
var probeFormat decode.Group
func init() {
registry.MustRegister(decode.Format{
Name: format.GZIP,
Description: "gzip compression",
Groups: []string{format.PROBE},
DecodeFn: gzDecode,
Dependencies: []decode.Dependency{
{Names: []string{format.PROBE}, Group: &probeFormat},
},
})
}
const delfateMethod = 8
var compressionMethodNames = scalar.UToSymStr{
delfateMethod: "deflate",
}
var osNames = scalar.UToSymStr{
0: "fat",
1: "amiga",
2: "vms",
3: "unix",
4: "vm_cms",
5: "atari_tOS",
6: "hpfs",
7: "Mmcintosh",
8: "z_system",
9: "cpm",
10: "tops_20",
11: "ntfs",
12: "qdos",
13: "acorn_riscos",
}
var deflateExtraFlagsNames = scalar.UToSymStr{
2: "slow",
4: "fast",
}
func gzDecode(d *decode.D, in any) any {
d.Endian = decode.LittleEndian
d.FieldRawLen("identification", 2*8, d.AssertBitBuf([]byte("\x1f\x8b")))
compressionMethod := d.FieldU8("compression_method", compressionMethodNames)
hasHeaderCRC := false
hasExtra := false
hasName := false
hasComment := false
d.FieldStruct("flags", func(d *decode.D) {
d.FieldBool("text")
hasHeaderCRC = d.FieldBool("header_crc")
hasExtra = d.FieldBool("extra")
hasName = d.FieldBool("name")
hasComment = d.FieldBool("comment")
d.FieldU3("reserved")
})
d.FieldU32("mtime", scalar.DescriptionActualUUnixTime)
switch compressionMethod {
case delfateMethod:
d.FieldU8("extra_flags", deflateExtraFlagsNames)
default:
d.FieldU8("extra_flags")
}
d.FieldU8("os", osNames)
if hasExtra {
// TODO:
xLen := d.FieldU16("xlen")
d.FieldRawLen("extra_fields", int64(xLen*8))
}
if hasName {
d.FieldUTF8Null("name")
}
if hasComment {
d.FieldUTF8Null("comment")
}
if hasHeaderCRC {
// TODO: validate
d.FieldRawLen("header_crc", 16, scalar.RawHex)
}
var rFn func(r io.Reader) io.Reader
switch compressionMethod {
case delfateMethod:
// bitio.NewIOReadSeeker implements io.ByteReader so that deflate don't do own
// buffering and might read more than needed messing up knowing compressed size
rFn = func(r io.Reader) io.Reader { return flate.NewReader(r) }
}
if rFn != nil {
readCompressedSize, uncompressedBR, dv, _, _ := d.TryFieldReaderRangeFormat("uncompressed", d.Pos(), d.BitsLeft(), rFn, probeFormat, nil)
if uncompressedBR != nil {
if dv == nil {
d.FieldRootBitBuf("uncompressed", uncompressedBR)
}
d.FieldRawLen("compressed", readCompressedSize)
crc32W := crc32.NewIEEE()
// TODO: cleanup clone
d.MustCopyBits(crc32W, d.MustCloneReadSeeker(uncompressedBR))
d.FieldU32("crc32", d.ValidateUBytes(crc32W.Sum(nil)), scalar.ActualHex)
d.FieldU32("isize")
}
}
return nil
}