diff --git a/toml.go b/toml.go index 2724af4..20180ab 100644 --- a/toml.go +++ b/toml.go @@ -333,10 +333,39 @@ func LoadBytes(b []byte) (tree *Tree, err error) { err = errors.New(r.(string)) } }() + + if len(b) >= 4 && (hasUTF32BigEndianBOM4(b) || hasUTF32LittleEndianBOM4(b)) { + b = b[4:] + } else if len(b) >= 3 && hasUTF8BOM3(b) { + b = b[3:] + } else if len(b) >= 2 && (hasUTF16BigEndianBOM2(b) || hasUTF16LittleEndianBOM2(b)) { + b = b[2:] + } + tree = parseToml(lexToml(b)) return } +func hasUTF16BigEndianBOM2(b []byte) bool { + return b[0] == 0xFE && b[1] == 0xFF +} + +func hasUTF16LittleEndianBOM2(b []byte) bool { + return b[0] == 0xFF && b[1] == 0xFE +} + +func hasUTF8BOM3(b []byte) bool { + return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF +} + +func hasUTF32BigEndianBOM4(b []byte) bool { + return b[0] == 0x00 && b[1] == 0x00 && b[2] == 0xFE && b[3] == 0xFF +} + +func hasUTF32LittleEndianBOM4(b []byte) bool { + return b[0] == 0xFF && b[1] == 0xFE && b[2] == 0x00 && b[3] == 0x00 +} + // LoadReader creates a Tree from any io.Reader. func LoadReader(reader io.Reader) (tree *Tree, err error) { inputBytes, err := ioutil.ReadAll(reader) diff --git a/toml_test.go b/toml_test.go index ab9c242..9bbe2c7 100644 --- a/toml_test.go +++ b/toml_test.go @@ -104,3 +104,23 @@ func TestTomlFromMap(t *testing.T) { t.Fatal("hello should be 42, not", tree.Get("hello")) } } + +func TestLoadBytesBOM(t *testing.T) { + payloads := [][]byte{ + []byte("\xFE\xFFhello=1"), + []byte("\xFF\xFEhello=1"), + []byte("\xEF\xBB\xBFhello=1"), + []byte("\x00\x00\xFE\xFFhello=1"), + []byte("\xFF\xFE\x00\x00hello=1"), + } + for _, data := range payloads { + tree, err := LoadBytes(data) + if err != nil { + t.Fatal("unexpected error:", err, "for:", data) + } + v := tree.Get("hello") + if v != int64(1) { + t.Fatal("hello should be 1, not", v) + } + } +}