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
Right now it`s capable of reading and writing ID3v1 and ID3v1.1 tags.
ID3v2 support is still in making, but it can read header and frames
Right now it`s capable of reading and writing ID3v1 and ID3v1.1 tags,
reading ID3v2. ID3v2 writing support is still not implemented.
---

34
util/conversion.go

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

15
util/conversion_test.go

@ -1,6 +1,8 @@
package util
import "testing"
import (
"testing"
)
func TestToStringLossy(t *testing.T) {
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)
}
}
// 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 {
ID string
Size int64
Size uint32
Flags FrameFlags
}
@ -63,10 +63,7 @@ func getFrameHeader(fHeaderbytes []byte, version string) (FrameHeader, error) {
}
header.ID = string(fHeaderbytes[0:3])
framesizeBytes, err := util.BytesToIntIgnoreFirstBit(fHeaderbytes[3:6])
if err != nil {
return FrameHeader{}, err
}
framesizeBytes := util.BytesToIntIgnoreFirstBit(fHeaderbytes[3:6])
header.Size = framesizeBytes
case V2_3:
@ -85,10 +82,7 @@ func getFrameHeader(fHeaderbytes []byte, version string) (FrameHeader, error) {
// Size
framesizeBytes := fHeaderbytes[4:8]
framesize, err := util.BytesToIntIgnoreFirstBit(framesizeBytes)
if err != nil {
return FrameHeader{}, err
}
framesize := util.BytesToIntIgnoreFirstBit(framesizeBytes)
header.Size = framesize
@ -183,3 +177,17 @@ func readNextFrame(r io.Reader, h Header) (Frame, uint64, error) {
func (f *Frame) Text() string {
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
Flags HeaderFlags
Version string
Size int64 // size of the whole tag - 10 header bytes
Size uint32
}
// Reads and structuralises ID3v2 header from given bytes.
@ -121,10 +121,7 @@ func readHeader(rs io.ReadSeeker) (Header, error) {
// size
sizeBytes := hBytes[6:]
size, err := util.BytesToIntIgnoreFirstBit(sizeBytes)
if err != nil {
return Header{}, err
}
size := util.BytesToIntIgnoreFirstBit(sizeBytes)
header.Size = size

2
v2/read_test.go

@ -32,6 +32,6 @@ func TestReadV2Tag(t *testing.T) {
picture := tag.Picture()
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