⬥ ID3 encoding/decoding library in Go ⬥
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
2.0 KiB

package v2
import (
"bytes"
"fmt"
"io"
"strconv"
"github.com/Unbewohnte/id3ed/util"
)
// ID3v2.x header structure
type Header struct {
Identifier string
Version string
Unsynchronisated bool
Compressed bool
Size int64 // size of the whole tag - 10 header bytes
}
// Reads and structuralises ID3v2 header
func GetHeader(rs io.ReadSeeker) (*Header, error) {
var header Header
rs.Seek(0, io.SeekStart)
identifier, err := util.Read(rs, 3)
if err != nil {
return nil, err
}
// check if ID3v2 is used
if !bytes.Equal([]byte(HEADERIDENTIFIER), identifier) {
return nil, fmt.Errorf("no ID3v2 identifier found")
}
header.Identifier = string(identifier)
// version
majorVersionByte, err := util.Read(rs, 1)
if err != nil {
return nil, err
}
revisionNumberByte, err := util.Read(rs, 1)
if err != nil {
return nil, err
}
majorVersion, err := util.BytesToInt(majorVersionByte)
if err != nil {
return nil, err
}
revisionNumber, err := util.BytesToInt(revisionNumberByte)
if err != nil {
return nil, err
}
header.Version = fmt.Sprintf("%d%d", -majorVersion, revisionNumber)
// flags
flags, err := util.Read(rs, 1)
if err != nil {
return nil, err
}
bits := fmt.Sprintf("%08b", flags) // 1 byte is 8 bits
if bits[0] == 1 {
header.Unsynchronisated = true
} else {
header.Unsynchronisated = false
}
if bits[1] == 1 {
header.Compressed = true
} else {
header.Compressed = false
}
// size
sizeBytes, err := util.Read(rs, 4)
if err != nil {
return nil, err
}
// represent each byte in size as binary and get rid from the first useless bit,
// then concatenate filtered parts
var filteredSizeStr string
for _, b := range sizeBytes {
// the first bit is always 0, so filter it out
filteredPart := fmt.Sprintf("%08b", b)[1:] // byte is 8 bits
filteredSizeStr += filteredPart
}
// converting filtered binary size into usable int64
size, err := strconv.ParseInt(filteredSizeStr, 2, 64)
if err != nil {
return nil, err
}
header.Size = int64(size)
return &header, nil
}