Browse Source

■ Small improvements, started to work on ID3v2 writing support ■

main
Unbewohnte 3 years ago
parent
commit
a130fda90c
  1. 5
      README.md
  2. 34
      util/conversion.go
  3. 15
      util/conversion_test.go
  4. 26
      v2/frame.go
  5. 7
      v2/header.go
  6. 2
      v2/read_test.go
  7. 19
      v2/write.go
  8. 16
      v2/write_test.go

5
README.md

@ -7,9 +7,8 @@
# Project status # Project status
Right now it`s capable of reading and writing ID3v1 and ID3v1.1 tags. Right now it`s capable of reading and writing ID3v1 and ID3v1.1 tags,
reading ID3v2. ID3v2 writing support is still not implemented.
ID3v2 support is still in making, but it can read header and frames
--- ---

34
util/conversion.go

@ -8,6 +8,10 @@ import (
euni "golang.org/x/text/encoding/unicode" 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 // Decodes given byte into integer
func ByteToInt(gByte byte) (int, error) { func ByteToInt(gByte byte) (int, error) {
integer, err := strconv.Atoi(fmt.Sprintf("%d", gByte)) integer, err := strconv.Atoi(fmt.Sprintf("%d", gByte))
@ -19,23 +23,29 @@ func ByteToInt(gByte byte) (int, error) {
// Decodes given integer bytes into integer, ignores the first bit // Decodes given integer bytes into integer, ignores the first bit
// of every given byte in binary form // of every given byte in binary form
func BytesToIntIgnoreFirstBit(gBytes []byte) (int64, error) { func BytesToIntIgnoreFirstBit(gBytes []byte) uint32 {
// represent each byte in size as binary and get rid from the first bit, var integer uint32 = 0
// then concatenate filtered parts
var filteredBits string
for _, b := range gBytes { for _, b := range gBytes {
// ignore the first bit integer = integer << 7
filteredPart := fmt.Sprintf("%08b", b)[1:] // byte is 8 bits integer = integer | uint32(b)
filteredBits += filteredPart
} }
// convert filtered binary into usable int64 return integer
integer, err := strconv.ParseInt(filteredBits, 2, 64)
if err != nil {
return -1, err
} }
return integer, nil // 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. // Converts given bytes into string, ignoring the first 31 non-printable ASCII characters.

15
util/conversion_test.go

@ -1,6 +1,8 @@
package util package util
import "testing" import (
"testing"
)
func TestToStringLossy(t *testing.T) { func TestToStringLossy(t *testing.T) {
someVeryNastyBytes := []byte{0, 1, 2, 3, 4, 5, 6, 50, 7, 8, 9, 10, 11, 50, 50} someVeryNastyBytes := []byte{0, 1, 2, 3, 4, 5, 6, 50, 7, 8, 9, 10, 11, 50, 50}
@ -22,3 +24,14 @@ func TestDecodeText(t *testing.T) {
t.Errorf("DecodeText failed: expected text %s, got %s", "22222", decodedUtf8text) t.Errorf("DecodeText failed: expected text %s, got %s", "22222", decodedUtf8text)
} }
} }
// func TestIntToBytesFirstBitZeroed(t *testing.T) {
// var testint uint32 = 123456
// intbytes := IntToBytesFirstBitZeroed(testint)
// if BytesToIntIgnoreFirstBit(intbytes) != testint {
// t.Errorf("IntToBytesFirstBitZeroed failed: expected to get %v; got %v",
// testint, BytesToIntIgnoreFirstBit(intbytes))
// }
// }

26
v2/frame.go

@ -24,7 +24,7 @@ type FrameFlags struct {
type FrameHeader struct { type FrameHeader struct {
ID string ID string
Size int64 Size uint32
Flags FrameFlags Flags FrameFlags
} }
@ -63,10 +63,7 @@ func getFrameHeader(fHeaderbytes []byte, version string) (FrameHeader, error) {
} }
header.ID = string(fHeaderbytes[0:3]) header.ID = string(fHeaderbytes[0:3])
framesizeBytes, err := util.BytesToIntIgnoreFirstBit(fHeaderbytes[3:6]) framesizeBytes := util.BytesToIntIgnoreFirstBit(fHeaderbytes[3:6])
if err != nil {
return FrameHeader{}, err
}
header.Size = framesizeBytes header.Size = framesizeBytes
case V2_3: case V2_3:
@ -85,10 +82,7 @@ func getFrameHeader(fHeaderbytes []byte, version string) (FrameHeader, error) {
// Size // Size
framesizeBytes := fHeaderbytes[4:8] framesizeBytes := fHeaderbytes[4:8]
framesize, err := util.BytesToIntIgnoreFirstBit(framesizeBytes) framesize := util.BytesToIntIgnoreFirstBit(framesizeBytes)
if err != nil {
return FrameHeader{}, err
}
header.Size = framesize header.Size = framesize
@ -183,3 +177,17 @@ func readNextFrame(r io.Reader, h Header) (Frame, uint64, error) {
func (f *Frame) Text() string { func (f *Frame) Text() string {
return util.DecodeText(f.Contents) return util.DecodeText(f.Contents)
} }
// Returns bytes of the frame that can be
// written in a file.
// func (f *Frame) Bytes() ([]byte, error) {
// header := f.Header
// contents := f.Contents
// var headerbytes []byte
// identifierBytes := []byte(header.ID)
// // sizeBytes
// return nil, nil
// }

7
v2/header.go

@ -22,7 +22,7 @@ type Header struct {
Identifier string Identifier string
Flags HeaderFlags Flags HeaderFlags
Version string Version string
Size int64 // size of the whole tag - 10 header bytes Size uint32
} }
// Reads and structuralises ID3v2 header from given bytes. // Reads and structuralises ID3v2 header from given bytes.
@ -121,10 +121,7 @@ func readHeader(rs io.ReadSeeker) (Header, error) {
// size // size
sizeBytes := hBytes[6:] sizeBytes := hBytes[6:]
size, err := util.BytesToIntIgnoreFirstBit(sizeBytes) size := util.BytesToIntIgnoreFirstBit(sizeBytes)
if err != nil {
return Header{}, err
}
header.Size = size header.Size = size

2
v2/read_test.go

@ -32,6 +32,6 @@ func TestReadV2Tag(t *testing.T) {
picture := tag.Picture() picture := tag.Picture()
if picture != nil { if picture != nil {
t.Errorf("ReadV2Tag failed: expected it not to have a picture") t.Errorf("ReadV2Tag failed: expected file not to have a picture")
} }
} }

19
v2/write.go

@ -0,0 +1,19 @@
package v2
// func WriteFrame(frame *Frame) error {
// return nil
// }
// // Writes ID3v2Tag to ws
// func (tag *ID3v2Tag) write(ws io.WriteSeeker, version string) error {
// _, err := ws.Seek(0, io.SeekStart)
// if err != nil {
// return fmt.Errorf("could not seek: %s", err)
// }
// return nil
// }
// func (tag *ID3v2Tag) WriteToFile(f *os.File) error {
// return nil
// }

16
v2/write_test.go

@ -0,0 +1,16 @@
package v2
// var TESTTAG = &ID3v2Tag{
// Frames: []Frame{
// Frame{
// Header: FrameHeader{
// ID: "COMM",
// },
// Contents: []byte("comment_here"),
// },
// },
// }
// func TestWrite(t *testing.T) {
// t.Errorf("%v", TESTTAG.Header.Version)
// }
Loading…
Cancel
Save