Line data Source code
1 : /*
2 : * Package : Cbor
3 : * Author : S. Hamblett <steve.hamblett@linux.com>
4 : * Date : 12/12/2016
5 : * Copyright : S.Hamblett
6 : */
7 :
8 : part of cbor;
9 :
10 : /// What we are waiting for next, if anything.
11 : enum whatsNext {
12 : aDateTimeString,
13 : aDateTimeEpoch,
14 : aDecimalFraction,
15 : aBigFloat,
16 : unassigned,
17 : aPositiveBignum,
18 : aNegativeBignum,
19 : aMultipleB64Url,
20 : aMultipleB64,
21 : aMultipleB16,
22 : encodedCBOR,
23 : aStringUri,
24 : aStringB64Url,
25 : aStringB64,
26 : aRegExp,
27 : aMIMEMessage,
28 : aSelfDescribeCBOR,
29 : nothing
30 : }
31 :
32 : /// The stack based listener class, produces a stack of DartItems
33 : /// from the decoder output.
34 : class ListenerStack extends Listener {
35 : ItemStack _stack = new ItemStack();
36 :
37 : /// Get the stack
38 3 : ItemStack get stack => _stack;
39 :
40 : /// Used to indicate what the
41 : /// next decoded item should be.
42 : whatsNext _next = whatsNext.nothing;
43 :
44 : /// Indefinite stack.
45 : /// A list of indefinite items, most recent at the end.
46 : /// Can only be string, bytes, list or map.
47 : List<String> _indefiniteStack = new List<String>();
48 :
49 : /// Indefinite bytes buffer assembler.
50 : final typed.Uint8Buffer _byteAssembly = new typed.Uint8Buffer();
51 :
52 : /// Indefinite String buffer assembler.
53 : String _stringAssembly;
54 :
55 : void onInteger(int value) {
56 : // Do not add nulls
57 : if (value == null) return;
58 3 : final DartItem item = new DartItem();
59 3 : item.data = value;
60 3 : item.type = dartTypes.dtInt;
61 3 : item.complete = true;
62 6 : if (_next == whatsNext.aDateTimeEpoch) {
63 3 : item.hint = dataHints.dateTimeEpoch;
64 3 : _next = whatsNext.nothing;
65 : }
66 3 : _append(item);
67 : }
68 :
69 : void onBytes(typed.Uint8Buffer data, int size) {
70 : // Check if we are expecting something, ie whats next
71 3 : switch (_next) {
72 3 : case whatsNext.aPositiveBignum:
73 : // Convert to a positive integer and append
74 1 : final int value = bignumToInt(data, "+");
75 1 : onInteger(value);
76 : break;
77 3 : case whatsNext.aNegativeBignum:
78 1 : int value = bignumToInt(data, "-");
79 1 : value = -1 + value;
80 2 : onInteger(value.abs());
81 : break;
82 3 : case whatsNext.aMultipleB64Url:
83 : if (data == null) return;
84 2 : final DartItem item = new DartItem();
85 2 : item.data = data;
86 2 : item.type = dartTypes.dtBuffer;
87 2 : item.hint = dataHints.base64Url;
88 2 : item.complete = true;
89 2 : _append(item);
90 : break;
91 3 : case whatsNext.aMultipleB64:
92 : if (data == null) return;
93 2 : final DartItem item = new DartItem();
94 2 : item.data = data;
95 2 : item.type = dartTypes.dtBuffer;
96 2 : item.hint = dataHints.base64;
97 2 : item.complete = true;
98 2 : _append(item);
99 : break;
100 3 : case whatsNext.aMultipleB16:
101 : if (data == null) return;
102 3 : final DartItem item = new DartItem();
103 3 : item.data = data;
104 3 : item.type = dartTypes.dtBuffer;
105 3 : item.hint = dataHints.base16;
106 3 : item.complete = true;
107 3 : _append(item);
108 : break;
109 3 : case whatsNext.encodedCBOR:
110 : if (data == null) return;
111 3 : final DartItem item = new DartItem();
112 3 : item.data = data;
113 3 : item.type = dartTypes.dtBuffer;
114 3 : item.hint = dataHints.encodedCBOR;
115 3 : item.complete = true;
116 3 : _append(item);
117 : break;
118 3 : case whatsNext.aSelfDescribeCBOR:
119 : if (data == null) return;
120 1 : final DartItem item = new DartItem();
121 1 : item.data = data;
122 1 : item.type = dartTypes.dtBuffer;
123 1 : item.hint = dataHints.selfDescCBOR;
124 1 : item.complete = true;
125 1 : _append(item);
126 : break;
127 3 : case whatsNext.unassigned:
128 : if (data == null) return;
129 0 : final DartItem item = new DartItem();
130 0 : item.data = data;
131 0 : item.type = dartTypes.dtBuffer;
132 0 : item.complete = true;
133 0 : _append(item);
134 : break;
135 3 : case whatsNext.nothing:
136 : default:
137 : if (data == null) return;
138 3 : if (_waitingIndefBytes()) {
139 4 : _byteAssembly.addAll(data);
140 : } else {
141 3 : final DartItem item = new DartItem();
142 3 : item.data = data;
143 3 : item.type = dartTypes.dtBuffer;
144 3 : item.complete = true;
145 3 : _append(item);
146 : }
147 : }
148 3 : _next = whatsNext.nothing;
149 : }
150 :
151 : void onString(String str) {
152 : if (str == null) return;
153 3 : if (_waitingIndefString()) {
154 4 : _stringAssembly += str;
155 : } else {
156 3 : final DartItem item = new DartItem();
157 3 : item.data = str;
158 3 : item.type = dartTypes.dtString;
159 3 : switch (_next) {
160 3 : case whatsNext.aDateTimeString:
161 3 : item.hint = dataHints.dateTimeString;
162 : break;
163 3 : case whatsNext.aStringUri:
164 3 : item.hint = dataHints.uri;
165 : break;
166 3 : case whatsNext.aStringB64Url:
167 1 : item.hint = dataHints.base64Url;
168 : break;
169 3 : case whatsNext.aStringB64:
170 1 : item.hint = dataHints.base64;
171 : break;
172 3 : case whatsNext.aRegExp:
173 1 : item.hint = dataHints.regex;
174 : break;
175 3 : case whatsNext.aMIMEMessage:
176 1 : item.hint = dataHints.mime;
177 : break;
178 : default:
179 : break;
180 : }
181 3 : _next = whatsNext.nothing;
182 3 : item.complete = true;
183 3 : _append(item);
184 : }
185 : }
186 :
187 : void onArray(int size) {
188 3 : final DartItem item = new DartItem();
189 3 : item.type = dartTypes.dtList;
190 6 : item.data = new List<dynamic>();
191 3 : item.targetSize = size;
192 3 : if (size == 0) {
193 3 : item.complete = true;
194 : }
195 3 : _append(item);
196 : }
197 :
198 : void onMap(int size) {
199 3 : final DartItem item = new DartItem();
200 3 : item.type = dartTypes.dtMap;
201 6 : item.data = new Map<dynamic, dynamic>();
202 3 : item.targetSize = size;
203 3 : item.awaitingMapKey = true;
204 3 : if (size == 0) {
205 1 : item.complete = true;
206 : }
207 3 : _append(item);
208 : }
209 :
210 : void onTag(int tag) {
211 : // Switch on the tag type
212 : switch (tag) {
213 3 : case 0: // Date time string
214 3 : _next = whatsNext.aDateTimeString;
215 : break;
216 3 : case 1: // Date/Time epoch
217 3 : _next = whatsNext.aDateTimeEpoch;
218 : break;
219 3 : case 2: // Positive bignum
220 1 : _next = whatsNext.aPositiveBignum;
221 : break;
222 3 : case 3: // Negative bignum
223 1 : _next = whatsNext.aNegativeBignum;
224 : break;
225 3 : case 4: // Decimal fraction
226 0 : _next = whatsNext.aDecimalFraction;
227 : break;
228 3 : case 5: // Bigfloat
229 0 : _next = whatsNext.aBigFloat;
230 : break;
231 3 : case 21: // B64 URL
232 2 : _next = whatsNext.aMultipleB64Url;
233 : break;
234 3 : case 22: // B64
235 2 : _next = whatsNext.aMultipleB64;
236 : break;
237 3 : case 23: // B16
238 3 : _next = whatsNext.aMultipleB16;
239 : break;
240 3 : case 24: // Encoded CBOR item
241 3 : _next = whatsNext.encodedCBOR;
242 : break;
243 3 : case 32: // URI
244 3 : _next = whatsNext.aStringUri;
245 : break;
246 1 : case 33: // String B64 URL
247 1 : _next = whatsNext.aStringB64Url;
248 : break;
249 1 : case 34: // String B64
250 1 : _next = whatsNext.aStringB64;
251 : break;
252 1 : case 35: // Regular Expression
253 1 : _next = whatsNext.aRegExp;
254 : break;
255 1 : case 36: // MIME message
256 1 : _next = whatsNext.aMIMEMessage;
257 : break;
258 1 : case 55799: // Self describe CBOR sequence
259 1 : _next = whatsNext.aSelfDescribeCBOR;
260 : break;
261 : default: // Unassigned values
262 1 : _next = whatsNext.unassigned;
263 : }
264 : }
265 :
266 : void onSpecial(int code) {
267 : if (code == null) return;
268 3 : final DartItem item = new DartItem();
269 3 : item.data = code;
270 3 : item.type = dartTypes.dtInt;
271 3 : item.complete = true;
272 3 : _append(item);
273 : }
274 :
275 : void onSpecialFloat(double value) {
276 : // Do not add nulls
277 : if (value == null) return;
278 3 : final DartItem item = new DartItem();
279 3 : item.data = value;
280 3 : item.type = dartTypes.dtDouble;
281 3 : item.complete = true;
282 3 : _append(item);
283 : }
284 :
285 : void onBool(bool state) {
286 : // Do not add nulls
287 : if (state == null) return;
288 3 : final DartItem item = new DartItem();
289 3 : item.data = state;
290 3 : item.type = dartTypes.dtBool;
291 3 : item.complete = true;
292 3 : _append(item);
293 : }
294 :
295 : void onNull() {
296 3 : final DartItem item = new DartItem();
297 3 : item.type = dartTypes.dtNull;
298 3 : item.complete = true;
299 3 : _append(item);
300 : }
301 :
302 : void onUndefined() {
303 3 : final DartItem item = new DartItem();
304 3 : item.type = dartTypes.dtUndefined;
305 3 : item.complete = true;
306 3 : _append(item);
307 : }
308 :
309 : void onError(String error) {
310 : if (error == null) return;
311 1 : final DartItem item = new DartItem();
312 1 : item.data = error;
313 1 : item.type = dartTypes.dtString;
314 1 : item.hint = dataHints.error;
315 1 : item.complete = true;
316 1 : _append(item);
317 : }
318 :
319 : void onExtraInteger(int value, int sign) {
320 : // Sign adjustment is done by the decoder so
321 : // we can ignore it here
322 1 : onInteger(value);
323 : }
324 :
325 : void onExtraTag(int tag) {
326 : // Not yet implemented
327 : }
328 :
329 : void onIndefinite(String text) {
330 : // Process depending on indefinite type.
331 : switch (text) {
332 2 : case indefBytes:
333 4 : _indefiniteStack.add(text);
334 4 : _byteAssembly.clear();
335 : break;
336 2 : case indefString:
337 4 : _indefiniteStack.add(text);
338 2 : _stringAssembly = "";
339 : break;
340 2 : case indefMap:
341 4 : _indefiniteStack.add(text);
342 2 : onMap(indefiniteMaxSize);
343 : break;
344 2 : case indefArray:
345 4 : _indefiniteStack.add(text);
346 2 : onArray(indefiniteMaxSize);
347 : break;
348 2 : case indefStop:
349 : // Get the top of the indefinite stack and switch on it.
350 6 : if (_indefiniteStack.length == 0) {
351 0 : onError("Unbalanced indefinite break");
352 : break;
353 : }
354 4 : final String top = _indefiniteStack.removeLast();
355 : switch (top) {
356 2 : case indefBytes:
357 8 : onBytes(_byteAssembly, _byteAssembly.length);
358 : break;
359 2 : case indefString:
360 4 : onString(_stringAssembly);
361 : break;
362 2 : case indefMap:
363 2 : case indefArray:
364 : // Complete the stack top, pop and append
365 2 : _stack
366 2 : .peek()
367 4 : .targetSize = _stack
368 2 : .peek()
369 2 : .data
370 2 : .length;
371 2 : _stack
372 2 : .peek()
373 2 : .complete = true;
374 6 : _append(_stack.pop());
375 : break;
376 : default:
377 0 : onError("Unknown indefinite type on stop");
378 : }
379 : break;
380 : default:
381 0 : onError("Unknown indefinite type on start");
382 : }
383 : }
384 :
385 : /// Main stack append method.
386 : void _append(DartItem item) {
387 3 : _appendImpl(item);
388 : }
389 :
390 : /// Append implementation.
391 : void _appendImpl(DartItem item) {
392 9 : if (_stack.size() == 0) {
393 : // Empty stack, straight add
394 6 : _stack.push(item);
395 : } else {
396 6 : final DartItem entry = _stack.peek();
397 :
398 : /// If its complete push
399 : /// the item. if not complete append and check
400 : /// for completeness.
401 3 : if (entry.complete) {
402 6 : _stack.push(item);
403 : } else {
404 : // List or Map
405 6 : if (entry.type == dartTypes.dtList) {
406 6 : if (item.isIncompleteList() || item.isIncompleteMap()) {
407 4 : _stack.push(item);
408 : } else {
409 9 : entry.data.add(item.data);
410 12 : if (entry.data.length == entry.targetSize) {
411 3 : entry.complete = true;
412 : // Item can be ignored.
413 3 : item.ignore = true;
414 : // Recurse for nested lists
415 6 : final DartItem item1 = _stack.pop();
416 3 : _appendImpl(item1);
417 : }
418 : }
419 6 : } else if (entry.type == dartTypes.dtMap) {
420 : // Check if we are expecting a key or a value
421 3 : if (entry.awaitingMapKey) {
422 : // Create the map entry with the key, set we
423 : // are now waiting for a value.
424 12 : entry.data.addAll({item.data: null});
425 6 : entry.lastMapKey = item.data;
426 3 : entry.awaitingMapKey = false;
427 3 : entry.awaitingMapValue = true;
428 3 : } else if (entry.awaitingMapValue) {
429 : // If the item is a list or a map just push it if it
430 : // is not complete,
431 : // if not then reset awaiting map value.
432 : // Either way update the entry with the value.
433 6 : if (item.isIncompleteList() || item.isIncompleteMap()) {
434 6 : _stack.push(item);
435 : } else {
436 3 : entry.awaitingMapValue = false;
437 : }
438 12 : entry.data[entry.lastMapKey] = item.data;
439 :
440 : // Check for completeness
441 12 : if (entry.data.length == entry.targetSize) {
442 3 : entry.complete = true;
443 : // Item can be ignored.
444 3 : item.ignore = true;
445 : // Recurse for nested maps
446 6 : final DartItem item1 = _stack.pop();
447 3 : _appendImpl(item1);
448 : } else {
449 : // If we are still awiating a value(netsed list
450 : // or map) then don't expect a key.
451 3 : if (!entry.awaitingMapValue) {
452 3 : entry.awaitingMapKey = true;
453 : }
454 : }
455 : }
456 : } else {
457 0 : onError("Incomplete stack item is not list or map");
458 : }
459 : }
460 : }
461 : }
462 :
463 : /// Helper functions.
464 :
465 : /// Waiting for indefinite bytes.
466 : bool _waitingIndefBytes() {
467 9 : if (_indefiniteStack.length != 0) {
468 6 : if (_indefiniteStack.last == indefBytes) {
469 : return true;
470 : }
471 : }
472 : return false;
473 : }
474 :
475 : /// Waiting for indefinite string.
476 : bool _waitingIndefString() {
477 9 : if (_indefiniteStack.length != 0) {
478 6 : if (_indefiniteStack.last == indefString) {
479 : return true;
480 : }
481 : }
482 : return false;
483 : }
484 : }
|