Repository: goccy/go-json (go)

Issue:
MarshalIndentWithOption is failing with UnorderedMap
Hello, 
There looks like an issue when using the option UnorderedMap with MarshalIndentWithOption.
Mostly it will timeout for me.
But It's taking forever to Marshal Json

Example code:

```go
	var obj map[string]*json.RawMessage
	data := `{\n  \"b\": \"b\",\n \"a\": \"a\"}`
	s, _ := strconv.Unquote(`"` + data + `"`)
	json.Unmarshal([]byte(s), &obj)
	fmt.Println(s)
	output, _ := json.MarshalIndentWithOption(obj, "", " ", json.UnorderedMap())
	fmt.Println(string(output))
```
**Playground: https://go.dev/play/p/8ERpUAccldx**

Pull request:
fix: fixed a problem that MarshalIndent does not work when UnorderedMap is specified
fixed negative overflow on appendObjectEnd
fixed output on appendColon and appendObjectEnd

fix #417

Patch:
diff --git a/internal/decoder/struct.go b/internal/decoder/struct.go
index 4e14a20..313da15 100644
--- a/internal/decoder/struct.go
+++ b/internal/decoder/struct.go
@@ -51,6 +51,14 @@ func init() {
 	}
 }
 
+func toASCIILower(s string) string {
+	b := []byte(s)
+	for i := range b {
+		b[i] = largeToSmallTable[b[i]]
+	}
+	return string(b)
+}
+
 func newStructDecoder(structName, fieldName string, fieldMap map[string]*structFieldSet) *structDecoder {
 	return &structDecoder{
 		fieldMap:         fieldMap,
@@ -91,6 +99,10 @@ func (d *structDecoder) tryOptimize() {
 	for k, v := range d.fieldMap {
 		key := strings.ToLower(k)
 		if key != k {
+			if key != toASCIILower(k) {
+				d.isTriedOptimize = true
+				return
+			}
 			// already exists same key (e.g. Hello and HELLO has same lower case key
 			if _, exists := conflicted[key]; exists {
 				d.isTriedOptimize = true
diff --git a/internal/encoder/vm_color_indent/util.go b/internal/encoder/vm_color_indent/util.go
index 60e4a8e..2395abe 100644
--- a/internal/encoder/vm_color_indent/util.go
+++ b/internal/encoder/vm_color_indent/util.go
@@ -189,7 +189,7 @@ func appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte {
 }
 
 func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
-	return append(b, ':', ' ')
+	return append(b[:len(b)-2], ':', ' ')
 }
 
 func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
@@ -229,8 +229,9 @@ func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte {
 
 func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
 	last := len(b) - 1
-	b[last] = '\n'
-	b = appendIndent(ctx, b, code.Indent-1)
+	// replace comma to newline
+	b[last-1] = '\n'
+	b = appendIndent(ctx, b[:last], code.Indent)
 	return append(b, '}', ',', '\n')
 }
 
diff --git a/internal/encoder/vm_indent/util.go b/internal/encoder/vm_indent/util.go
index fca8f18..6cb745e 100644
--- a/internal/encoder/vm_indent/util.go
+++ b/internal/encoder/vm_indent/util.go
@@ -133,7 +133,7 @@ func appendNullComma(_ *encoder.RuntimeContext, b []byte) []byte {
 }
 
 func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
-	return append(b, ':', ' ')
+	return append(b[:len(b)-2], ':', ' ')
 }
 
 func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
@@ -173,8 +173,9 @@ func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte {
 
 func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
 	last := len(b) - 1
-	b[last] = '\n'
-	b = appendIndent(ctx, b, code.Indent-1)
+	// replace comma to newline
+	b[last-1] = '\n'
+	b = appendIndent(ctx, b[:last], code.Indent)
 	return append(b, '}', ',', '\n')
 }
 


Test patch:
diff --git a/decode_test.go b/decode_test.go
index a1a10e9..9306b2e 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -4016,6 +4016,18 @@ func TestIssue408(t *testing.T) {
 	}
 }
 
+func TestIssue416(t *testing.T) {
+	b := []byte(`{"Сообщение":"Текст"}`)
+
+	type T struct {
+		Msg string `json:"Сообщение"`
+	}
+	var x T
+	err := json.Unmarshal(b, &x)
+	assertErr(t, err)
+	assertEq(t, "unexpected result", "Текст", x.Msg)
+}
+
 func TestIssue429(t *testing.T) {
 	var x struct {
 		N int32
diff --git a/encode_test.go b/encode_test.go
index 3ff3fcb..f3b57bf 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -2630,6 +2630,22 @@ func TestCustomMarshalForMapKey(t *testing.T) {
 	assertEq(t, "custom map key", string(expected), string(got))
 }
 
+func TestIssue417(t *testing.T) {
+	x := map[string]string{
+		"b": "b",
+		"a": "a",
+	}
+	b, err := json.MarshalIndentWithOption(x, "", " ", json.UnorderedMap())
+	assertErr(t, err)
+
+	var y map[string]string
+	err = json.Unmarshal(b, &y)
+	assertErr(t, err)
+
+	assertEq(t, "key b", "b", y["b"])
+	assertEq(t, "key a", "a", y["a"])
+}
+
 func TestIssue426(t *testing.T) {
 	type I interface {
 		Foo()