Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions internal/format/au.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,29 +49,29 @@ const (
// for a valid AU file. It returns the total size of the detected
// AU data, or 0 and an error if no valid AU file is found at the beginning.
// The reader's position will be at the end of the AU data upon successful return.
func ScanSunAudio(r *Reader) (uint64, error) {
func ScanSunAudio(r *Reader) (*ScanResult, error) {
// We'll use a 24-byte buffer for the fixed part of the AU header.
headerBuf := make([]byte, MIN_AU_HEADER_SIZE)

// Read the first MIN_AU_HEADER_SIZE bytes
n, err := io.ReadFull(r, headerBuf)
if err != nil {
if err == io.EOF {
return 0, fmt.Errorf("reader too small (%d bytes) to contain a minimum AU header (%d bytes)", n, MIN_AU_HEADER_SIZE)
return nil, fmt.Errorf("reader too small (%d bytes) to contain a minimum AU header (%d bytes)", n, MIN_AU_HEADER_SIZE)
}
return 0, fmt.Errorf("failed to read AU header: %w", err)
return nil, fmt.Errorf("failed to read AU header: %w", err)
}

// 1. Check Magic Number (Big Endian)
magic := binary.BigEndian.Uint32(headerBuf[0:4])
if magic != AU_MAGIC {
return 0, fmt.Errorf("reader does not start with AU magic signature")
return nil, fmt.Errorf("reader does not start with AU magic signature")
}

// 2. Read Header Size (Big Endian)
headerSize := binary.BigEndian.Uint32(headerBuf[4:8])
if headerSize < MIN_AU_HEADER_SIZE {
return 0, fmt.Errorf("AU header size (%d) is invalid", headerSize)
return nil, fmt.Errorf("AU header size (%d) is invalid", headerSize)
}

// 3. Read Data Size (Big Endian)
Expand All @@ -87,9 +87,9 @@ func ScanSunAudio(r *Reader) (uint64, error) {
if err != nil {
if err == io.EOF && skipped < int(skipBytes) {
// Header is truncated, cannot be a valid AU file.
return 0, fmt.Errorf("AU header truncated: expected %d bytes, got %d", headerSize, MIN_AU_HEADER_SIZE+uint32(skipped))
return nil, fmt.Errorf("AU header truncated: expected %d bytes, got %d", headerSize, MIN_AU_HEADER_SIZE+uint32(skipped))
}
return 0, fmt.Errorf("failed to skip remaining header bytes: %w", err)
return nil, fmt.Errorf("failed to skip remaining header bytes: %w", err)
}
bytesRead += uint64(skipped)
}
Expand All @@ -100,7 +100,7 @@ func ScanSunAudio(r *Reader) (uint64, error) {
// We've read the header, so the remaining size is what's left in the reader.
// Since we don't know the full length, we'll return the bytes read so far.
// The caller would typically read until EOF for the data.
return bytesRead, nil // Indicate that the valid part up to the header is found
return &ScanResult{Size: bytesRead}, nil // Indicate that the valid part up to the header is found
} else {
// Data size is explicitly defined.
totalAUSize = uint64(headerSize) + uint64(dataSize)
Expand All @@ -114,14 +114,14 @@ func ScanSunAudio(r *Reader) (uint64, error) {
if err != nil {
if err == io.EOF && skipped < dataBytesToRead {
// Data chunk is truncated. The valid AU ends here.
return bytesRead + uint64(skipped), nil
return &ScanResult{Size: bytesRead + uint64(skipped)}, nil
}
return 0, fmt.Errorf("failed to skip AU data: %w", err)
return nil, fmt.Errorf("failed to skip AU data: %w", err)
}
bytesRead += uint64(skipped)
}
}

// If we reach here, we've successfully scanned and potentially skipped all valid AU data.
return totalAUSize, nil
return &ScanResult{Size: totalAUSize}, nil
}
17 changes: 8 additions & 9 deletions internal/format/gif.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,30 +64,30 @@ type gifDecoder struct {
tmp [1024]byte // must be at least 768 so we can read color table
}

func ScanGIF(r *Reader) (uint64, error) {
func ScanGIF(r *Reader) (*ScanResult, error) {
d := gifDecoder{
loopCount: -1,
r: r,
}

err := d.readHeaderAndScreenDescriptor()
if err != nil {
return 0, err
return nil, err
}

for {
c, err := readByte(d.r.(io.ByteReader))
if err != nil {
return 0, fmt.Errorf("gif: reading frames: %v", err)
return nil, fmt.Errorf("gif: reading frames: %v", err)
}
switch c {
case sExtension:
if err = d.readExtension(); err != nil {
return 0, err
return nil, err
}
case sImageDescriptor:
if err = d.readImageDescriptor(); err != nil {
return 0, err
return nil, err
}

//if len(d.image) == 1 {
Expand All @@ -97,12 +97,11 @@ func ScanGIF(r *Reader) (uint64, error) {
case sTrailer:
if !d.dataParsed {
// If we haven't parsed the image descriptor, we can't have a valid image.
return 0, errors.New("gif: missing image data")
return nil, errors.New("gif: missing image data")
}
return r.n, nil

return &ScanResult{Size: r.n}, nil
default:
return 0, fmt.Errorf("gif: unknown block type: 0x%.2x", c)
return nil, fmt.Errorf("gif: unknown block type: 0x%.2x", c)
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion internal/format/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@
// THE SOFTWARE.
package format

type ScanResult struct {
Name string
Ext string
Size uint64
}

type FileHeader struct {
Ext string // File extension, e.g., "mp3", "wav"
Signatures [][]byte
ScanFile func(r *Reader) (uint64, error)
ScanFile func(r *Reader) (*ScanResult, error)
}

var fileHeaders = []FileHeader{
Expand Down
20 changes: 10 additions & 10 deletions internal/format/jpeg.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,24 +71,24 @@ func discard(n int, r io.Reader) error {
// It returns the total size of the JPEG file (the offset of the EOI marker
// plus its 2-byte length) or the buffer's length if the file appears truncated.
// It returns an error if the file is malformed or doesn't start with an SOI marker.
func ScanJPEG(r *Reader) (uint64, error) {
func ScanJPEG(r *Reader) (*ScanResult, error) {
// Check for the Start Of Image marker.
var tmp [2]byte

_, err := r.Read(tmp[:])
if err != nil {
return 0, err
return nil, err
}

if tmp[0] != 0xff || tmp[1] != soiMarker {
return 0, fmt.Errorf("missing SOI marker")
return nil, fmt.Errorf("missing SOI marker")
}

// Process the remaining segments until the End Of Image marker.
for {
_, err := r.Read(tmp[:])
if err != nil {
return 0, err
return nil, err
}
for tmp[0] != 0xff {
// Strictly speaking, this is a format error. However, libjpeg is
Expand All @@ -114,7 +114,7 @@ func ScanJPEG(r *Reader) (uint64, error) {
tmp[0] = tmp[1]
tmp[1], err = r.ReadByte()
if err != nil {
return 0, err
return nil, err
}
}
marker := tmp[1]
Expand All @@ -127,11 +127,11 @@ func ScanJPEG(r *Reader) (uint64, error) {
// number of fill bytes, which are bytes assigned code X'FF'".
marker, err = r.ReadByte()
if err != nil {
return 0, err
return nil, err
}
}
if marker == eoiMarker { // End Of Image.
return uint64(r.BytesRead()), nil
return &ScanResult{Size: uint64(r.BytesRead())}, nil
}
if rst0Marker <= marker && marker <= rst7Marker {
// Figures B.2 and B.16 of the specification suggest that restart markers should
Expand All @@ -146,11 +146,11 @@ func ScanJPEG(r *Reader) (uint64, error) {
// Read the 16-bit length of the segment. The value includes the 2 bytes for the
// length itself, so we subtract 2 to get the number of remaining bytes.
if _, err = r.Read(tmp[:]); err != nil {
return 0, err
return nil, err
}
n := int(tmp[0])<<8 + int(tmp[1]) - 2
if n < 0 {
return 0, fmt.Errorf("short segment length")
return nil, fmt.Errorf("short segment length")
}

switch marker {
Expand All @@ -168,7 +168,7 @@ func ScanJPEG(r *Reader) (uint64, error) {
}
}
if err != nil {
return 0, err
return nil, err
}
}
}
14 changes: 7 additions & 7 deletions internal/format/mp3.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,14 @@ func parseMP3Header(headerBytes []byte) (mp3Header, bool) {
// of the detected stream within the buffer, or 0 and an error if no
// valid stream is found. An optional ID3v2 tag at the very beginning
// is allowed and skipped.
func ScanMP3(r *Reader) (uint64, error) {
func ScanMP3(r *Reader) (*ScanResult, error) {
var n int // Tracks the current position in the buffer

// Check for and skip an initial ID3v2 tag (if present)
// This is the only non-audio content allowed at the very start of the stream.
skippedBytes, err := skipID3v2Tag(r)
if err != nil {
return 0, fmt.Errorf("error processing initial ID3v2 tag: %w", err)
return nil, fmt.Errorf("error processing initial ID3v2 tag: %w", err)
}
n += skippedBytes // Move past the ID3v2 tag

Expand All @@ -236,7 +236,7 @@ func ScanMP3(r *Reader) (uint64, error) {
// This is critical for subsequent iterations to get the next frame's header.
_, err = r.Read(headerBytes[:])
if err != nil && err != io.EOF {
return 0, err
return nil, err
}
if err == io.EOF {
break
Expand All @@ -249,11 +249,11 @@ func ScanMP3(r *Reader) (uint64, error) {
}

if header.FrameSize < minMp3FrameSize || header.FrameSize > maxMp3FrameSize {
return 0, fmt.Errorf("invalid mp3 frame size")
return nil, fmt.Errorf("invalid mp3 frame size")
}

if _, err := r.Discard(header.FrameSize - 4); err != nil {
return 0, err
return nil, err
}

n += header.FrameSize
Expand All @@ -264,7 +264,7 @@ func ScanMP3(r *Reader) (uint64, error) {
// Requiring at least 2 frames provides more confidence.
const MinimumRequiredFrames = 2
if numFrames < MinimumRequiredFrames {
return 0, fmt.Errorf("detected MP3 stream is too short (only %d frames)", numFrames)
return nil, fmt.Errorf("detected MP3 stream is too short (only %d frames)", numFrames)
}
return uint64(n), nil
return &ScanResult{Size: uint64(n)}, nil
}
14 changes: 7 additions & 7 deletions internal/format/pdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ var (
// uint64: The size of the carved PDF file in bytes.
// error: An error if the PDF header or EOF marker is not found, or if the
// EOF marker appears before the header.
func ScanPDF(r *Reader) (uint64, error) {
func ScanPDF(r *Reader) (*ScanResult, error) {
var headerBuf [5]byte
_, err := r.Read(headerBuf[:])
if err != nil {
return 0, err
return nil, err
}

if !bytes.Equal(headerBuf[:], pdfHeader) {
return 0, fmt.Errorf("invalid pdf file")
return nil, fmt.Errorf("invalid pdf file")
}

var size uint64
Expand All @@ -74,22 +74,22 @@ func ScanPDF(r *Reader) (uint64, error) {

seeked, err := SeekAt(r, eofMarker, pdfMaxFileSize)
if err != nil {
return 0, err
return nil, err
}
if !seeked {
break
}

_, err = r.Discard(len(eofMarker))
if err != nil {
return 0, err
return nil, err
}

size = r.BytesRead() - n + uint64(len(eofMarker))
}

if size == 0 {
return 0, fmt.Errorf("invalid pdf file")
return nil, fmt.Errorf("invalid pdf file")
}
return size, nil
return &ScanResult{Size: size}, nil
}
8 changes: 4 additions & 4 deletions internal/format/png.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (d *decoder) verifyChecksum() error {
return nil
}

func ScanPNG(r *Reader) (uint64, error) {
func ScanPNG(r *Reader) (*ScanResult, error) {
d := &decoder{
r: r,
crc: crc32.NewIEEE(),
Expand All @@ -163,16 +163,16 @@ func ScanPNG(r *Reader) (uint64, error) {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return 0, err
return nil, err
}

for d.stage != dsSeenIEND {
if err := d.parseChunk(); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return 0, err
return nil, err
}
}
return r.BytesRead(), nil
return &ScanResult{Size: r.BytesRead()}, nil
}
Loading
Loading