| 200 | } |
| 201 | |
| 202 | func (dec *Decoder) skipObject() (int, error) { |
| 203 | var objectsOpen = 1 |
| 204 | var objectsClosed = 0 |
| 205 | for j := dec.cursor; j < dec.length || dec.read(); j++ { |
| 206 | switch dec.data[j] { |
| 207 | case '}': |
| 208 | objectsClosed++ |
| 209 | // everything is closed return |
| 210 | if objectsOpen == objectsClosed { |
| 211 | // add char to object data |
| 212 | return j + 1, nil |
| 213 | } |
| 214 | case '{': |
| 215 | objectsOpen++ |
| 216 | case '"': |
| 217 | j++ |
| 218 | var isInEscapeSeq bool |
| 219 | var isFirstQuote = true |
| 220 | for ; j < dec.length || dec.read(); j++ { |
| 221 | if dec.data[j] != '"' { |
| 222 | continue |
| 223 | } |
| 224 | if dec.data[j-1] != '\\' || (!isInEscapeSeq && !isFirstQuote) { |
| 225 | break |
| 226 | } else { |
| 227 | isInEscapeSeq = false |
| 228 | } |
| 229 | if isFirstQuote { |
| 230 | isFirstQuote = false |
| 231 | } |
| 232 | // loop backward and count how many anti slash found |
| 233 | // to see if string is effectively escaped |
| 234 | ct := 0 |
| 235 | for i := j - 1; i > 0; i-- { |
| 236 | if dec.data[i] != '\\' { |
| 237 | break |
| 238 | } |
| 239 | ct++ |
| 240 | } |
| 241 | // is pair number of slashes, quote is not escaped |
| 242 | if ct&1 == 0 { |
| 243 | break |
| 244 | } |
| 245 | isInEscapeSeq = true |
| 246 | } |
| 247 | default: |
| 248 | continue |
| 249 | } |
| 250 | } |
| 251 | return 0, dec.raiseInvalidJSONErr(dec.cursor) |
| 252 | } |
| 253 | |
| 254 | func (dec *Decoder) nextKey() (string, bool, error) { |
| 255 | for ; dec.cursor < dec.length || dec.read(); dec.cursor++ { |