From c91bc93ba3fb1b454eb9be915a8c5db2e9973b7a Mon Sep 17 00:00:00 2001 From: Unbewohnte Date: Thu, 1 Jul 2021 13:21:13 +0300 Subject: [PATCH] =?UTF-8?q?=E2=AC=9C=20Error-handling=20and=20an=20attempt?= =?UTF-8?q?=20to=20wrap=20read/write=20functions=20=E2=AC=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- id3ed.go | 59 +++++++++++++++++++++++++++++++++++++ id3ed_test.go | 48 ++++++++++++++++++++++++++++++ testData/testWriteTags.mp3 | 0 testData/testwritev1.mp3 | Bin 4128 -> 1439 bytes util/etc.go | 3 +- util/write.go | 9 ++++-- v1/id3v10.go | 26 +++++++++------- v1/id3v11.go | 23 ++++++++++----- 8 files changed, 146 insertions(+), 22 deletions(-) create mode 100644 id3ed.go create mode 100644 id3ed_test.go create mode 100755 testData/testWriteTags.mp3 diff --git a/id3ed.go b/id3ed.go new file mode 100644 index 0000000..c3fadda --- /dev/null +++ b/id3ed.go @@ -0,0 +1,59 @@ +package id3ed + +import ( + "fmt" + "io" + "os" + + v1 "github.com/Unbewohnte/id3ed/v1" +) + +type Tagger interface { + WriteToFile(*os.File) error + Version() int +} + +// Reads certain ID3 tags from io.ReadSeeker according to given version. +// Wrapper function to v1|v2 package functions +func ReadTags(rs io.ReadSeeker, version int) (Tagger, error) { + switch version { + + case 10: + // ID3v1 + t, err := v1.Getv1Tags(rs) + if err != nil { + return nil, err + } + return t, nil + + case 11: + // ID3v1.1 + t, err := v1.Getv11Tags(rs) + if err != nil { + return nil, err + } + return t, nil + + case 23: + // ID3v2.3 + return nil, fmt.Errorf("v2.3 is not supported") + + case 24: + // ID3v2.4 + return nil, fmt.Errorf("v2.4 is not supported") + } + + return nil, fmt.Errorf("invalid version or not supported") +} + +// DOESN`T work for some reason !? err is coming from f.Seek(), but it`s completely fine +// when run directly from v1.WriteToFile() function. +// Writes tags to file. +func WriteTags(dstf *os.File, t Tagger) error { + err := t.WriteToFile(dstf) + if err != nil { + return err + } + + return nil +} diff --git a/id3ed_test.go b/id3ed_test.go new file mode 100644 index 0000000..33aab00 --- /dev/null +++ b/id3ed_test.go @@ -0,0 +1,48 @@ +package id3ed + +import ( + "os" + "path/filepath" + "testing" +) + +var TESTDATAPATH string = filepath.Join("testData") + +func TestReadTags(t *testing.T) { + f, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testreadv1.mp3"), os.O_RDONLY, os.ModePerm) + if err != nil { + t.Errorf("%s", err) + } + + _, err = ReadTags(f, 11) + if err != nil { + t.Errorf("ReadTags failed: %s", err) + } + + _, err = ReadTags(f, 10) + if err != nil { + t.Errorf("ReadTags failed: %s", err) + } +} + +// func TestWriteTags(t *testing.T) { +// f, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testreadv1.mp3"), os.O_RDONLY, os.ModePerm) +// if err != nil { +// t.Errorf("%s", err) +// } + +// tagger, err := ReadTags(f, 11) +// if err != nil { +// t.Errorf("%s", err) +// } + +// f2, err := os.OpenFile(filepath.Join(TESTDATAPATH, "testWriteTags.mp3"), os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) +// if err != nil { +// t.Errorf("%s", err) +// } + +// err = WriteTags(f2, tagger) +// if err != nil { +// t.Errorf("WriteTags failed: %s", err) +// } +// } diff --git a/testData/testWriteTags.mp3 b/testData/testWriteTags.mp3 new file mode 100755 index 0000000..e69de29 diff --git a/testData/testwritev1.mp3 b/testData/testwritev1.mp3 index 74b8811fb3bced8ea0152a3f8d4dc4ec85051bd9..5dfc8db24c6b32771cbeaf4b2e74c88eea024733 100644 GIT binary patch delta 11 ScmZ3WFrRyaJmba%4J-f|Q3MbG delta 24 YcmbQwy+C1uJmcnhjEpRc=fg2G0Anx*W&i*H diff --git a/util/etc.go b/util/etc.go index f7e8835..d84beca 100644 --- a/util/etc.go +++ b/util/etc.go @@ -3,6 +3,7 @@ package util import ( "bytes" "encoding/binary" + "fmt" ) // Returns found key (int) in provided map by value (string); @@ -21,7 +22,7 @@ func BytesToInt(gBytes []byte) (int64, error) { buff := bytes.NewBuffer(gBytes) integer, err := binary.ReadVarint(buff) if err != nil { - return 0, err + return 0, fmt.Errorf("could not decode integer: %s", err) } buff = nil return integer, nil diff --git a/util/write.go b/util/write.go index 75ba32d..fa8232d 100644 --- a/util/write.go +++ b/util/write.go @@ -15,21 +15,24 @@ func WriteToExtent(wr io.Writer, data []byte, lenNeeded int) error { buff := new(bytes.Buffer) for i := 0; i < lenNeeded; i++ { if i < len(data) { + // write given data err := buff.WriteByte(data[i]) if err != nil { - return err + return fmt.Errorf("could not write byte: %s", err) } } else { + // write null bytes err := buff.WriteByte(0) if err != nil { - return err + return fmt.Errorf("could not write byte: %s", err) } } } + // write constructed buffer`s bytes _, err := wr.Write(buff.Bytes()) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } return nil diff --git a/v1/id3v10.go b/v1/id3v10.go index 2101f07..a50802b 100644 --- a/v1/id3v10.go +++ b/v1/id3v10.go @@ -75,7 +75,7 @@ func Getv1Tags(rs io.ReadSeeker) (*ID3v1Tags, error) { } genreInt, err := util.BytesToInt(genreByte) if err != nil { - return nil, err + return nil, fmt.Errorf("cannot convert bytes to int: %s", err) } genre, exists := id3v1genres[int(genreInt)] if !exists { @@ -101,37 +101,37 @@ func (tags *ID3v1Tags) Write(dst io.WriteSeeker) error { // TAG _, err := dst.Write([]byte(ID3v1IDENTIFIER)) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } // Song name err = util.WriteToExtent(dst, []byte(tags.SongName), 30) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } // Artist err = util.WriteToExtent(dst, []byte(tags.Artist), 30) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } // Album err = util.WriteToExtent(dst, []byte(tags.Album), 30) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } // Year err = util.WriteToExtent(dst, []byte(fmt.Sprint(tags.Year)), 4) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } // Comment err = util.WriteToExtent(dst, []byte(tags.Comment), 30) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } // Genre @@ -145,7 +145,7 @@ func (tags *ID3v1Tags) Write(dst io.WriteSeeker) error { _, err = dst.Write(genrebyte) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } return nil @@ -175,20 +175,24 @@ func (tags *ID3v1Tags) WriteToFile(f *os.File) error { // does contain ID3v1 tag. Removing it fStats, err := f.Stat() if err != nil { - return err + return fmt.Errorf("cannot get file stats: %s", err) } err = f.Truncate(fStats.Size() - int64(ID3v1SIZE)) if err != nil { - return nil + return fmt.Errorf("could not truncate file %s", err) } // writing new tags err = tags.Write(f) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } return nil } + +func (tags *ID3v1Tags) Version() int { + return 10 +} diff --git a/v1/id3v11.go b/v1/id3v11.go index ccf8a91..a05b23f 100644 --- a/v1/id3v11.go +++ b/v1/id3v11.go @@ -81,7 +81,7 @@ func Getv11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { track, err := util.BytesToInt(trackByte) if err != nil { - return nil, err + return nil, fmt.Errorf("cannot convert bytes to int: %s", err) } genreByte, err := util.Read(rs, 1) @@ -90,7 +90,7 @@ func Getv11Tags(rs io.ReadSeeker) (*ID3v11Tags, error) { } genreInt, err := util.BytesToInt(genreByte) if err != nil { - return nil, err + return nil, fmt.Errorf("cannot convert bytes to int: %s", err) } genre, exists := id3v1genres[int(genreInt)] if !exists { @@ -185,18 +185,23 @@ func (tags *ID3v11Tags) WriteToFile(f *os.File) error { defer f.Close() // check for existing ID3v1.1 tag - f.Seek(-int64(ID3v1SIZE), io.SeekEnd) + _, err := f.Seek(-int64(ID3v1SIZE), io.SeekEnd) + if err != nil { + return fmt.Errorf("could not seek: %s", err) + } tag, err := util.Read(f, 3) if err != nil { + // return err return err + } if !bytes.Equal(tag, []byte(ID3v1IDENTIFIER)) { // no existing tag, just write given tags err = tags.Write(f) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } return nil } @@ -204,19 +209,23 @@ func (tags *ID3v11Tags) WriteToFile(f *os.File) error { // does contain ID3v1.1 tag. Removing it fStats, err := f.Stat() if err != nil { - return err + return fmt.Errorf("cannot get file stats: %s", err) } err = f.Truncate(fStats.Size() - int64(ID3v1SIZE)) if err != nil { - return nil + return fmt.Errorf("could not truncate file %s", err) } // writing new tags err = tags.Write(f) if err != nil { - return err + return fmt.Errorf("could not write to writer: %s", err) } return nil } + +func (tags *ID3v11Tags) Version() int { + return 11 +}