diff --git a/util/conversion.go b/util/conversion.go index 74a617b..acd67d0 100644 --- a/util/conversion.go +++ b/util/conversion.go @@ -35,7 +35,7 @@ func BytesToIntSynchsafe(gBytes []byte) uint32 { // Finally understood with the help of: https://github.com/bogem/id3v2/blob/master/size.go , // thank you very much ! func IntToBytesSynchsafe(gInt uint32) []byte { - synchsafeIBytes := make([]byte, 4) + var synchsafeIBytes []byte // skip 4 0`ed bits gInt = gInt << 4 @@ -71,15 +71,22 @@ func ToStringLossy(gBytes []byte) string { return strings.ToValidUTF8(string(runes), "") } +const ( + EncodingISO8859 byte = iota + EncodingUTF16BOM + EncodingUTF16 + EncodingUTF8 +) + // Decodes the given frame`s contents func DecodeText(fContents []byte) string { textEncoding := fContents[0] // the first byte is the encoding switch textEncoding { - case 0: + case EncodingISO8859: // ISO-8859-1 return ToStringLossy(fContents[1:]) - case 1: + case EncodingUTF16BOM: // UTF-16 with BOM encoding := euni.UTF16(euni.BigEndian, euni.ExpectBOM) decoder := encoding.NewDecoder() @@ -92,7 +99,7 @@ func DecodeText(fContents []byte) string { return string(decodedBytes) - case 2: + case EncodingUTF16: // UTF-16 encoding := euni.UTF16(euni.BigEndian, euni.IgnoreBOM) decoder := encoding.NewDecoder() @@ -105,7 +112,7 @@ func DecodeText(fContents []byte) string { return string(decodedBytes) - case 3: + case EncodingUTF8: // UTF-8 return ToStringLossy(fContents[1:]) } diff --git a/util/conversion_test.go b/util/conversion_test.go index 01326b0..aa2e9a6 100644 --- a/util/conversion_test.go +++ b/util/conversion_test.go @@ -37,6 +37,9 @@ func TestIntToBytesSynchsafe(t *testing.T) { for _, testInt := range testInts { synchSafeBytes := IntToBytesSynchsafe(testInt) + if len(synchSafeBytes) != 4 { + t.Errorf("IntToBytesSynchsafe failed: expected len to be %d; got %d", 4, len(synchSafeBytes)) + } synchsafeInt := BytesToIntSynchsafe(synchSafeBytes) diff --git a/v2/frame.go b/v2/frame.go index 775981e..6a3df4c 100644 --- a/v2/frame.go +++ b/v2/frame.go @@ -268,62 +268,66 @@ func (f *Frame) Text() string { return util.DecodeText(f.Contents) } -func v23FlagsToBytes(v23f FrameFlags) []byte { - var flags = []byte{0, 0} +func frameFlagsToBytes(ff FrameFlags, version string) []byte { + var flagBytes = []byte{0, 0} - if v23f.TagAlterPreservation { - flags[0] = util.SetBit(flags[0], 8) - } - if v23f.FileAlterPreservation { - flags[0] = util.SetBit(flags[0], 7) - } - if v23f.ReadOnly { - flags[0] = util.SetBit(flags[0], 6) - } + switch version { + case V2_2: + return nil - if v23f.Compressed { - flags[1] = util.SetBit(flags[1], 8) - } - if v23f.Encrypted { - flags[1] = util.SetBit(flags[1], 7) - } - if v23f.InGroup { - flags[1] = util.SetBit(flags[1], 6) - } + case V2_3: + if ff.TagAlterPreservation { + flagBytes[0] = util.SetBit(flagBytes[0], 8) + } + if ff.FileAlterPreservation { + flagBytes[0] = util.SetBit(flagBytes[0], 7) + } + if ff.ReadOnly { + flagBytes[0] = util.SetBit(flagBytes[0], 6) + } - return flags -} + if ff.Compressed { + flagBytes[1] = util.SetBit(flagBytes[1], 8) + } + if ff.Encrypted { + flagBytes[1] = util.SetBit(flagBytes[1], 7) + } + if ff.InGroup { + flagBytes[1] = util.SetBit(flagBytes[1], 6) + } + return flagBytes -func v24FlagsToBytes(v24f FrameFlags) []byte { - var flagBytes = []byte{0, 0} + case V2_4: + if ff.TagAlterPreservation { + flagBytes[0] = util.SetBit(flagBytes[0], 7) + } + if ff.FileAlterPreservation { + flagBytes[0] = util.SetBit(flagBytes[0], 6) + } + if ff.ReadOnly { + flagBytes[0] = util.SetBit(flagBytes[0], 5) + } - if v24f.TagAlterPreservation { - flagBytes[0] = util.SetBit(flagBytes[0], 7) - } - if v24f.FileAlterPreservation { - flagBytes[0] = util.SetBit(flagBytes[0], 6) - } - if v24f.ReadOnly { - flagBytes[0] = util.SetBit(flagBytes[0], 5) - } + if ff.InGroup { + flagBytes[1] = util.SetBit(flagBytes[1], 7) + } + if ff.Compressed { + flagBytes[1] = util.SetBit(flagBytes[1], 4) + } + if ff.Encrypted { + flagBytes[1] = util.SetBit(flagBytes[1], 3) + } + if ff.Unsyrchronised { + flagBytes[1] = util.SetBit(flagBytes[1], 2) + } + if ff.HasDataLengthIndicator { + flagBytes[1] = util.SetBit(flagBytes[1], 1) + } + return flagBytes - if v24f.InGroup { - flagBytes[1] = util.SetBit(flagBytes[1], 7) - } - if v24f.Compressed { - flagBytes[1] = util.SetBit(flagBytes[1], 4) + default: + return nil } - if v24f.Encrypted { - flagBytes[1] = util.SetBit(flagBytes[1], 3) - } - if v24f.Unsyrchronised { - flagBytes[1] = util.SetBit(flagBytes[1], 2) - } - if v24f.HasDataLengthIndicator { - flagBytes[1] = util.SetBit(flagBytes[1], 1) - } - - return flagBytes } // Converts frame to ready-to-write bytes @@ -337,17 +341,13 @@ func (f *Frame) toBytes(version string) []byte { buff.Write(util.IntToBytesSynchsafe(f.Header.Size)) // flags - var flagBytes []byte - switch version { - case V2_2: - break - case V2_3: - flagBytes = v23FlagsToBytes(f.Header.Flags) - buff.Write(flagBytes) - case V2_4: - flagBytes = v24FlagsToBytes(f.Header.Flags) + flagBytes := frameFlagsToBytes(f.Header.Flags, version) + if flagBytes != nil { buff.Write(flagBytes) } + // contents + buff.Write(f.Contents) + return buff.Bytes() } diff --git a/v2/frame_test.go b/v2/frame_test.go index 47b4d70..cd9e8b1 100644 --- a/v2/frame_test.go +++ b/v2/frame_test.go @@ -49,3 +49,54 @@ func TestReadNextFrame(t *testing.T) { "2006", secondFrame.Contents) } } + +func TestFrameFlagsToBytes(t *testing.T) { + testFlags := FrameFlags{ + TagAlterPreservation: true, + ReadOnly: true, + } + + versions := []string{V2_2, V2_3, V2_4} + + for _, version := range versions { + flagBytes := frameFlagsToBytes(testFlags, version) + if version == V2_2 && flagBytes != nil { + t.Errorf("frameFlagsToBytes failed: V2_2, expected flagbytes to be nil; got %v", flagBytes) + } + if version != V2_2 && len(flagBytes) != 2 { + t.Errorf("frameFlagsToBytes failed: expected flagbytes to be len of 2; got %v", len(flagBytes)) + } + } +} + +func TestFrameToBytes(t *testing.T) { + testframe := Frame{ + Header: FrameHeader{ + ID: "TEST", + Flags: FrameFlags{}, // all false + Size: 4, + }, + Contents: []byte{util.EncodingUTF8, 60, 60, 60}, // 60 == < + } + + frameBytes := testframe.toBytes(V2_4) + + // t.Errorf("%+v", frameBytes) + // 84 69 83 84 0 0 0 4 0 0 3 60 60 60 + + // 84 69 83 84 - id (4) + // 0 0 - flags (2) + // 0 4 0 0 - size (4) + // header - 4 + 4 + 2 = 10 bytes (success) + // 3 60 60 60 - contents + + if len(frameBytes)-int(testframe.Header.Size) != HEADERSIZE { + t.Errorf("FrameToBytes failed: expected header size to be %d; got %d", + HEADERSIZE, len(frameBytes)-int(testframe.Header.Size)) + } + + if util.DecodeText(frameBytes[10:]) != "<<<" { + t.Errorf("FrameToBytes failed: expected contents to be %v; got %v", + testframe.Contents, frameBytes[10:]) + } +}