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 |