From 2b197fa0c1bd115834c2bd4f29c848400a0a806f Mon Sep 17 00:00:00 2001 From: Unbewohnte Date: Fri, 2 Jul 2021 12:12:23 +0300 Subject: [PATCH] =?UTF-8?q?=E2=9D=96=20Improved=20utils,=20continued=20to?= =?UTF-8?q?=20work=20on=20v2=20frames=20=E2=9D=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- testData/testwritev1.mp3 | Bin 2207 -> 2975 bytes util/etc.go | 22 +++++++++++++++++++++ util/read.go | 13 ++++++++++++- v1/id3v10.go | 10 +++++----- v1/id3v11.go | 10 +++++----- v2/constants.go | 2 ++ v2/frame.go | 41 ++++++++++++++++++++++++--------------- v2/frame_test.go | 35 +++++++++++++++++++++------------ v2/header.go | 15 ++------------ 9 files changed, 96 insertions(+), 52 deletions(-) diff --git a/testData/testwritev1.mp3 b/testData/testwritev1.mp3 index a5c531b6b562e7fdc42e50d108931f43cd49a13e..3402b049ba8b1784ec3b9d5839511b58fdf97b0c 100644 GIT binary patch delta 11 ScmbO)IA46je2&HQ8JPhZ`2++2 delta 7 OcmbO)K3{Odd=3B$p8~!B diff --git a/util/etc.go b/util/etc.go index d84beca..8739463 100644 --- a/util/etc.go +++ b/util/etc.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "fmt" + "strconv" ) // Returns found key (int) in provided map by value (string); @@ -27,3 +28,24 @@ func BytesToInt(gBytes []byte) (int64, error) { buff = nil return integer, nil } + +// 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 + for _, b := range gBytes { + // ignore the first bit + filteredPart := fmt.Sprintf("%08b", b)[1:] // byte is 8 bits + filteredBits += filteredPart + } + + // convert filtered binary into usable int64 + integer, err := strconv.ParseInt(filteredBits, 2, 64) + if err != nil { + return -1, err + } + + return integer, nil +} diff --git a/util/read.go b/util/read.go index c7e2eba..c0cec46 100644 --- a/util/read.go +++ b/util/read.go @@ -18,7 +18,7 @@ func Read(rs io.Reader, n uint64) ([]byte, error) { // Shortcut function to read n bytes and convert them into string. // If encountered zero-byte - converts to string only previously read bytes -func ReadToString(rs io.Reader, n int) (string, error) { +func ReadToStringIgnoreNullB(rs io.Reader, n uint64) (string, error) { read := make([]byte, n) _, err := rs.Read(read) if err != nil { @@ -35,3 +35,14 @@ func ReadToString(rs io.Reader, n int) (string, error) { return readString, nil } + +// Reads from rs and conversts read []byte into string +func ReadToString(rs io.Reader, n uint64) (string, error) { + read := make([]byte, n) + _, err := rs.Read(read) + if err != nil { + return "", fmt.Errorf("could not read from reader: %s", err) + } + + return string(read), nil +} diff --git a/v1/id3v10.go b/v1/id3v10.go index a50802b..84c3ee5 100644 --- a/v1/id3v10.go +++ b/v1/id3v10.go @@ -40,22 +40,22 @@ func Getv1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) { return nil, fmt.Errorf("does not use ID3v1: expected %s; got %s", ID3v1IDENTIFIER, tag) } - songname, err := util.ReadToString(rs, 30) + songname, err := util.ReadToStringIgnoreNullB(rs, 30) if err != nil { return nil, err } - artist, err := util.ReadToString(rs, 30) + artist, err := util.ReadToStringIgnoreNullB(rs, 30) if err != nil { return nil, err } - album, err := util.ReadToString(rs, 30) + album, err := util.ReadToStringIgnoreNullB(rs, 30) if err != nil { return nil, err } - yearStr, err := util.ReadToString(rs, 4) + yearStr, err := util.ReadToStringIgnoreNullB(rs, 4) if err != nil { return nil, err } @@ -64,7 +64,7 @@ func Getv1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) { return nil, fmt.Errorf("could not convert yearbytes into int: %s", err) } - comment, err := util.ReadToString(rs, 30) + comment, err := util.ReadToStringIgnoreNullB(rs, 30) if err != nil { return nil, err } diff --git a/v1/id3v11.go b/v1/id3v11.go index a05b23f..9204eab 100644 --- a/v1/id3v11.go +++ b/v1/id3v11.go @@ -39,22 +39,22 @@ func Getv11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { return nil, fmt.Errorf("does not use ID3v1: expected %s; got %s", ID3v1IDENTIFIER, tag) } - songname, err := util.ReadToString(rs, 30) + songname, err := util.ReadToStringIgnoreNullB(rs, 30) if err != nil { return nil, err } - artist, err := util.ReadToString(rs, 30) + artist, err := util.ReadToStringIgnoreNullB(rs, 30) if err != nil { return nil, err } - album, err := util.ReadToString(rs, 30) + album, err := util.ReadToStringIgnoreNullB(rs, 30) if err != nil { return nil, err } - yearStr, err := util.ReadToString(rs, 4) + yearStr, err := util.ReadToStringIgnoreNullB(rs, 4) if err != nil { return nil, err } @@ -63,7 +63,7 @@ func Getv11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { return nil, fmt.Errorf("could not convert yearbytes into int: %s", err) } - comment, err := util.ReadToString(rs, 28) + comment, err := util.ReadToStringIgnoreNullB(rs, 28) if err != nil { return nil, err } diff --git a/v2/constants.go b/v2/constants.go index ec81cf5..9048b14 100644 --- a/v2/constants.go +++ b/v2/constants.go @@ -4,3 +4,5 @@ package v2 const HEADERIDENTIFIER string = "ID3" const HEADERSIZE int = 10 // bytes const HEADERMAXSIZE int = 268435456 // bytes (256 MB) + +// Version specific constants diff --git a/v2/frame.go b/v2/frame.go index ed34f7d..687b539 100644 --- a/v2/frame.go +++ b/v2/frame.go @@ -11,49 +11,58 @@ import ( //////////////////////////////////////////////////////////////////////////// type FrameHeader struct { - Identifier string - FrameSize int64 + ID string + FrameSize int64 + Flags int } type Frame struct { - Header *FrameHeader + Header FrameHeader Contents string } -// NOT TESTED ! -func Readv2Frame(rs io.Reader) (*Frame, error) { - var frameHeader *FrameHeader +// NOT TESTED ! Reads v2.3 | v2.4 frame +func ReadFrame(rs io.Reader) (*Frame, error) { + var frameHeader FrameHeader var frame Frame - identifier, err := util.ReadToString(rs, 3) + identifier, err := util.ReadToString(rs, 4) if err != nil { return nil, err } - frameHeader.Identifier = identifier + frameHeader.ID = identifier - framesizeBytes, err := util.Read(rs, 3) + framesizeBytes, err := util.Read(rs, 4) if err != nil { return nil, err } - framesize, err := util.BytesToInt(framesizeBytes) + framesize, err := util.BytesToIntIgnoreFirstBit(framesizeBytes) if err != nil { return nil, err } frameHeader.FrameSize = framesize - frameContents, err := util.ReadToString(rs, int(framesize)) + frameFlagsBytes, err := util.Read(rs, 2) + if err != nil { + return nil, err + } + + // STILL NOT IMPLEMENTED FLAG HANDLING ! + frameFlags, err := util.BytesToInt(frameFlagsBytes) + if err != nil { + return nil, err + } + frameHeader.Flags = int(frameFlags) + + frameContents, err := util.Read(rs, uint64(framesize)) if err != nil { return nil, err } frame.Header = frameHeader - frame.Contents = frameContents + frame.Contents = string(frameContents) return &frame, nil } - -// func ReadFrame(rs io.Reader, version string) error { -// return nil -// } diff --git a/v2/frame_test.go b/v2/frame_test.go index c86280d..d2c28e6 100644 --- a/v2/frame_test.go +++ b/v2/frame_test.go @@ -1,16 +1,27 @@ package v2 -// func TestReadFrame(t *testing.T) { -// f, err := os.Open(filepath.Join(TESTDATAPATH, "testreadv2.mp3")) -// if err != nil { -// t.Errorf("%s", err) -// } +import ( + "io" + "os" + "path/filepath" + "testing" +) -// // read right after header`s bytes -// f.Seek(int64(HEADERSIZE), io.SeekStart) +func TestReadFrame(t *testing.T) { + f, err := os.Open(filepath.Join(TESTDATAPATH, "testreadv2.mp3")) + if err != nil { + t.Errorf("%s", err) + } -// _, err = Readv2Frame(f) -// if err != nil { -// t.Errorf("ReadFrame failed: %s", err) -// } -// } + // read right after header`s bytes + f.Seek(int64(HEADERSIZE), io.SeekStart) + + firstFrame, err := ReadFrame(f) + if err != nil { + t.Errorf("ReadFrame failed: %s", err) + } + + if firstFrame.Header.ID != "TRCK" { + t.Errorf("ReadFrame failed: expected ID %s; got %s", "TRCK", firstFrame.Header.ID) + } +} diff --git a/v2/header.go b/v2/header.go index 4cfdbe3..c46f479 100644 --- a/v2/header.go +++ b/v2/header.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "io" - "strconv" "github.com/Unbewohnte/id3ed/util" ) @@ -77,22 +76,12 @@ func GetHeader(rs io.ReadSeeker) (*Header, error) { 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) + size, err := util.BytesToIntIgnoreFirstBit(sizeBytes) if err != nil { return nil, err } - header.Size = int64(size) + header.Size = size return &header, nil }