| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package serialize | 5 package serialize |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "errors" | 9 "errors" |
| 10 "fmt" | 10 "fmt" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 panicIf(buf.WriteByte(1)) | 68 panicIf(buf.WriteByte(1)) |
| 69 panicIf(WriteKeyTok(buf, tok)) | 69 panicIf(WriteKeyTok(buf, tok)) |
| 70 } | 70 } |
| 71 return buf.WriteByte(0) | 71 return buf.WriteByte(0) |
| 72 } | 72 } |
| 73 | 73 |
| 74 // ReadKey deserializes a key from the buffer. The value of context must match | 74 // ReadKey deserializes a key from the buffer. The value of context must match |
| 75 // the value of context that was passed to WriteKey when the key was encoded. | 75 // the value of context that was passed to WriteKey when the key was encoded. |
| 76 // If context == WithoutContext, then the appid and namespace parameters are | 76 // If context == WithoutContext, then the appid and namespace parameters are |
| 77 // used in the decoded Key. Otherwise they're ignored. | 77 // used in the decoded Key. Otherwise they're ignored. |
| 78 func ReadKey(buf Buffer, context KeyContext, appid, namespace string) (ret *ds.K
ey, err error) { | 78 func ReadKey(buf Buffer, context KeyContext, inKC ds.KeyContext) (ret *ds.Key, e
rr error) { |
| 79 defer recoverTo(&err) | 79 defer recoverTo(&err) |
| 80 actualCtx, e := buf.ReadByte() | 80 actualCtx, e := buf.ReadByte() |
| 81 panicIf(e) | 81 panicIf(e) |
| 82 | 82 |
| 83 » actualAid, actualNS := "", "" | 83 » var kc ds.KeyContext |
| 84 if actualCtx == 1 { | 84 if actualCtx == 1 { |
| 85 » » actualAid, _, e = cmpbin.ReadString(buf) | 85 » » kc.AppID, _, e = cmpbin.ReadString(buf) |
| 86 panicIf(e) | 86 panicIf(e) |
| 87 » » actualNS, _, e = cmpbin.ReadString(buf) | 87 » » kc.Namespace, _, e = cmpbin.ReadString(buf) |
| 88 panicIf(e) | 88 panicIf(e) |
| 89 } else if actualCtx != 0 { | 89 } else if actualCtx != 0 { |
| 90 err = fmt.Errorf("helper: expected actualCtx to be 0 or 1, got %
d", actualCtx) | 90 err = fmt.Errorf("helper: expected actualCtx to be 0 or 1, got %
d", actualCtx) |
| 91 return | 91 return |
| 92 } | 92 } |
| 93 | 93 |
| 94 if context == WithoutContext { | 94 if context == WithoutContext { |
| 95 // overrwrite with the supplied ones | 95 // overrwrite with the supplied ones |
| 96 » » actualAid = appid | 96 » » kc = inKC |
| 97 » » actualNS = namespace | |
| 98 } | 97 } |
| 99 | 98 |
| 100 toks := []ds.KeyTok{} | 99 toks := []ds.KeyTok{} |
| 101 for { | 100 for { |
| 102 ctrlByte, e := buf.ReadByte() | 101 ctrlByte, e := buf.ReadByte() |
| 103 panicIf(e) | 102 panicIf(e) |
| 104 if ctrlByte == 0 { | 103 if ctrlByte == 0 { |
| 105 break | 104 break |
| 106 } | 105 } |
| 107 if len(toks)+1 > ReadKeyNumToksReasonableLimit { | 106 if len(toks)+1 > ReadKeyNumToksReasonableLimit { |
| 108 err = fmt.Errorf( | 107 err = fmt.Errorf( |
| 109 "helper: tried to decode huge key with > %d toke
ns", | 108 "helper: tried to decode huge key with > %d toke
ns", |
| 110 ReadKeyNumToksReasonableLimit) | 109 ReadKeyNumToksReasonableLimit) |
| 111 return | 110 return |
| 112 } | 111 } |
| 113 | 112 |
| 114 tok, e := ReadKeyTok(buf) | 113 tok, e := ReadKeyTok(buf) |
| 115 panicIf(e) | 114 panicIf(e) |
| 116 | 115 |
| 117 toks = append(toks, tok) | 116 toks = append(toks, tok) |
| 118 } | 117 } |
| 119 | 118 |
| 120 » return ds.NewKeyToks(actualAid, actualNS, toks), nil | 119 » return kc.NewKeyToks(toks), nil |
| 121 } | 120 } |
| 122 | 121 |
| 123 // WriteKeyTok writes a KeyTok to the buffer. You usually want WriteKey | 122 // WriteKeyTok writes a KeyTok to the buffer. You usually want WriteKey |
| 124 // instead of this. | 123 // instead of this. |
| 125 func WriteKeyTok(buf Buffer, tok ds.KeyTok) (err error) { | 124 func WriteKeyTok(buf Buffer, tok ds.KeyTok) (err error) { |
| 126 // tok.kind ++ typ ++ [tok.stringID || tok.intID] | 125 // tok.kind ++ typ ++ [tok.stringID || tok.intID] |
| 127 defer recoverTo(&err) | 126 defer recoverTo(&err) |
| 128 _, e := cmpbin.WriteString(buf, tok.Kind) | 127 _, e := cmpbin.WriteString(buf, tok.Kind) |
| 129 panicIf(e) | 128 panicIf(e) |
| 130 if tok.StringID != "" { | 129 if tok.StringID != "" { |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 err = WriteGeoPoint(buf, t) | 269 err = WriteGeoPoint(buf, t) |
| 271 case *ds.Key: | 270 case *ds.Key: |
| 272 err = WriteKey(buf, context, t) | 271 err = WriteKey(buf, context, t) |
| 273 | 272 |
| 274 default: | 273 default: |
| 275 err = fmt.Errorf("unsupported type: %T", t) | 274 err = fmt.Errorf("unsupported type: %T", t) |
| 276 } | 275 } |
| 277 return | 276 return |
| 278 } | 277 } |
| 279 | 278 |
| 280 // ReadProperty reads a Property from the buffer. `context`, `appid`, and | 279 // ReadProperty reads a Property from the buffer. `context` and `kc` behave the |
| 281 // `namespace` behave the same way they do for ReadKey, but only have an | 280 // same way they do for ReadKey, but only have an effect if the decoded property |
| 282 // effect if the decoded property has a Key value. | 281 // has a Key value. |
| 283 func ReadProperty(buf Buffer, context KeyContext, appid, namespace string) (p ds
.Property, err error) { | 282 func ReadProperty(buf Buffer, context KeyContext, kc ds.KeyContext) (p ds.Proper
ty, err error) { |
| 284 val := interface{}(nil) | 283 val := interface{}(nil) |
| 285 b, err := buf.ReadByte() | 284 b, err := buf.ReadByte() |
| 286 if err != nil { | 285 if err != nil { |
| 287 return | 286 return |
| 288 } | 287 } |
| 289 is := ds.ShouldIndex | 288 is := ds.ShouldIndex |
| 290 if (b & 0x80) == 0 { | 289 if (b & 0x80) == 0 { |
| 291 is = ds.NoIndex | 290 is = ds.NoIndex |
| 292 } | 291 } |
| 293 switch ds.PropertyType(b & 0x7f) { | 292 switch ds.PropertyType(b & 0x7f) { |
| 294 case ds.PTNull: | 293 case ds.PTNull: |
| 295 case ds.PTBool: | 294 case ds.PTBool: |
| 296 b, err = buf.ReadByte() | 295 b, err = buf.ReadByte() |
| 297 val = (b != 0) | 296 val = (b != 0) |
| 298 case ds.PTInt: | 297 case ds.PTInt: |
| 299 val, _, err = cmpbin.ReadInt(buf) | 298 val, _, err = cmpbin.ReadInt(buf) |
| 300 case ds.PTFloat: | 299 case ds.PTFloat: |
| 301 val, _, err = cmpbin.ReadFloat64(buf) | 300 val, _, err = cmpbin.ReadFloat64(buf) |
| 302 case ds.PTString: | 301 case ds.PTString: |
| 303 val, _, err = cmpbin.ReadString(buf) | 302 val, _, err = cmpbin.ReadString(buf) |
| 304 case ds.PTBytes: | 303 case ds.PTBytes: |
| 305 val, _, err = cmpbin.ReadBytes(buf) | 304 val, _, err = cmpbin.ReadBytes(buf) |
| 306 case ds.PTTime: | 305 case ds.PTTime: |
| 307 val, err = ReadTime(buf) | 306 val, err = ReadTime(buf) |
| 308 case ds.PTGeoPoint: | 307 case ds.PTGeoPoint: |
| 309 val, err = ReadGeoPoint(buf) | 308 val, err = ReadGeoPoint(buf) |
| 310 case ds.PTKey: | 309 case ds.PTKey: |
| 311 » » val, err = ReadKey(buf, context, appid, namespace) | 310 » » val, err = ReadKey(buf, context, kc) |
| 312 case ds.PTBlobKey: | 311 case ds.PTBlobKey: |
| 313 s := "" | 312 s := "" |
| 314 if s, _, err = cmpbin.ReadString(buf); err != nil { | 313 if s, _, err = cmpbin.ReadString(buf); err != nil { |
| 315 break | 314 break |
| 316 } | 315 } |
| 317 val = blobstore.Key(s) | 316 val = blobstore.Key(s) |
| 318 default: | 317 default: |
| 319 err = fmt.Errorf("read: unknown type! %v", b) | 318 err = fmt.Errorf("read: unknown type! %v", b) |
| 320 } | 319 } |
| 321 if err == nil { | 320 if err == nil { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 panicIf(e) | 356 panicIf(e) |
| 358 for _, r := range rows { | 357 for _, r := range rows { |
| 359 _, e := buf.WriteString(r) | 358 _, e := buf.WriteString(r) |
| 360 panicIf(e) | 359 panicIf(e) |
| 361 } | 360 } |
| 362 return | 361 return |
| 363 } | 362 } |
| 364 | 363 |
| 365 // ReadPropertyMap reads a PropertyMap from the buffer. `context` and | 364 // ReadPropertyMap reads a PropertyMap from the buffer. `context` and |
| 366 // friends behave the same way that they do for ReadKey. | 365 // friends behave the same way that they do for ReadKey. |
| 367 func ReadPropertyMap(buf Buffer, context KeyContext, appid, namespace string) (p
m ds.PropertyMap, err error) { | 366 func ReadPropertyMap(buf Buffer, context KeyContext, kc ds.KeyContext) (pm ds.Pr
opertyMap, err error) { |
| 368 defer recoverTo(&err) | 367 defer recoverTo(&err) |
| 369 | 368 |
| 370 numRows := uint64(0) | 369 numRows := uint64(0) |
| 371 numRows, _, e := cmpbin.ReadUint(buf) | 370 numRows, _, e := cmpbin.ReadUint(buf) |
| 372 panicIf(e) | 371 panicIf(e) |
| 373 if numRows > ReadPropertyMapReasonableLimit { | 372 if numRows > ReadPropertyMapReasonableLimit { |
| 374 err = fmt.Errorf("helper: tried to decode map with huge number o
f rows %d", numRows) | 373 err = fmt.Errorf("helper: tried to decode map with huge number o
f rows %d", numRows) |
| 375 return | 374 return |
| 376 } | 375 } |
| 377 | 376 |
| 378 pm = make(ds.PropertyMap, numRows) | 377 pm = make(ds.PropertyMap, numRows) |
| 379 | 378 |
| 380 name, prop := "", ds.Property{} | 379 name, prop := "", ds.Property{} |
| 381 for i := uint64(0); i < numRows; i++ { | 380 for i := uint64(0); i < numRows; i++ { |
| 382 name, _, e = cmpbin.ReadString(buf) | 381 name, _, e = cmpbin.ReadString(buf) |
| 383 panicIf(e) | 382 panicIf(e) |
| 384 | 383 |
| 385 numProps, _, e := cmpbin.ReadUint(buf) | 384 numProps, _, e := cmpbin.ReadUint(buf) |
| 386 panicIf(e) | 385 panicIf(e) |
| 387 if numProps > ReadPropertyMapReasonableLimit { | 386 if numProps > ReadPropertyMapReasonableLimit { |
| 388 err = fmt.Errorf("helper: tried to decode map with huge
number of properties %d", numProps) | 387 err = fmt.Errorf("helper: tried to decode map with huge
number of properties %d", numProps) |
| 389 return | 388 return |
| 390 } | 389 } |
| 391 props := make([]ds.Property, 0, numProps) | 390 props := make([]ds.Property, 0, numProps) |
| 392 for j := uint64(0); j < numProps; j++ { | 391 for j := uint64(0); j < numProps; j++ { |
| 393 » » » prop, err = ReadProperty(buf, context, appid, namespace) | 392 » » » prop, err = ReadProperty(buf, context, kc) |
| 394 panicIf(err) | 393 panicIf(err) |
| 395 props = append(props, prop) | 394 props = append(props, prop) |
| 396 } | 395 } |
| 397 pm[name] = props | 396 pm[name] = props |
| 398 } | 397 } |
| 399 return | 398 return |
| 400 } | 399 } |
| 401 | 400 |
| 402 // WriteIndexColumn writes an IndexColumn to the buffer. | 401 // WriteIndexColumn writes an IndexColumn to the buffer. |
| 403 func WriteIndexColumn(buf Buffer, c ds.IndexColumn) (err error) { | 402 func WriteIndexColumn(buf Buffer, c ds.IndexColumn) (err error) { |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 } | 611 } |
| 613 } | 612 } |
| 614 | 613 |
| 615 func recoverTo(err *error) { | 614 func recoverTo(err *error) { |
| 616 if r := recover(); r != nil { | 615 if r := recover(); r != nil { |
| 617 if rerr := r.(parseError); rerr != nil { | 616 if rerr := r.(parseError); rerr != nil { |
| 618 *err = error(rerr) | 617 *err = error(rerr) |
| 619 } | 618 } |
| 620 } | 619 } |
| 621 } | 620 } |
| OLD | NEW |