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.
103 lines
2.2 KiB
103 lines
2.2 KiB
3 years ago
|
package v2
|
||
3 years ago
|
|
||
|
//////////////////////////////////////
|
||
|
//(ᗜˬᗜ)~⭐//Under construction//(ᗜ‸ᗜ)//
|
||
|
//////////////////////////////////////
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"io"
|
||
3 years ago
|
"strconv"
|
||
3 years ago
|
|
||
|
"github.com/Unbewohnte/id3ed/util"
|
||
3 years ago
|
)
|
||
|
|
||
3 years ago
|
// ID3v2.x header structure
|
||
3 years ago
|
type Header struct {
|
||
3 years ago
|
Identifier string
|
||
|
Version string
|
||
|
Unsynchronisated bool
|
||
|
Compressed bool
|
||
3 years ago
|
Size int64 // size of the whole tag - 10 header bytes
|
||
3 years ago
|
}
|
||
|
|
||
3 years ago
|
// Reads and structuralises ID3v2 header
|
||
3 years ago
|
func GetHeader(rs io.ReadSeeker) (*Header, error) {
|
||
|
var header Header
|
||
|
|
||
|
rs.Seek(0, io.SeekStart)
|
||
|
|
||
3 years ago
|
identifier, err := util.Read(rs, 3)
|
||
3 years ago
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
// check if ID3v2 is used
|
||
|
if !bytes.Equal([]byte(ID3v2IDENTIFIER), identifier) {
|
||
3 years ago
|
return nil, fmt.Errorf("no ID3v2 identifier found")
|
||
3 years ago
|
}
|
||
|
header.Identifier = string(identifier)
|
||
|
|
||
3 years ago
|
// version
|
||
3 years ago
|
majorVersionByte, err := util.Read(rs, 1)
|
||
3 years ago
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
3 years ago
|
revisionNumberByte, err := util.Read(rs, 1)
|
||
3 years ago
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
3 years ago
|
majorVersion, err := util.BytesToInt(majorVersionByte)
|
||
3 years ago
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
3 years ago
|
revisionNumber, err := util.BytesToInt(revisionNumberByte)
|
||
3 years ago
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
header.Version = fmt.Sprintf("%d%d", -majorVersion, revisionNumber)
|
||
|
|
||
|
// flags
|
||
3 years ago
|
flags, err := util.Read(rs, 1)
|
||
3 years ago
|
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
|
||
3 years ago
|
sizeBytes, err := util.Read(rs, 4)
|
||
3 years ago
|
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)
|
||
|
|
||
3 years ago
|
return &header, nil
|
||
|
}
|