1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package id3
import (
"encoding/binary"
"errors"
"fmt"
"strconv"
"strings"
"unicode/utf16"
)
type ErrFormat struct {
Format string
Err error
}
func (e ErrFormat) Error() string {
return fmt.Sprintf("gotaglib: error parsing format %q: %v", e.Format, e.Err)
}
func parseBase128Int(bytes []byte) uint64 {
var result uint64
for _, b := range bytes {
result = result << 7
result |= uint64(b)
}
return result
}
func parseLeadingInt(s string) (int, error) {
var intEnd int
for intEnd < len(s) && '0' <= s[intEnd] && s[intEnd] <= '9' {
intEnd++
}
return strconv.Atoi(s[0:intEnd])
}
func getTextIdentificationFrame(content []byte) ([]string, error) {
normalized, err := parseText(content)
if err != nil {
return nil, err
}
return strings.Split(normalized, string([]byte{0})), nil
}
// Parses a string from frame data. The first byte represents the encoding:
// 0x01 ISO-8859-1
// 0x02 UTF-16 w/ BOM
// 0x03 UTF-16BE w/o BOM
// 0x04 UTF-8
//
// Refer to section 4 of http://id3.org/id3v2.4.0-structure
func parseText(strBytes []byte) (string, error) {
if len(strBytes) == 0 {
return "", errors.New("empty id3 frame")
}
if len(strBytes) < 2 {
// Not an error according to the spec (because at least 1 byte big)
return "", nil
}
encoding, strBytes := strBytes[0], strBytes[1:]
switch encoding {
case 0: // ISO-8859-1 text.
return parseIso8859(strBytes), nil
case 1: // UTF-16 with BOM.
return parseUtf16WithBOM(strBytes)
case 2: // UTF-16BE without BOM.
return parseUtf16(strBytes, binary.BigEndian)
case 3: // UTF-8 text.
return parseUtf8(strBytes)
default:
return "", id3v24Err("invalid encoding byte %x", encoding)
}
}
func parseIso8859(strBytes []byte) string {
runes := make([]rune, len(strBytes))
for i, b := range strBytes {
runes[i] = rune(b)
}
return string(runes)
}
func parseUtf16WithBOM(strBytes []byte) (string, error) {
if strBytes[0] == 0xFE && strBytes[1] == 0xFF {
return parseUtf16(strBytes[2:], binary.BigEndian)
}
if strBytes[0] == 0xFF && strBytes[1] == 0xFE {
return parseUtf16(strBytes[2:], binary.LittleEndian)
}
return "", id3v24Err("invalid byte order marker %x %x", strBytes[0], strBytes[1])
}
func parseUtf16(strBytes []byte, bo binary.ByteOrder) (string, error) {
shorts := make([]uint16, 0, len(strBytes)/2)
for i := 0; i < len(strBytes); i += 2 {
short := bo.Uint16(strBytes[i : i+2])
shorts = append(shorts, short)
}
return string(utf16.Decode(shorts)), nil
}
func parseUtf8(strBytes []byte) (string, error) {
return string(strBytes), nil
}
|