package jsoniter import ( "fmt" "strings" ) // ReadObject read one field from object. // If object ended, returns empty string. // Otherwise, returns the field name. func (iter *Iterator) ReadObject() (ret string) { c := iter.nextToken() switch c { case 'n': iter.skipThreeBytes('u', 'l', 'l') return "" // null case '{': c = iter.nextToken() if c == '"' { iter.unreadByte() field := iter.ReadString() c = iter.nextToken() if c != ':' { iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) } return field } if c == '}' { return "" // end of object } iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c})) return case ',': field := iter.ReadString() c = iter.nextToken() if c != ':' { iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) } return field case '}': return "" // end of object default: iter.ReportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c}))) return } } // CaseInsensitive func (iter *Iterator) readFieldHash() int64 { hash := int64(0x811c9dc5) c := iter.nextToken() if c != '"' { iter.ReportError("readFieldHash", `expect ", but found `+string([]byte{c})) return 0 } for { for i := iter.head; i < iter.tail; i++ { // require ascii string and no escape b := iter.buf[i] if b == '\\' { iter.head = i for _, b := range iter.readStringSlowPath() { if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive { b += 'a' - 'A' } hash ^= int64(b) hash *= 0x1000193 } c = iter.nextToken() if c != ':' { iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) return 0 } return hash } if b == '"' { iter.head = i + 1 c = iter.nextToken() if c != ':' { iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) return 0 } return hash } if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive { b += 'a' - 'A' } hash ^= int64(b) hash *= 0x1000193 } if !iter.loadMore() { iter.ReportError("readFieldHash", `incomplete field name`) return 0 } } } func calcHash(str string, caseSensitive bool) int64 { if !caseSensitive { str = strings.ToLower(str) } hash := int64(0x811c9dc5) for _, b := range []byte(str) { hash ^= int64(b) hash *= 0x1000193 } return int64(hash) } // ReadObjectCB read object with callback, the key is ascii only and field name not copied func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { c := iter.nextToken() var field string if c == '{' { if !iter.incrementDepth() { return false } c = iter.nextToken() if c == '"' { iter.unreadByte() field = iter.ReadString() c = iter.nextToken() if c != ':' { iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) } if !callback(iter, field) { iter.decrementDepth() return false } c = iter.nextToken() for c == ',' { field = iter.ReadString() c = iter.nextToken() if c != ':' { iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) } if !callback(iter, field) { iter.decrementDepth() return false } c = iter.nextToken() } if c != '}' { iter.ReportError("ReadObjectCB", `object not ended with }`) iter.decrementDepth() return false } return iter.decrementDepth() } if c == '}' { return iter.decrementDepth() } iter.ReportError("ReadObjectCB", `expect " after {, but found `+string([]byte{c})) iter.decrementDepth() return false } if c == 'n' { iter.skipThreeBytes('u', 'l', 'l') return true // null } iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c})) return false } // ReadMapCB read map with callback, the key can be any string func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { c := iter.nextToken() if c == '{' { if !iter.incrementDepth() { return false } c = iter.nextToken() if c == '"' { iter.unreadByte() field := iter.ReadString() if iter.nextToken() != ':' { iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) iter.decrementDepth() return false } if !callback(iter, field) { iter.decrementDepth() return false } c = iter.nextToken() for c == ',' { field = iter.ReadString() if iter.nextToken() != ':' { iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) iter.decrementDepth() return false } if !callback(iter, field) { iter.decrementDepth() return false } c = iter.nextToken() } if c != '}' { iter.ReportError("ReadMapCB", `object not ended with }`) iter.decrementDepth() return false } return iter.decrementDepth() } if c == '}' { return iter.decrementDepth() } iter.ReportError("ReadMapCB", `expect " after {, but found `+string([]byte{c})) iter.decrementDepth() return false } if c == 'n' { iter.skipThreeBytes('u', 'l', 'l') return true // null } iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) return false } func (iter *Iterator) readObjectStart() bool { c := iter.nextToken() if c == '{' { c = iter.nextToken() if c == '}' { return false } iter.unreadByte() return true } else if c == 'n' { iter.skipThreeBytes('u', 'l', 'l') return false } iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c})) return false } func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) { str := iter.ReadStringAsSlice() if iter.skipWhitespacesWithoutLoadMore() { if ret == nil { ret = make([]byte, len(str)) copy(ret, str) } if !iter.loadMore() { return } } if iter.buf[iter.head] != ':' { iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]})) return } iter.head++ if iter.skipWhitespacesWithoutLoadMore() { if ret == nil { ret = make([]byte, len(str)) copy(ret, str) } if !iter.loadMore() { return } } if ret == nil { return str } return ret }