Browse Source

❖ Now can convert v2.Header into bytes ! ❖

main
Unbewohnte 3 years ago
parent
commit
6624f21ece
  1. 8
      util/conversion.go
  2. 18
      util/conversion_test.go
  3. 160
      v2/header.go
  4. 53
      v2/header_test.go

8
util/conversion.go

@ -1,6 +1,7 @@
package util package util
import ( import (
"encoding/binary"
"strings" "strings"
euni "golang.org/x/text/encoding/unicode" euni "golang.org/x/text/encoding/unicode"
@ -19,6 +20,13 @@ func BytesToInt(gBytes []byte) uint32 {
return integer return integer
} }
// Simply converts given uint32 into synch unsafe bytes
func IntToBytes(gInt uint32) []byte {
buff := make([]byte, 4)
binary.BigEndian.PutUint32(buff, gInt)
return buff
}
// 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 BytesToIntSynchsafe(gBytes []byte) uint32 { func BytesToIntSynchsafe(gBytes []byte) uint32 {

18
util/conversion_test.go

@ -1,6 +1,8 @@
package util package util
import ( import (
"fmt"
"strconv"
"testing" "testing"
) )
@ -48,3 +50,19 @@ func TestIntToBytesSynchsafe(t *testing.T) {
} }
} }
} }
func TestIntToBytes(t *testing.T) {
var testInt uint32 = 124567
testIntBits := fmt.Sprintf("%032b", testInt)
gotBytes := IntToBytes(testInt)
i := 0
for _, gotByte := range gotBytes {
correctByte, _ := strconv.ParseUint(testIntBits[i:i+8], 2, 8)
if gotByte != byte(correctByte) {
t.Errorf("IntToBytes failed: expected byte to be %d; got %d", correctByte, gotByte)
}
i += 8
}
}

160
v2/header.go

@ -10,7 +10,7 @@ import (
// Main header`s flags // Main header`s flags
type HeaderFlags struct { type HeaderFlags struct {
Unsynchronisated bool Unsynchronised bool
Compressed bool Compressed bool
HasExtendedHeader bool HasExtendedHeader bool
Experimental bool Experimental bool
@ -19,7 +19,7 @@ type HeaderFlags struct {
// ID3v2.x`s main header structure // ID3v2.x`s main header structure
type Header struct { type Header struct {
Identifier string // Identifier string
Flags HeaderFlags Flags HeaderFlags
Version string Version string
Size uint32 Size uint32
@ -197,7 +197,6 @@ func readHeader(rs io.ReadSeeker) (Header, error) {
if !bytes.Equal([]byte(HEADERIDENTIFIER), identifier) { if !bytes.Equal([]byte(HEADERIDENTIFIER), identifier) {
return Header{}, ErrDoesNotUseID3v2 return Header{}, ErrDoesNotUseID3v2
} }
header.Identifier = string(identifier)
// version // version
majorVersion := int(hBytes[3]) majorVersion := int(hBytes[3])
@ -221,9 +220,9 @@ func readHeader(rs io.ReadSeeker) (Header, error) {
switch header.Version { switch header.Version {
case V2_2: case V2_2:
if util.GetBit(flags, 1) { if util.GetBit(flags, 1) {
header.Flags.Unsynchronisated = true header.Flags.Unsynchronised = true
} else { } else {
header.Flags.Unsynchronisated = false header.Flags.Unsynchronised = false
} }
if util.GetBit(flags, 2) { if util.GetBit(flags, 2) {
header.Flags.Compressed = true header.Flags.Compressed = true
@ -232,9 +231,9 @@ func readHeader(rs io.ReadSeeker) (Header, error) {
} }
case V2_3: case V2_3:
if util.GetBit(flags, 1) { if util.GetBit(flags, 1) {
header.Flags.Unsynchronisated = true header.Flags.Unsynchronised = true
} else { } else {
header.Flags.Unsynchronisated = false header.Flags.Unsynchronised = false
} }
if util.GetBit(flags, 2) { if util.GetBit(flags, 2) {
header.Flags.HasExtendedHeader = true header.Flags.HasExtendedHeader = true
@ -251,9 +250,9 @@ func readHeader(rs io.ReadSeeker) (Header, error) {
case V2_4: case V2_4:
if util.GetBit(flags, 1) { if util.GetBit(flags, 1) {
header.Flags.Unsynchronisated = true header.Flags.Unsynchronised = true
} else { } else {
header.Flags.Unsynchronisated = false header.Flags.Unsynchronised = false
} }
if util.GetBit(flags, 2) { if util.GetBit(flags, 2) {
header.Flags.HasExtendedHeader = true header.Flags.HasExtendedHeader = true
@ -288,3 +287,146 @@ func readHeader(rs io.ReadSeeker) (Header, error) {
return header, nil return header, nil
} }
// Converts given HeaderFlags struct into ready-to-write byte
// containing flags
func headerFlagsToByte(hf HeaderFlags, version string) byte {
var flagsByte byte = 0
switch version {
case V2_2:
if hf.Unsynchronised {
flagsByte = util.SetBit(flagsByte, 8)
}
if hf.Compressed {
flagsByte = util.SetBit(flagsByte, 7)
}
case V2_3:
if hf.Unsynchronised {
flagsByte = util.SetBit(flagsByte, 8)
}
if hf.HasExtendedHeader {
flagsByte = util.SetBit(flagsByte, 7)
}
if hf.Experimental {
flagsByte = util.SetBit(flagsByte, 6)
}
case V2_4:
if hf.Unsynchronised {
flagsByte = util.SetBit(flagsByte, 8)
}
if hf.HasExtendedHeader {
flagsByte = util.SetBit(flagsByte, 7)
}
if hf.Experimental {
flagsByte = util.SetBit(flagsByte, 6)
}
if hf.FooterPresent {
flagsByte = util.SetBit(flagsByte, 5)
}
}
return flagsByte
}
// Converts given header into ready-to-write bytes
func (h *Header) toBytes() []byte {
buff := new(bytes.Buffer)
// id
buff.Write([]byte(HEADERIDENTIFIER))
// version
version := []byte{0, 0}
switch h.Version {
case V2_2:
version = []byte{2, 0}
case V2_3:
version = []byte{3, 0}
case V2_4:
version = []byte{4, 0}
}
buff.Write(version)
// flags
flagByte := headerFlagsToByte(h.Flags, h.Version)
buff.WriteByte(flagByte)
// size
tagSize := util.IntToBytesSynchsafe(h.Size)
buff.Write(tagSize)
// extended header
if !h.Flags.HasExtendedHeader {
return buff.Bytes()
}
// double check for possible errors
if h.Version == V2_2 {
return buff.Bytes()
}
// size
extSize := util.IntToBytes(h.ExtendedHeader.Size)
buff.Write(extSize)
// flags and other version specific fields
switch h.Version {
case V2_3:
// flags
flagBytes := []byte{0, 0}
if h.ExtendedHeader.Flags.CRCpresent {
flagBytes[0] = util.SetBit(flagBytes[0], 8)
}
buff.Write(flagBytes)
// crc data
if h.ExtendedHeader.Flags.CRCpresent {
buff.Write(h.ExtendedHeader.CRCdata)
}
// padding size
paddingSize := util.IntToBytes(h.ExtendedHeader.PaddingSize)
buff.Write(paddingSize)
case V2_4:
numberOfFlagBytes := byte(1)
buff.WriteByte(numberOfFlagBytes)
extFlags := byte(0)
if h.ExtendedHeader.Flags.UpdateTag {
extFlags = util.SetBit(extFlags, 7)
}
if h.ExtendedHeader.Flags.CRCpresent {
extFlags = util.SetBit(extFlags, 6)
}
if h.ExtendedHeader.Flags.HasRestrictions {
extFlags = util.SetBit(extFlags, 5)
}
buff.WriteByte(extFlags)
// writing data, provided by flags
if h.ExtendedHeader.Flags.UpdateTag {
// data len
buff.WriteByte(0)
}
if h.ExtendedHeader.Flags.CRCpresent {
// data len
buff.WriteByte(5)
// data
buff.Write(h.ExtendedHeader.CRCdata)
}
if h.ExtendedHeader.Flags.HasRestrictions {
// data len
buff.WriteByte(1)
// data
buff.WriteByte(h.ExtendedHeader.Flags.Restrictions)
}
}
return buff.Bytes()
}

53
v2/header_test.go

@ -4,6 +4,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/Unbewohnte/id3ed/util"
) )
var TESTDATAPATH string = filepath.Join("..", "testData") var TESTDATAPATH string = filepath.Join("..", "testData")
@ -19,19 +21,58 @@ func TestReadHeader(t *testing.T) {
t.Errorf("GetHeader failed: %s", err) t.Errorf("GetHeader failed: %s", err)
} }
if header.Identifier != "ID3" {
t.Errorf("GetHeader failed: expected identifier %s; got %s", "ID3", header.Identifier)
}
if header.Flags.HasExtendedHeader != false { if header.Flags.HasExtendedHeader != false {
t.Errorf("GetHeader failed: expected flag %v; got %v", false, header.Flags.HasExtendedHeader) t.Errorf("GetHeader failed: expected flag %v; got %v", false, header.Flags.HasExtendedHeader)
} }
if header.Flags.Unsynchronisated != false { if header.Flags.Unsynchronised != false {
t.Errorf("GetHeader failed: expected flag %v; got %v", false, header.Flags.Unsynchronisated) t.Errorf("GetHeader failed: expected flag %v; got %v", false, header.Flags.Unsynchronised)
} }
if header.Size != 1138 { if header.Size != 1138 {
t.Errorf("GetHeader failed: expected size %v; got %v", 1138, header.Size) t.Errorf("GetHeader failed: expected size %v; got %v", 1138, header.Size)
} }
} }
func TestHeaderFlagsToByte(t *testing.T) {
hf := HeaderFlags{
Experimental: true,
FooterPresent: true,
}
var correctFlagsByte byte = 0
correctFlagsByte = util.SetBit(correctFlagsByte, 5)
correctFlagsByte = util.SetBit(correctFlagsByte, 6)
gotByte := headerFlagsToByte(hf, V2_4)
if gotByte != correctFlagsByte {
t.Errorf("headerFlagsToByte failed: expected to get %d; got %d", correctFlagsByte, gotByte)
}
}
func TestHeaderToBytes(t *testing.T) {
testHeader := Header{
Version: V2_4,
Flags: HeaderFlags{}, // all false
Size: 12345,
ExtendedHeader: ExtendedHeader{},
}
hBytes := testHeader.toBytes()
// t.Errorf("%v", hBytes)
// 73 68 51 4 0 0 0 0 96 57
// 73 68 51 - identifier
// 4 0 - version
// 0 - flags
// 0 0 96 57 - size
if string(hBytes[0:3]) != HEADERIDENTIFIER {
t.Errorf("expected to get %s, got %s", HEADERIDENTIFIER, string(hBytes[0:3]))
}
if util.BytesToIntSynchsafe(hBytes[6:10]) != testHeader.Size {
t.Errorf("toBytes failed: expected size to be %d; got %d",
testHeader.Size, util.BytesToIntSynchsafe(hBytes[7:10]))
}
}

Loading…
Cancel
Save