terence zhang / wakaama
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers json.c Source File

json.c

00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2015 Intel Corporation and others.
00004  * All rights reserved. This program and the accompanying materials
00005  * are made available under the terms of the Eclipse Public License v1.0
00006  * and Eclipse Distribution License v1.0 which accompany this distribution.
00007  *
00008  * The Eclipse Public License is available at
00009  *    http://www.eclipse.org/legal/epl-v10.html
00010  * The Eclipse Distribution License is available at
00011  *    http://www.eclipse.org/org/documents/edl-v10.php.
00012  *
00013  * Contributors:
00014  *    David Navarro, Intel Corporation - initial API and implementation
00015  *
00016  *******************************************************************************/
00017 
00018 
00019 #include "internals.h"
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <stdio.h>
00023 #include <inttypes.h>
00024 
00025 
00026 #ifdef LWM2M_SUPPORT_JSON
00027 
00028 #define PRV_JSON_BUFFER_SIZE 1024
00029 
00030 #define JSON_MIN_ARRAY_LEN      21      // e":[{"n":"N","v":X}]}
00031 #define JSON_MIN_BASE_LEN        7      // n":"N",
00032 #define JSON_ITEM_MAX_SIZE      36      // with ten characters for value
00033 #define JSON_MIN_BX_LEN          5      // bt":1
00034 
00035 #define JSON_FALSE_STRING  "false"
00036 #define JSON_TRUE_STRING   "true"
00037 
00038 #define JSON_RES_ITEM_URI           "{\"n\":\""
00039 #define JSON_RES_ITEM_URI_SIZE      6
00040 #define JSON_ITEM_BOOL_TRUE         "\",\"bv\":true},"
00041 #define JSON_ITEM_BOOL_TRUE_SIZE    13
00042 #define JSON_ITEM_BOOL_FALSE        "\",\"bv\":false},"
00043 #define JSON_ITEM_BOOL_FALSE_SIZE   14
00044 #define JSON_ITEM_NUM               "\",\"v\":"
00045 #define JSON_ITEM_NUM_SIZE          6
00046 #define JSON_ITEM_NUM_END           "},"
00047 #define JSON_ITEM_NUM_END_SIZE      2
00048 #define JSON_ITEM_STRING_BEGIN      "\",\"sv\":\""
00049 #define JSON_ITEM_STRING_BEGIN_SIZE 8
00050 #define JSON_ITEM_STRING_END        "\"},"
00051 #define JSON_ITEM_STRING_END_SIZE   3
00052 
00053 #define JSON_BN_HEADER_1        "{\"bn\":\""
00054 #define JSON_BN_HEADER_1_SIZE   7
00055 #define JSON_BN_HEADER_2        "\",\"e\":["
00056 #define JSON_BN_HEADER_2_SIZE   7
00057 #define JSON_HEADER             "{\"e\":["
00058 #define JSON_HEADER_SIZE        6
00059 #define JSON_FOOTER             "]}"
00060 #define JSON_FOOTER_SIZE        2
00061 
00062 
00063 #define _GO_TO_NEXT_CHAR(I,B,L)         \
00064     {                                   \
00065         I++;                            \
00066         I += prv_skipSpace(B+I, L-I);   \
00067         if (I == L) goto error;         \
00068     }
00069 
00070 typedef enum
00071 {
00072     _STEP_START,
00073     _STEP_TOKEN,
00074     _STEP_ANY_SEPARATOR,
00075     _STEP_SEPARATOR,
00076     _STEP_QUOTED_VALUE,
00077     _STEP_VALUE,
00078     _STEP_DONE
00079 } _itemState;
00080 
00081 typedef enum
00082 {
00083     _TYPE_UNSET,
00084     _TYPE_FALSE,
00085     _TYPE_TRUE,
00086     _TYPE_FLOAT,
00087     _TYPE_STRING
00088 } _type;
00089 
00090 typedef struct
00091 {
00092     uint16_t    ids[4];
00093     _type       type;
00094     uint8_t *   value;
00095     size_t      valueLen;
00096 } _record_t;
00097 
00098 static int prv_isReserved(char sign)
00099 {
00100     if (sign == '['
00101      || sign == '{'
00102      || sign == ']'
00103      || sign == '}'
00104      || sign == ':'
00105      || sign == ','
00106      || sign == '"')
00107     {
00108         return 1;
00109     }
00110 
00111     return 0;
00112 }
00113 
00114 static int prv_isWhiteSpace(uint8_t sign)
00115 {
00116     if (sign == 0x20
00117      || sign == 0x09
00118      || sign == 0x0A
00119      || sign == 0x0D)
00120     {
00121         return 1;
00122     }
00123 
00124     return 0;
00125 }
00126 
00127 static size_t prv_skipSpace(uint8_t * buffer,
00128                             size_t bufferLen)
00129 {
00130     size_t i;
00131 
00132     i = 0;
00133     while ((i < bufferLen)
00134         && prv_isWhiteSpace(buffer[i]))
00135     {
00136         i++;
00137     }
00138 
00139     return i;
00140 }
00141 
00142 static int prv_split(uint8_t * buffer,
00143                      size_t bufferLen,
00144                      int * tokenStartP,
00145                      int * tokenLenP,
00146                      int * valueStartP,
00147                      int * valueLenP)
00148 {
00149     size_t index;
00150     _itemState step;
00151 
00152     index = 0;
00153     step = _STEP_START;
00154 
00155     index = prv_skipSpace(buffer + index, bufferLen - index);
00156     if (index == bufferLen) return -1;
00157 
00158     while ((index < bufferLen)
00159         && (buffer[index] != ','))
00160     {
00161         switch (step)
00162         {
00163         case _STEP_START:
00164             if (buffer[index] != '"') return -1;
00165             *tokenStartP = index+1;
00166             step = _STEP_TOKEN;
00167             break;
00168 
00169         case _STEP_TOKEN:
00170             if (buffer[index] == '"')
00171             {
00172                 *tokenLenP = index - *tokenStartP;
00173                 step = _STEP_ANY_SEPARATOR;
00174             }
00175             break;
00176 
00177         case _STEP_ANY_SEPARATOR:
00178             if (buffer[index] != ':') return -1;
00179             step = _STEP_SEPARATOR;
00180             break;
00181 
00182         case _STEP_SEPARATOR:
00183             if (buffer[index] == '"')
00184             {
00185                 *valueStartP = index;
00186                 step = _STEP_QUOTED_VALUE;
00187             } else if (!prv_isReserved(buffer[index]))
00188             {
00189                 *valueStartP = index;
00190                 step = _STEP_VALUE;
00191             } else
00192             {
00193                 return -1;
00194             }
00195             break;
00196 
00197         case _STEP_QUOTED_VALUE:
00198             if (buffer[index] == '"' && buffer[index-1] != '\\' )
00199             {
00200                 *valueLenP = index - *valueStartP + 1;
00201                 step = _STEP_DONE;
00202             }
00203             break;
00204 
00205         case _STEP_VALUE:
00206             if (prv_isWhiteSpace(buffer[index]))
00207             {
00208                 *valueLenP = index - *valueStartP;
00209                 step = _STEP_DONE;
00210             }
00211             break;
00212 
00213         case _STEP_DONE:
00214         default:
00215             return -1;
00216         }
00217 
00218         index++;
00219         if (step == _STEP_START
00220          || step == _STEP_ANY_SEPARATOR
00221          || step == _STEP_SEPARATOR
00222          || step == _STEP_DONE)
00223         {
00224             index += prv_skipSpace(buffer + index, bufferLen - index);
00225         }
00226     }
00227 
00228     if (step == _STEP_VALUE)
00229     {
00230         *valueLenP = index - *valueStartP;
00231         step = _STEP_DONE;
00232     }
00233 
00234     if (step != _STEP_DONE) return -1;
00235 
00236     return (int)index;
00237 }
00238 
00239 static int prv_countItems(uint8_t * buffer,
00240                           size_t bufferLen)
00241 {
00242     int count;
00243     size_t index;
00244     int in;
00245 
00246     count = 0;
00247     index = 0;
00248     in = 0;
00249 
00250     while (index < bufferLen)
00251     {
00252         if (in == 0)
00253         {
00254             if (buffer[index] != '{') return -1;
00255             in = 1;
00256             _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00257         }
00258         else
00259         {
00260             if (buffer[index] == '{') return -1;
00261             if (buffer[index] == '}')
00262             {
00263                 in = 0;
00264                 count++;
00265                 _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00266                 if (buffer[index] == ']')
00267                 {
00268                     break;
00269                 }
00270                 if (buffer[index] != ',') return -1;
00271                 _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00272             }
00273             else
00274             {
00275                 _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00276             }
00277         }
00278     }
00279     if (in == 1) return -1;
00280 
00281     return count;
00282 
00283 error:
00284     return -1;
00285 }
00286 
00287 static int prv_parseItem(uint8_t * buffer,
00288                          size_t bufferLen,
00289                          _record_t * recordP)
00290 {
00291     size_t index;
00292 
00293     memset(recordP->ids, 0xFF, 4*sizeof(uint16_t));
00294     recordP->type = _TYPE_UNSET;
00295     recordP->value = NULL;
00296     recordP->valueLen = 0;
00297 
00298     index = 0;
00299     do
00300     {
00301         int tokenStart;
00302         int tokenLen;
00303         int valueStart;
00304         int valueLen;
00305         int next;
00306 
00307         next = prv_split(buffer+index, bufferLen-index, &tokenStart, &tokenLen, &valueStart, &valueLen);
00308         if (next < 0) return -1;
00309 
00310         switch (tokenLen)
00311         {
00312         case 1:
00313         {
00314             switch (buffer[index+tokenStart])
00315             {
00316             case 'n':
00317             {
00318                 int i;
00319                 int j;
00320 
00321                 if (recordP->ids[0] != LWM2M_MAX_ID) return -1;
00322 
00323                 // Check for " around URI
00324                 if (valueLen < 3
00325                  || buffer[index+valueStart] != '"'
00326                  || buffer[index+valueStart+valueLen-1] != '"')
00327                 {
00328                     return -1;
00329                 }
00330                 // Ignore starting /
00331                 if (buffer[index + valueStart + 1] == '/')
00332                 {
00333                     if (valueLen < 4)
00334                     {
00335                         return -1;
00336                     }
00337                     valueStart += 1;
00338                     valueLen -= 1;
00339                 }
00340                 i = 0;
00341                 j = 0;
00342                 do {
00343                     uint32_t readId;
00344 
00345                     readId = 0;
00346                     i++;
00347                     while (i < valueLen-1 && buffer[index+valueStart+i] != '/')
00348                     {
00349                         if (buffer[index+valueStart+i] < '0'
00350                          || buffer[index+valueStart+i] > '9')
00351                         {
00352                             return -1;
00353                         }
00354                         readId *= 10;
00355                         readId += buffer[index+valueStart+i] - '0';
00356                         if (readId > LWM2M_MAX_ID) return -1;
00357                         i++;
00358                     }
00359                     recordP->ids[j] = readId;
00360                     j++;
00361                 } while (i < valueLen-1 && j < 4 && buffer[index+valueStart+i] == '/');
00362                 if (i < valueLen-1 ) return -1;
00363             }
00364             break;
00365 
00366             case 'v':
00367                 if (recordP->type != _TYPE_UNSET) return -1;
00368                 recordP->type = _TYPE_FLOAT;
00369                 recordP->value = buffer + index + valueStart;
00370                 recordP->valueLen = valueLen;
00371                 break;
00372 
00373             case 't':
00374                 // TODO: support time
00375                 break;
00376 
00377             default:
00378                 return -1;
00379             }
00380         }
00381         break;
00382 
00383         case 2:
00384         {
00385             // "bv", "ov", or "sv"
00386             if (buffer[index+tokenStart+1] != 'v') return -1;
00387             switch (buffer[index+tokenStart])
00388             {
00389             case 'b':
00390                 if (recordP->type != _TYPE_UNSET) return -1;
00391                 if (0 == lwm2m_strncmp(JSON_TRUE_STRING, (char *)buffer + index + valueStart, valueLen))
00392                 {
00393                     recordP->type = _TYPE_TRUE;
00394                 }
00395                 else if (0 == lwm2m_strncmp(JSON_FALSE_STRING, (char *)buffer + index + valueStart, valueLen))
00396                 {
00397                     recordP->type = _TYPE_FALSE;
00398                 }
00399                 else
00400                 {
00401                     return -1;
00402                 }
00403                 break;
00404 
00405             case 'o':
00406                 if (recordP->type != _TYPE_UNSET) return -1;
00407                 // TODO: support object link
00408                 break;
00409 
00410             case 's':
00411                 if (recordP->type != _TYPE_UNSET) return -1;
00412                 // Check for " around value
00413                 if (valueLen < 2
00414                  || buffer[index+valueStart] != '"'
00415                  || buffer[index+valueStart+valueLen-1] != '"')
00416                 {
00417                     return -1;
00418                 }
00419                 recordP->type = _TYPE_STRING;
00420                 recordP->value = buffer + index + valueStart + 1;
00421                 recordP->valueLen = valueLen - 2;
00422                 break;
00423 
00424             default:
00425                 return -1;
00426             }
00427         }
00428         break;
00429 
00430         default:
00431             return -1;
00432         }
00433 
00434         index += next + 1;
00435     } while (index < bufferLen);
00436 
00437     return 0;
00438 }
00439 
00440 static bool prv_convertValue(_record_t * recordP,
00441                              lwm2m_data_t * targetP)
00442 {
00443     switch (recordP->type)
00444     {
00445     case _TYPE_FALSE:
00446         lwm2m_data_encode_bool(false, targetP);
00447         break;
00448     case _TYPE_TRUE:
00449         lwm2m_data_encode_bool(true, targetP);
00450         break;
00451     case _TYPE_FLOAT:
00452     {
00453         size_t i;
00454 
00455         i = 0;
00456         while (i < recordP->valueLen
00457             && recordP->value[i] != '.')
00458         {
00459             i++;
00460         }
00461         if (i == recordP->valueLen)
00462         {
00463             int64_t value;
00464 
00465             if ( 1 != utils_plainTextToInt64(recordP->value,
00466                                              recordP->valueLen,
00467                                              &value))
00468             {
00469                 return false;
00470             }
00471 
00472             lwm2m_data_encode_int(value, targetP);
00473         }
00474         else
00475         {
00476             double value;
00477 
00478             if ( 1 != utils_plainTextToFloat64(recordP->value,
00479                                                recordP->valueLen,
00480                                                &value))
00481             {
00482                 return false;
00483             }
00484 
00485             lwm2m_data_encode_float(value, targetP);
00486         }
00487     }
00488     break;
00489 
00490     case _TYPE_STRING:
00491         lwm2m_data_encode_opaque(recordP->value, recordP->valueLen, targetP);
00492         targetP->type = LWM2M_TYPE_STRING;
00493         break;
00494 
00495     case _TYPE_UNSET:
00496     default:
00497         return false;
00498     }
00499 
00500     return true;
00501 }
00502 
00503 static lwm2m_data_t * prv_findDataItem(lwm2m_data_t * listP,
00504                                        int count,
00505                                        uint16_t id)
00506 {
00507     int i;
00508 
00509     i = 0;
00510     while (i < count)
00511     {
00512         if (listP[i].type != LWM2M_TYPE_UNDEFINED && listP[i].id == id)
00513         {
00514             return listP + i;
00515         }
00516         i++;
00517     }
00518 
00519     return NULL;
00520 }
00521 
00522 static uri_depth_t prv_decreaseLevel(uri_depth_t level)
00523 {
00524     switch(level)
00525     {
00526     case URI_DEPTH_OBJECT:
00527         return URI_DEPTH_OBJECT_INSTANCE;
00528     case URI_DEPTH_OBJECT_INSTANCE:
00529         return URI_DEPTH_RESOURCE;
00530     case URI_DEPTH_RESOURCE:
00531         return URI_DEPTH_RESOURCE_INSTANCE;
00532     case URI_DEPTH_RESOURCE_INSTANCE:
00533         return URI_DEPTH_RESOURCE_INSTANCE;
00534     default:
00535         return URI_DEPTH_RESOURCE;
00536     }
00537 }
00538 
00539 static lwm2m_data_t * prv_extendData(lwm2m_data_t * parentP)
00540 {
00541     lwm2m_data_t * newP;
00542 
00543     newP = lwm2m_data_new(parentP->value.asChildren.count + 1);
00544     if (newP == NULL) return NULL;
00545     if (parentP->value.asChildren.array != NULL)
00546     {
00547         memcpy(newP, parentP->value.asChildren.array, parentP->value.asChildren.count * sizeof(lwm2m_data_t));
00548         lwm2m_free(parentP->value.asChildren.array);     // do not use lwm2m_data_free() to keep pointed values
00549     }
00550     parentP->value.asChildren.array = newP;
00551     parentP->value.asChildren.count += 1;
00552 
00553     return newP + parentP->value.asChildren.count - 1;
00554 }
00555 
00556 static int prv_convertRecord(lwm2m_uri_t * uriP,
00557                              _record_t * recordArray,
00558                              int count,
00559                              lwm2m_data_t ** dataP)
00560 {
00561     int index;
00562     int freeIndex;
00563     lwm2m_data_t * rootP;
00564     int size;
00565     uri_depth_t rootLevel;
00566 
00567     if (uriP == NULL)
00568     {
00569         size = count;
00570         *dataP = lwm2m_data_new(count);
00571         if (NULL == *dataP) return -1;
00572         rootLevel = URI_DEPTH_OBJECT;
00573         rootP = *dataP;
00574     }
00575     else
00576     {
00577         lwm2m_data_t * parentP;
00578         size = 1;
00579 
00580         *dataP = lwm2m_data_new(1);
00581         if (NULL == *dataP) return -1;
00582         (*dataP)->type = LWM2M_TYPE_OBJECT;
00583         (*dataP)->id = uriP->objectId;
00584         rootLevel = URI_DEPTH_OBJECT_INSTANCE;
00585         parentP = *dataP;
00586         if (LWM2M_URI_IS_SET_INSTANCE(uriP))
00587         {
00588             parentP->value.asChildren.count = 1;
00589             parentP->value.asChildren.array = lwm2m_data_new(1);
00590             if (NULL == parentP->value.asChildren.array) goto error;
00591             parentP = parentP->value.asChildren.array;
00592             parentP->type = LWM2M_TYPE_OBJECT_INSTANCE;
00593             parentP->id = uriP->instanceId;
00594             rootLevel = URI_DEPTH_RESOURCE;
00595             if (LWM2M_URI_IS_SET_RESOURCE(uriP))
00596             {
00597                 parentP->value.asChildren.count = 1;
00598                 parentP->value.asChildren.array = lwm2m_data_new(1);
00599                 if (NULL == parentP->value.asChildren.array) goto error;
00600                 parentP = parentP->value.asChildren.array;
00601                 parentP->type = LWM2M_TYPE_UNDEFINED;
00602                 parentP->id = uriP->resourceId;
00603                 rootLevel = URI_DEPTH_RESOURCE_INSTANCE;
00604             }
00605         }
00606         parentP->value.asChildren.count = count;
00607         parentP->value.asChildren.array = lwm2m_data_new(count);
00608         if (NULL == parentP->value.asChildren.array) goto error;
00609         rootP = parentP->value.asChildren.array;
00610     }
00611 
00612     freeIndex = 0;
00613     for (index = 0 ; index < count ; index++)
00614     {
00615         lwm2m_data_t * targetP;
00616         int resSegmentIndex;
00617         int i;
00618 
00619         // check URI depth
00620         // resSegmentIndex is set to the resource segment position
00621         switch(rootLevel)
00622         {
00623         case URI_DEPTH_OBJECT:
00624             resSegmentIndex = 2;
00625             break;
00626         case URI_DEPTH_OBJECT_INSTANCE:
00627             resSegmentIndex = 1;
00628             break;
00629         case URI_DEPTH_RESOURCE:
00630             resSegmentIndex = 0;
00631             break;
00632         case URI_DEPTH_RESOURCE_INSTANCE:
00633             resSegmentIndex = -1;
00634             break;
00635         default:
00636             goto error;
00637         }
00638         for (i = 0 ; i <= resSegmentIndex ; i++)
00639         {
00640             if (recordArray[index].ids[i] == LWM2M_MAX_ID) goto error;
00641         }
00642         if (resSegmentIndex < 2)
00643         {
00644             if (recordArray[index].ids[resSegmentIndex + 2] != LWM2M_MAX_ID) goto error;
00645         }
00646 
00647         targetP = prv_findDataItem(rootP, count, recordArray[index].ids[0]);
00648         if (targetP == NULL)
00649         {
00650             targetP = rootP + freeIndex;
00651             freeIndex++;
00652             targetP->id = recordArray[index].ids[0];
00653             targetP->type = utils_depthToDatatype(rootLevel);
00654         }
00655         if (recordArray[index].ids[1] != LWM2M_MAX_ID)
00656         {
00657             lwm2m_data_t * parentP;
00658             uri_depth_t level;
00659 
00660             parentP = targetP;
00661             level = prv_decreaseLevel(rootLevel);
00662             for (i = 1 ; i <= resSegmentIndex ; i++)
00663             {
00664                 targetP = prv_findDataItem(parentP->value.asChildren.array, parentP->value.asChildren.count, recordArray[index].ids[i]);
00665                 if (targetP == NULL)
00666                 {
00667                     targetP = prv_extendData(parentP);
00668                     if (targetP == NULL) goto error;
00669                     targetP->id = recordArray[index].ids[i];
00670                     targetP->type = utils_depthToDatatype(level);
00671                 }
00672                 level = prv_decreaseLevel(level);
00673                 parentP = targetP;
00674             }
00675             if (recordArray[index].ids[resSegmentIndex + 1] != LWM2M_MAX_ID)
00676             {
00677                 targetP->type = LWM2M_TYPE_MULTIPLE_RESOURCE;
00678                 targetP = prv_extendData(targetP);
00679                 if (targetP == NULL) goto error;
00680                 targetP->id = recordArray[index].ids[resSegmentIndex + 1];
00681                 targetP->type = LWM2M_TYPE_UNDEFINED;
00682             }
00683         }
00684 
00685         if (true != prv_convertValue(recordArray + index, targetP)) goto error;
00686     }
00687 
00688     return size;
00689 
00690 error:
00691     lwm2m_data_free(size, *dataP);
00692     *dataP = NULL;
00693 
00694     return -1;
00695 }
00696 
00697 static int prv_dataStrip(int size,
00698                          lwm2m_data_t * dataP,
00699                          lwm2m_data_t ** resultP)
00700 {
00701     int i;
00702     int j;
00703     int realSize;
00704 
00705     realSize = 0;
00706     for (i = 0 ; i < size ; i++)
00707     {
00708         if (dataP[i].type != LWM2M_TYPE_UNDEFINED)
00709         {
00710             realSize++;
00711         }
00712     }
00713 
00714     *resultP = lwm2m_data_new(realSize);
00715     if (*resultP == NULL) return -1;
00716 
00717     j = 0;
00718     for (i = 0 ; i < size ; i++)
00719     {
00720         if (dataP[i].type != LWM2M_TYPE_UNDEFINED)
00721         {
00722             memcpy((*resultP) + j, dataP + i, sizeof(lwm2m_data_t));
00723 
00724             if (dataP[i].type == LWM2M_TYPE_OBJECT
00725              || dataP[i].type == LWM2M_TYPE_OBJECT_INSTANCE
00726              || dataP[i].type == LWM2M_TYPE_MULTIPLE_RESOURCE)
00727             {
00728                 int childLen;
00729 
00730                 childLen = prv_dataStrip(dataP[i].value.asChildren.count, dataP[i].value.asChildren.array, &((*resultP)[j].value.asChildren.array));
00731                 if (childLen <= 0)
00732                 {
00733                     // skip this one
00734                     j--;
00735                 }
00736                 else
00737                 {
00738                     (*resultP)[j].value.asChildren.count = childLen;
00739                 }
00740             }
00741             else
00742             {
00743                 dataP[i].value.asBuffer.buffer = NULL;
00744             }
00745 
00746             j++;
00747         }
00748     }
00749 
00750     return realSize;
00751 }
00752 
00753 int json_parse(lwm2m_uri_t * uriP,
00754                uint8_t * buffer,
00755                size_t bufferLen,
00756                lwm2m_data_t ** dataP)
00757 {
00758     size_t index;
00759     int count = 0;
00760     bool eFound = false;
00761     bool bnFound = false;
00762     bool btFound = false;
00763     int bnStart;
00764     int bnLen;
00765     _record_t * recordArray;
00766     lwm2m_data_t * parsedP;
00767 
00768     LOG_ARG("bufferLen: %d, buffer: \"%s\"", bufferLen, (char *)buffer);
00769     LOG_URI(uriP);
00770     *dataP = NULL;
00771     recordArray = NULL;
00772     parsedP = NULL;
00773 
00774     index = prv_skipSpace(buffer, bufferLen);
00775     if (index == bufferLen) return -1;
00776 
00777     if (buffer[index] != '{') return -1;
00778     do
00779     {
00780         _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00781         if (buffer[index] != '"') goto error;
00782         if (index++ >= bufferLen) goto error;
00783         switch (buffer[index])
00784         {
00785         case 'e':
00786         {
00787             int recordIndex;
00788 
00789             if (bufferLen-index < JSON_MIN_ARRAY_LEN) goto error;
00790             index++;
00791             if (buffer[index] != '"') goto error;
00792             if (eFound == true) goto error;
00793             eFound = true;
00794 
00795             _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00796             if (buffer[index] != ':') goto error;
00797             _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00798             if (buffer[index] != '[') goto error;
00799             _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00800             count = prv_countItems(buffer + index, bufferLen - index);
00801             if (count <= 0) goto error;
00802             recordArray = (_record_t*)lwm2m_malloc(count * sizeof(_record_t));
00803             if (recordArray == NULL) goto error;
00804             // at this point we are sure buffer[index] is '{' and all { and } are matching
00805             recordIndex = 0;
00806             while (recordIndex < count)
00807             {
00808                 int itemLen;
00809 
00810                 if (buffer[index] != '{') goto error;
00811                 itemLen = 0;
00812                 while (buffer[index + itemLen] != '}') itemLen++;
00813                 if (0 != prv_parseItem(buffer + index + 1, itemLen - 1, recordArray + recordIndex))
00814                 {
00815                     goto error;
00816                 }
00817                 recordIndex++;
00818                 index += itemLen;
00819                 _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00820                 switch (buffer[index])
00821                 {
00822                 case ',':
00823                     _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00824                     break;
00825                 case ']':
00826                     if (recordIndex == count) break;
00827                     // else this is an error
00828                 default:
00829                     goto error;
00830                 }
00831             }
00832             if (buffer[index] != ']') goto error;
00833         }
00834         break;
00835 
00836         case 'b':
00837             if (bufferLen-index < JSON_MIN_BX_LEN) goto error;
00838             index++;
00839             switch (buffer[index])
00840             {
00841             case 't':
00842                 index++;
00843                 if (buffer[index] != '"') goto error;
00844                 if (btFound == true) goto error;
00845                 btFound = true;
00846 
00847                 // TODO: handle timed values
00848                 // temp: skip this token
00849                 while(index < bufferLen && buffer[index] != ',' && buffer[index] != '}') index++;
00850                 if (index == bufferLen) goto error;
00851                 index--;
00852                 // end temp
00853                 break;
00854             case 'n':
00855                 {
00856                     int next;
00857                     int tokenStart;
00858                     int tokenLen;
00859                     int itemLen;
00860 
00861                     index++;
00862                     if (buffer[index] != '"') goto error;
00863                     if (bnFound == true) goto error;
00864                     bnFound = true;
00865                     index -= 3;
00866                     itemLen = 0;
00867                     while (buffer[index + itemLen] != '}'
00868                         && buffer[index + itemLen] != ','
00869                         && index + itemLen < bufferLen)
00870                     {
00871                         itemLen++;
00872                     }
00873                     if (index + itemLen == bufferLen) goto error;
00874                     next = prv_split(buffer+index, itemLen, &tokenStart, &tokenLen, &bnStart, &bnLen);
00875                     if (next < 0) goto error;
00876                     bnStart += index;
00877                     index += next - 1;
00878                 }
00879                 break;
00880             default:
00881                 goto error;
00882             }
00883             break;
00884 
00885         default:
00886             goto error;
00887         }
00888 
00889         _GO_TO_NEXT_CHAR(index, buffer, bufferLen);
00890     } while (buffer[index] == ',');
00891 
00892     if (buffer[index] != '}') goto error;
00893 
00894     if (eFound == true)
00895     {
00896         lwm2m_uri_t baseURI;
00897         lwm2m_uri_t * baseUriP;
00898         lwm2m_data_t * resultP;
00899         int size;
00900 
00901         memset(&baseURI, 0, sizeof(lwm2m_uri_t));
00902         if (bnFound == false)
00903         {
00904             baseUriP = uriP;
00905         }
00906         else
00907         {
00908             int res;
00909 
00910             // we ignore the request URI and use the bn one.
00911 
00912             // Check for " around URI
00913             if (bnLen < 3
00914              || buffer[bnStart] != '"'
00915              || buffer[bnStart+bnLen-1] != '"')
00916             {
00917                 goto error;
00918             }
00919             bnStart += 1;
00920             bnLen -= 2;
00921 
00922             if (bnLen == 1)
00923             {
00924                 if (buffer[bnStart] != '/') goto error;
00925                 baseUriP = NULL;
00926             }
00927             else
00928             {
00929                 res = lwm2m_stringToUri((char *)buffer + bnStart, bnLen, &baseURI);
00930                 if (res < 0 || res != bnLen) goto error;
00931                 baseUriP = &baseURI;
00932             }
00933         }
00934 
00935         count = prv_convertRecord(baseUriP, recordArray, count, &parsedP);
00936         lwm2m_free(recordArray);
00937         recordArray = NULL;
00938 
00939         if (count > 0 && uriP != NULL)
00940         {
00941             if (parsedP->type != LWM2M_TYPE_OBJECT || parsedP->id != uriP->objectId) goto error;
00942             if (!LWM2M_URI_IS_SET_INSTANCE(uriP))
00943             {
00944                 size = parsedP->value.asChildren.count;
00945                 resultP = parsedP->value.asChildren.array;
00946             }
00947             else
00948             {
00949                 int i;
00950 
00951                 resultP = NULL;
00952                 // be permissive and allow full object JSON when requesting for a single instance
00953                 for (i = 0 ; i < (int)parsedP->value.asChildren.count && resultP == NULL; i++)
00954                 {
00955                     lwm2m_data_t * targetP;
00956 
00957                     targetP = parsedP->value.asChildren.array + i;
00958                     if (targetP->id == uriP->instanceId)
00959                     {
00960                         resultP = targetP->value.asChildren.array;
00961                         size = targetP->value.asChildren.count;
00962                     }
00963                 }
00964                 if (resultP == NULL) goto error;
00965                 if (LWM2M_URI_IS_SET_RESOURCE(uriP))
00966                 {
00967                     lwm2m_data_t * resP;
00968 
00969                     resP = NULL;
00970                     for (i = 0 ; i < size && resP == NULL; i++)
00971                     {
00972                         lwm2m_data_t * targetP;
00973 
00974                         targetP = resultP + i;
00975                         if (targetP->id == uriP->resourceId)
00976                         {
00977                             if (targetP->type == LWM2M_TYPE_MULTIPLE_RESOURCE)
00978                             {
00979                                 resP = targetP->value.asChildren.array;
00980                                 size = targetP->value.asChildren.count;
00981                             }
00982                             else
00983                             {
00984                                 size = prv_dataStrip(1, targetP, &resP);
00985                                 if (size <= 0) goto error;
00986                                 lwm2m_data_free(count, parsedP);
00987                                 parsedP = NULL;
00988                             }
00989                         }
00990                     }
00991                     if (resP == NULL) goto error;
00992                     resultP = resP;
00993                 }
00994             }
00995         }
00996         else
00997         {
00998             resultP = parsedP;
00999             size = count;
01000         }
01001 
01002         if (parsedP != NULL)
01003         {
01004             lwm2m_data_t * tempP;
01005 
01006             size = prv_dataStrip(size, resultP, &tempP);
01007             if (size <= 0) goto error;
01008             lwm2m_data_free(count, parsedP);
01009             resultP = tempP;
01010         }
01011         count = size;
01012         *dataP = resultP;
01013     }
01014 
01015     LOG_ARG("Parsing successful. count: %d", count);
01016     return count;
01017 
01018 error:
01019     LOG("Parsing failed");
01020     if (parsedP != NULL)
01021     {
01022         lwm2m_data_free(count, parsedP);
01023         parsedP = NULL;
01024     }
01025     if (recordArray != NULL)
01026     {
01027         lwm2m_free(recordArray);
01028     }
01029     return -1;
01030 }
01031 
01032 static int prv_serializeValue(lwm2m_data_t * tlvP,
01033                               uint8_t * buffer,
01034                               size_t bufferLen)
01035 {
01036     int res;
01037     int head;
01038 
01039     switch (tlvP->type)
01040     {
01041     case LWM2M_TYPE_STRING:
01042         if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1;
01043         memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE);
01044         head = JSON_ITEM_STRING_BEGIN_SIZE;
01045 
01046         if (bufferLen - head < tlvP->value.asBuffer.length) return -1;
01047         memcpy(buffer + head, tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length);
01048         head += tlvP->value.asBuffer.length;
01049 
01050         if (bufferLen - head < JSON_ITEM_STRING_END_SIZE) return -1;
01051         memcpy(buffer + head, JSON_ITEM_STRING_END, JSON_ITEM_STRING_END_SIZE);
01052         head += JSON_ITEM_STRING_END_SIZE;
01053 
01054         break;
01055 
01056     case LWM2M_TYPE_INTEGER:
01057     {
01058         int64_t value;
01059 
01060         if (0 == lwm2m_data_decode_int(tlvP, &value)) return -1;
01061 
01062         if (bufferLen < JSON_ITEM_NUM_SIZE) return -1;
01063         memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE);
01064         head = JSON_ITEM_NUM_SIZE;
01065 
01066         res = utils_intToText(value, buffer + head, bufferLen - head);
01067         if (res <= 0) return -1;
01068         head += res;
01069 
01070         if (bufferLen - head < JSON_ITEM_NUM_END_SIZE) return -1;
01071         memcpy(buffer + head, JSON_ITEM_NUM_END, JSON_ITEM_NUM_END_SIZE);
01072         head += JSON_ITEM_NUM_END_SIZE;
01073     }
01074     break;
01075 
01076     case LWM2M_TYPE_FLOAT:
01077     {
01078         double value;
01079 
01080         if (0 == lwm2m_data_decode_float(tlvP, &value)) return -1;
01081 
01082         if (bufferLen < JSON_ITEM_NUM_SIZE) return -1;
01083         memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE);
01084         head = JSON_ITEM_NUM_SIZE;
01085 
01086         res = utils_floatToText(value, buffer + head, bufferLen - head);
01087         if (res <= 0) return -1;
01088         head += res;
01089 
01090         if (bufferLen - head < JSON_ITEM_NUM_END_SIZE) return -1;
01091         memcpy(buffer + head, JSON_ITEM_NUM_END, JSON_ITEM_NUM_END_SIZE);
01092         head += JSON_ITEM_NUM_END_SIZE;
01093     }
01094     break;
01095 
01096     case LWM2M_TYPE_BOOLEAN:
01097     {
01098         bool value;
01099 
01100         if (0 == lwm2m_data_decode_bool(tlvP, &value)) return -1;
01101 
01102         if (value == true)
01103         {
01104             if (bufferLen < JSON_ITEM_BOOL_TRUE_SIZE) return -1;
01105             memcpy(buffer, JSON_ITEM_BOOL_TRUE, JSON_ITEM_BOOL_TRUE_SIZE);
01106             head = JSON_ITEM_BOOL_TRUE_SIZE;
01107         }
01108         else
01109         {
01110             if (bufferLen < JSON_ITEM_BOOL_FALSE_SIZE) return -1;
01111             memcpy(buffer, JSON_ITEM_BOOL_FALSE, JSON_ITEM_BOOL_FALSE_SIZE);
01112             head = JSON_ITEM_BOOL_FALSE_SIZE;
01113         }
01114     }
01115     break;
01116 
01117     case LWM2M_TYPE_OPAQUE:
01118         if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1;
01119         memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE);
01120         head = JSON_ITEM_STRING_BEGIN_SIZE;
01121 
01122         res = utils_base64Encode(tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length, buffer+head, bufferLen - head);
01123         if (res == 0) return -1;
01124         head += res;
01125 
01126         if (bufferLen - head < JSON_ITEM_STRING_END_SIZE) return -1;
01127         memcpy(buffer + head, JSON_ITEM_STRING_END, JSON_ITEM_STRING_END_SIZE);
01128         head += JSON_ITEM_STRING_END_SIZE;
01129         break;
01130 
01131     case LWM2M_TYPE_OBJECT_LINK:
01132         // TODO: implement
01133         return -1;
01134 
01135     default:
01136         return -1;
01137     }
01138 
01139     return head;
01140 }
01141 
01142 int prv_serializeData(lwm2m_data_t * tlvP,
01143                       uint8_t * parentUriStr,
01144                       size_t parentUriLen,
01145                       uint8_t * buffer,
01146                       size_t bufferLen)
01147 {
01148     int head;
01149     int res;
01150 
01151     head = 0;
01152 
01153     switch (tlvP->type)
01154     {
01155     case LWM2M_TYPE_OBJECT:
01156     case LWM2M_TYPE_OBJECT_INSTANCE:
01157     case LWM2M_TYPE_MULTIPLE_RESOURCE:
01158     {
01159         uint8_t uriStr[URI_MAX_STRING_LEN];
01160         size_t uriLen;
01161         size_t index;
01162 
01163         if (parentUriLen > 0)
01164         {
01165             if (URI_MAX_STRING_LEN < parentUriLen) return -1;
01166             memcpy(uriStr, parentUriStr, parentUriLen);
01167             uriLen = parentUriLen;
01168         }
01169         else
01170         {
01171             uriLen = 0;
01172         }
01173         res = utils_intToText(tlvP->id, uriStr + uriLen, URI_MAX_STRING_LEN - uriLen);
01174         if (res <= 0) return -1;
01175         uriLen += res;
01176         uriStr[uriLen] = '/';
01177         uriLen++;
01178 
01179         head = 0;
01180         for (index = 0 ; index < tlvP->value.asChildren.count; index++)
01181         {
01182             res = prv_serializeData(tlvP->value.asChildren.array + index, uriStr, uriLen, buffer + head, bufferLen - head);
01183             if (res < 0) return -1;
01184             head += res;
01185         }
01186     }
01187     break;
01188 
01189     default:
01190         if (bufferLen < JSON_RES_ITEM_URI_SIZE) return -1;
01191         memcpy(buffer, JSON_RES_ITEM_URI, JSON_RES_ITEM_URI_SIZE);
01192         head = JSON_RES_ITEM_URI_SIZE;
01193 
01194         if (parentUriLen > 0)
01195         {
01196             if (bufferLen - head < parentUriLen) return -1;
01197             memcpy(buffer + head, parentUriStr, parentUriLen);
01198             head += parentUriLen;
01199         }
01200 
01201         res = utils_intToText(tlvP->id, buffer + head, bufferLen - head);
01202         if (res <= 0) return -1;
01203         head += res;
01204 
01205         res = prv_serializeValue(tlvP, buffer + head, bufferLen - head);
01206         if (res < 0) return -1;
01207         head += res;
01208         break;
01209     }
01210 
01211     return head;
01212 }
01213 
01214 static int prv_findAndCheckData(lwm2m_uri_t * uriP,
01215                                 uri_depth_t level,
01216                                 size_t size,
01217                                 lwm2m_data_t * tlvP,
01218                                 lwm2m_data_t ** targetP)
01219 {
01220     size_t index;
01221     int result;
01222 
01223     if (size == 0) return 0;
01224 
01225     if (size > 1)
01226     {
01227         if (tlvP[0].type == LWM2M_TYPE_OBJECT || tlvP[0].type == LWM2M_TYPE_OBJECT_INSTANCE)
01228         {
01229             for (index = 0; index < size; index++)
01230             {
01231                 if (tlvP[index].type != tlvP[0].type)
01232                 {
01233                     *targetP = NULL;
01234                     return -1;
01235                 }
01236             }
01237         }
01238         else
01239         {
01240             for (index = 0; index < size; index++)
01241             {
01242                 if (tlvP[index].type == LWM2M_TYPE_OBJECT || tlvP[index].type == LWM2M_TYPE_OBJECT_INSTANCE)
01243                 {
01244                     *targetP = NULL;
01245                     return -1;
01246                 }
01247             }
01248         }
01249     }
01250 
01251     *targetP = NULL;
01252     result = -1;
01253     switch (level)
01254     {
01255     case URI_DEPTH_OBJECT:
01256         if (tlvP[0].type == LWM2M_TYPE_OBJECT)
01257         {
01258             *targetP = tlvP;
01259             result = (int)size;
01260         }
01261         break;
01262 
01263     case URI_DEPTH_OBJECT_INSTANCE:
01264         switch (tlvP[0].type)
01265         {
01266         case LWM2M_TYPE_OBJECT:
01267             for (index = 0; index < size; index++)
01268             {
01269                 if (tlvP[index].id == uriP->objectId)
01270                 {
01271                     return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
01272                 }
01273             }
01274             break;
01275         case LWM2M_TYPE_OBJECT_INSTANCE:
01276             *targetP = tlvP;
01277             result = (int)size;
01278             break;
01279         default:
01280             break;
01281         }
01282         break;
01283 
01284     case URI_DEPTH_RESOURCE:
01285         switch (tlvP[0].type)
01286         {
01287         case LWM2M_TYPE_OBJECT:
01288             for (index = 0; index < size; index++)
01289             {
01290                 if (tlvP[index].id == uriP->objectId)
01291                 {
01292                     return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
01293                 }
01294             }
01295             break;
01296         case LWM2M_TYPE_OBJECT_INSTANCE:
01297             for (index = 0; index < size; index++)
01298             {
01299                 if (tlvP[index].id == uriP->instanceId)
01300                 {
01301                     return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
01302                 }
01303             }
01304             break;
01305         default:
01306             *targetP = tlvP;
01307             result = (int)size;
01308             break;
01309         }
01310         break;
01311 
01312     case URI_DEPTH_RESOURCE_INSTANCE:
01313         switch (tlvP[0].type)
01314         {
01315         case LWM2M_TYPE_OBJECT:
01316             for (index = 0; index < size; index++)
01317             {
01318                 if (tlvP[index].id == uriP->objectId)
01319                 {
01320                     return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
01321                 }
01322             }
01323             break;
01324         case LWM2M_TYPE_OBJECT_INSTANCE:
01325             for (index = 0; index < size; index++)
01326             {
01327                 if (tlvP[index].id == uriP->instanceId)
01328                 {
01329                     return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
01330                 }
01331             }
01332             break;
01333         case LWM2M_TYPE_MULTIPLE_RESOURCE:
01334             for (index = 0; index < size; index++)
01335             {
01336                 if (tlvP[index].id == uriP->resourceId)
01337                 {
01338                     return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
01339                 }
01340             }
01341             break;
01342         default:
01343             *targetP = tlvP;
01344             result = (int)size;
01345             break;
01346         }
01347         break;
01348 
01349     default:
01350         break;
01351     }
01352 
01353     return result;
01354 }
01355 
01356 int json_serialize(lwm2m_uri_t * uriP,
01357                    int size,
01358                    lwm2m_data_t * tlvP,
01359                    uint8_t ** bufferP)
01360 {
01361     int index;
01362     size_t head;
01363     uint8_t bufferJSON[PRV_JSON_BUFFER_SIZE];
01364     uint8_t baseUriStr[URI_MAX_STRING_LEN];
01365     int baseUriLen;
01366     uri_depth_t rootLevel;
01367     int num;
01368     lwm2m_data_t * targetP;
01369 
01370     LOG_ARG("size: %d", size);
01371     LOG_URI(uriP);
01372     if (size != 0 && tlvP == NULL) return -1;
01373 
01374     baseUriLen = uri_toString(uriP, baseUriStr, URI_MAX_STRING_LEN, &rootLevel);
01375     if (baseUriLen < 0) return -1;
01376 
01377     num = prv_findAndCheckData(uriP, rootLevel, size, tlvP, &targetP);
01378     if (num < 0) return -1;
01379 
01380     while (num == 1
01381         && (targetP->type == LWM2M_TYPE_OBJECT
01382          || targetP->type == LWM2M_TYPE_OBJECT_INSTANCE
01383          || targetP->type == LWM2M_TYPE_MULTIPLE_RESOURCE))
01384     {
01385         int res;
01386 
01387         res = utils_intToText(targetP->id, baseUriStr + baseUriLen, URI_MAX_STRING_LEN - baseUriLen);
01388         if (res <= 0) return 0;
01389         baseUriLen += res;
01390         if (baseUriLen >= URI_MAX_STRING_LEN -1) return 0;
01391         num = targetP->value.asChildren.count;
01392         targetP = targetP->value.asChildren.array;
01393         baseUriStr[baseUriLen] = '/';
01394         baseUriLen++;
01395     }
01396 
01397     if (baseUriLen > 0)
01398     {
01399         memcpy(bufferJSON, JSON_BN_HEADER_1, JSON_BN_HEADER_1_SIZE);
01400         head = JSON_BN_HEADER_1_SIZE;
01401         memcpy(bufferJSON + head, baseUriStr, baseUriLen);
01402         head += baseUriLen;
01403         memcpy(bufferJSON + head, JSON_BN_HEADER_2, JSON_BN_HEADER_2_SIZE);
01404         head += JSON_BN_HEADER_2_SIZE;
01405     }
01406     else
01407     {
01408         memcpy(bufferJSON, JSON_HEADER, JSON_HEADER_SIZE);
01409         head = JSON_HEADER_SIZE;
01410     }
01411 
01412     for (index = 0 ; index < num && head < PRV_JSON_BUFFER_SIZE ; index++)
01413     {
01414         int res;
01415 
01416         res = prv_serializeData(targetP + index, NULL, 0, bufferJSON + head, PRV_JSON_BUFFER_SIZE - head);
01417         if (res < 0) return 0;
01418         head += res;
01419     }
01420 
01421     if (head + JSON_FOOTER_SIZE - 1 > PRV_JSON_BUFFER_SIZE) return 0;
01422 
01423     if (num > 0) head = head - 1;
01424 
01425     memcpy(bufferJSON + head, JSON_FOOTER, JSON_FOOTER_SIZE);
01426     head = head + JSON_FOOTER_SIZE;
01427 
01428     *bufferP = (uint8_t *)lwm2m_malloc(head);
01429     if (*bufferP == NULL) return 0;
01430     memcpy(*bufferP, bufferJSON, head);
01431 
01432     return head;
01433 }
01434 
01435 #endif
01436