253 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
| package jsoniter
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"unicode"
 | |
| )
 | |
| 
 | |
| // 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 {
 | |
| 	hash := int64(0x811c9dc5)
 | |
| 	for _, b := range str {
 | |
| 		if caseSensitive {
 | |
| 			hash ^= int64(b)
 | |
| 		} else {
 | |
| 			hash ^= int64(unicode.ToLower(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 == '{' {
 | |
| 		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) {
 | |
| 				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) {
 | |
| 					return false
 | |
| 				}
 | |
| 				c = iter.nextToken()
 | |
| 			}
 | |
| 			if c != '}' {
 | |
| 				iter.ReportError("ReadObjectCB", `object not ended with }`)
 | |
| 				return false
 | |
| 			}
 | |
| 			return true
 | |
| 		}
 | |
| 		if c == '}' {
 | |
| 			return true
 | |
| 		}
 | |
| 		iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c}))
 | |
| 		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 == '{' {
 | |
| 		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}))
 | |
| 				return false
 | |
| 			}
 | |
| 			if !callback(iter, field) {
 | |
| 				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}))
 | |
| 					return false
 | |
| 				}
 | |
| 				if !callback(iter, field) {
 | |
| 					return false
 | |
| 				}
 | |
| 				c = iter.nextToken()
 | |
| 			}
 | |
| 			if c != '}' {
 | |
| 				iter.ReportError("ReadMapCB", `object not ended with }`)
 | |
| 				return false
 | |
| 			}
 | |
| 			return true
 | |
| 		}
 | |
| 		if c == '}' {
 | |
| 			return true
 | |
| 		}
 | |
| 		iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
 | |
| 		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
 | |
| }
 |