LCOV - code coverage report
Current view: top level - src - cbor_listener_stack.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 227 238 95.4 %
Date: 2017-04-06 Functions: 0 0 -

          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             : }

Generated by: LCOV version 1.10