⬥ 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.

105 lines
2.4 KiB

package util
import (
"fmt"
"strconv"
"strings"
euni "golang.org/x/text/encoding/unicode"
)
// got the logic from: https://github.com/bogem/id3v2 , thank you very much.
const first7BitsMask = uint32(254) << 24 // shifting 11111110 to the end of uint32
// Decodes given byte into integer
func ByteToInt(gByte byte) (int, error) {
integer, err := strconv.Atoi(fmt.Sprintf("%d", gByte))
if err != nil {
return 0, err
}
return integer, nil
}
// Decodes given integer bytes into integer, ignores the first bit
// of every given byte in binary form
func BytesToIntIgnoreFirstBit(gBytes []byte) uint32 {
var integer uint32 = 0
for _, b := range gBytes {
integer = integer << 7
integer = integer | uint32(b)
}
return integer
}
// The exact opposite of what `BytesToIntIgnoreFirstBit` does
func IntToBytesFirstBitZeroed(gInt uint32) []byte {
bytes := make([]byte, 32)
// looping 4 times (32 bits / 8 bits (4 bytes in int32))
for i := 0; i < 32; i += 8 {
gIntCopy := gInt //ie: 11010100 11001011 00100000 10111111
first7 := gIntCopy & first7BitsMask
shifted := first7 >> 25 // 00000000 00000000 00000000 01101010
bytes = append(bytes, byte(shifted))
}
return bytes
}
// Converts given bytes into string, ignoring the first 31 non-printable ASCII characters.
// (LOSSY, if given bytes contain some nasty ones)
func ToStringLossy(gBytes []byte) string {
var runes []rune
for _, b := range gBytes {
if b <= 31 {
continue
}
runes = append(runes, rune(b))
}
return strings.ToValidUTF8(string(runes), "")
}
// Decodes the given frame`s contents
func DecodeText(fContents []byte) string {
textEncoding := fContents[0] // the first byte is the encoding
switch textEncoding {
case 0:
// ISO-8859-1
return ToStringLossy(fContents[1:])
case 1:
// UTF-16 with BOM
encoding := euni.UTF16(euni.BigEndian, euni.ExpectBOM)
decoder := encoding.NewDecoder()
decodedBytes := make([]byte, len(fContents)*2)
_, _, err := decoder.Transform(decodedBytes, fContents[1:], true)
if err != nil {
return ""
}
return string(decodedBytes)
case 2:
// UTF-16
encoding := euni.UTF16(euni.BigEndian, euni.IgnoreBOM)
decoder := encoding.NewDecoder()
decodedBytes := make([]byte, len(fContents)*2)
_, _, err := decoder.Transform(decodedBytes, fContents[1:], true)
if err != nil {
return ""
}
return string(decodedBytes)
case 3:
// UTF-8
return ToStringLossy(fContents[1:])
}
return ""
}