Home | History | Annotate | Download | only in ndef
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2010-2014 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 
     20 /******************************************************************************
     21  *
     22  *  This file contains source code for some utility functions to help parse
     23  *  and build NFC Data Exchange Format (NDEF) messages
     24  *
     25  ******************************************************************************/
     26 #include <string.h>
     27 #include "ndef_utils.h"
     28 
     29 /*******************************************************************************
     30 **
     31 **              Static Local Functions
     32 **
     33 *******************************************************************************/
     34 
     35 
     36 /*******************************************************************************
     37 **
     38 ** Function         shiftdown
     39 **
     40 ** Description      shift memory down (to make space to insert a record)
     41 **
     42 *******************************************************************************/
     43 static void shiftdown (UINT8 *p_mem, UINT32 len, UINT32 shift_amount)
     44 {
     45     register UINT8 *ps = p_mem + len - 1;
     46     register UINT8 *pd = ps + shift_amount;
     47     register UINT32 xx;
     48 
     49     for (xx = 0; xx < len; xx++)
     50         *pd-- = *ps--;
     51 }
     52 
     53 /*******************************************************************************
     54 **
     55 ** Function         shiftup
     56 **
     57 ** Description      shift memory up (to delete a record)
     58 **
     59 *******************************************************************************/
     60 static void shiftup (UINT8 *p_dest, UINT8 *p_src, UINT32 len)
     61 {
     62     register UINT8 *ps = p_src;
     63     register UINT8 *pd = p_dest;
     64     register UINT32 xx;
     65 
     66     for (xx = 0; xx < len; xx++)
     67         *pd++ = *ps++;
     68 }
     69 
     70 /*******************************************************************************
     71 **
     72 ** Function         NDEF_MsgValidate
     73 **
     74 ** Description      This function validates an NDEF message.
     75 **
     76 ** Returns          TRUE if all OK, or FALSE if the message is invalid.
     77 **
     78 *******************************************************************************/
     79 tNDEF_STATUS NDEF_MsgValidate (UINT8 *p_msg, UINT32 msg_len, BOOLEAN b_allow_chunks)
     80 {
     81     UINT8   *p_rec = p_msg;
     82     UINT8   *p_end = p_msg + msg_len;
     83     UINT8   rec_hdr=0, type_len, id_len;
     84     int     count;
     85     UINT32  payload_len;
     86     BOOLEAN bInChunk = FALSE;
     87 
     88     if ( (p_msg == NULL) || (msg_len < 3) )
     89         return (NDEF_MSG_TOO_SHORT);
     90 
     91     /* The first record must have the MB bit set */
     92     if ((*p_msg & NDEF_MB_MASK) == 0)
     93         return (NDEF_MSG_NO_MSG_BEGIN);
     94 
     95     /* The first record cannot be a chunk */
     96     if ((*p_msg & NDEF_TNF_MASK) == NDEF_TNF_UNCHANGED)
     97         return (NDEF_MSG_UNEXPECTED_CHUNK);
     98 
     99     for (count = 0; p_rec < p_end; count++)
    100     {
    101         /* if less than short record header */
    102         if (p_rec + 3 > p_end)
    103             return (NDEF_MSG_TOO_SHORT);
    104 
    105         rec_hdr = *p_rec++;
    106 
    107         /* The second and all subsequent records must NOT have the MB bit set */
    108         if ( (count > 0) && (rec_hdr & NDEF_MB_MASK) )
    109             return (NDEF_MSG_EXTRA_MSG_BEGIN);
    110 
    111         /* Type field length */
    112         type_len = *p_rec++;
    113 
    114         /* Payload length - can be 1 or 4 bytes */
    115         if (rec_hdr & NDEF_SR_MASK)
    116             payload_len = *p_rec++;
    117         else
    118         {
    119             /* if less than 4 bytes payload length */
    120             if (p_rec + 4 > p_end)
    121                 return (NDEF_MSG_TOO_SHORT);
    122 
    123             BE_STREAM_TO_UINT32 (payload_len, p_rec);
    124         }
    125 
    126         /* ID field Length */
    127         if (rec_hdr & NDEF_IL_MASK)
    128         {
    129             /* if less than 1 byte ID field length */
    130             if (p_rec + 1 > p_end)
    131                 return (NDEF_MSG_TOO_SHORT);
    132 
    133             id_len = *p_rec++;
    134         }
    135         else
    136             id_len = 0;
    137 
    138         /* A chunk must have type "unchanged", and no type or ID fields */
    139         if (rec_hdr & NDEF_CF_MASK)
    140         {
    141             if (!b_allow_chunks)
    142                 return (NDEF_MSG_UNEXPECTED_CHUNK);
    143 
    144             /* Inside a chunk, the type must be unchanged and no type or ID field i sallowed */
    145             if (bInChunk)
    146             {
    147                 if ( (type_len != 0) || (id_len != 0) || ((rec_hdr & NDEF_TNF_MASK) != NDEF_TNF_UNCHANGED) )
    148                     return (NDEF_MSG_INVALID_CHUNK);
    149             }
    150             else
    151             {
    152                 /* First record of a chunk must NOT have type "unchanged" */
    153                 if ((rec_hdr & NDEF_TNF_MASK) == NDEF_TNF_UNCHANGED)
    154                     return (NDEF_MSG_INVALID_CHUNK);
    155 
    156                 bInChunk = TRUE;
    157             }
    158         }
    159         else
    160         {
    161             /* This may be the last guy in a chunk. */
    162             if (bInChunk)
    163             {
    164                 if ( (type_len != 0) || (id_len != 0) || ((rec_hdr & NDEF_TNF_MASK) != NDEF_TNF_UNCHANGED) )
    165                     return (NDEF_MSG_INVALID_CHUNK);
    166 
    167                 bInChunk = FALSE;
    168             }
    169             else
    170             {
    171                 /* If not in a chunk, the record must NOT have type "unchanged" */
    172                 if ((rec_hdr & NDEF_TNF_MASK) == NDEF_TNF_UNCHANGED)
    173                     return (NDEF_MSG_INVALID_CHUNK);
    174             }
    175         }
    176 
    177         /* An empty record must NOT have a type, ID or payload */
    178         if ((rec_hdr & NDEF_TNF_MASK) == NDEF_TNF_EMPTY)
    179         {
    180             if ( (type_len != 0) || (id_len != 0) || (payload_len != 0) )
    181                 return (NDEF_MSG_INVALID_EMPTY_REC);
    182         }
    183 
    184         if ((rec_hdr & NDEF_TNF_MASK) == NDEF_TNF_UNKNOWN)
    185         {
    186             if (type_len != 0)
    187                 return (NDEF_MSG_LENGTH_MISMATCH);
    188         }
    189 
    190         /* Point to next record */
    191         p_rec += (payload_len + type_len + id_len);
    192 
    193         if (rec_hdr & NDEF_ME_MASK)
    194             break;
    195 
    196         rec_hdr = 0;
    197     }
    198 
    199     /* The last record should have the ME bit set */
    200     if ((rec_hdr & NDEF_ME_MASK) == 0)
    201         return (NDEF_MSG_NO_MSG_END);
    202 
    203     /* p_rec should equal p_end if all the length fields were correct */
    204     if (p_rec != p_end)
    205         return (NDEF_MSG_LENGTH_MISMATCH);
    206 
    207     return (NDEF_OK);
    208 }
    209 
    210 /*******************************************************************************
    211 **
    212 ** Function         NDEF_MsgGetNumRecs
    213 **
    214 ** Description      This function gets the number of records in the given NDEF
    215 **                  message.
    216 **
    217 ** Returns          The record count, or 0 if the message is invalid.
    218 **
    219 *******************************************************************************/
    220 INT32 NDEF_MsgGetNumRecs (UINT8 *p_msg)
    221 {
    222     UINT8   *p_rec = p_msg;
    223     UINT8   rec_hdr, type_len, id_len;
    224     int     count;
    225     UINT32  payload_len;
    226 
    227     for (count = 0; ; )
    228     {
    229         count++;
    230 
    231         rec_hdr = *p_rec++;
    232 
    233         if (rec_hdr & NDEF_ME_MASK)
    234             break;
    235 
    236         /* Type field length */
    237         type_len = *p_rec++;
    238 
    239         /* Payload length - can be 1 or 4 bytes */
    240         if (rec_hdr & NDEF_SR_MASK)
    241             payload_len = *p_rec++;
    242         else
    243             BE_STREAM_TO_UINT32 (payload_len, p_rec);
    244 
    245         /* ID field Length */
    246         if (rec_hdr & NDEF_IL_MASK)
    247             id_len = *p_rec++;
    248         else
    249             id_len = 0;
    250 
    251         /* Point to next record */
    252         p_rec += (payload_len + type_len + id_len);
    253     }
    254 
    255     /* Return the number of records found */
    256     return (count);
    257 }
    258 
    259 /*******************************************************************************
    260 **
    261 ** Function         NDEF_MsgGetRecLength
    262 **
    263 ** Description      This function returns length of the current record in the given
    264 **                  NDEF message.
    265 **
    266 ** Returns          Length of record
    267 **
    268 *******************************************************************************/
    269 UINT32 NDEF_MsgGetRecLength (UINT8 *p_cur_rec)
    270 {
    271     UINT8   rec_hdr, type_len, id_len;
    272     UINT32  rec_len = 0;
    273     UINT32  payload_len;
    274 
    275     /* Get the current record's header */
    276     rec_hdr = *p_cur_rec++;
    277     rec_len++;
    278 
    279     /* Type field length */
    280     type_len = *p_cur_rec++;
    281     rec_len++;
    282 
    283     /* Payload length - can be 1 or 4 bytes */
    284     if (rec_hdr & NDEF_SR_MASK)
    285     {
    286         payload_len = *p_cur_rec++;
    287         rec_len++;
    288     }
    289     else
    290     {
    291         BE_STREAM_TO_UINT32 (payload_len, p_cur_rec);
    292         rec_len += 4;
    293     }
    294 
    295     /* ID field Length */
    296     if (rec_hdr & NDEF_IL_MASK)
    297     {
    298         id_len = *p_cur_rec++;
    299         rec_len++;
    300     }
    301     else
    302         id_len = 0;
    303 
    304     /* Total length of record */
    305     rec_len += (payload_len + type_len + id_len);
    306 
    307     return (rec_len);
    308 }
    309 
    310 /*******************************************************************************
    311 **
    312 ** Function         NDEF_MsgGetNextRec
    313 **
    314 ** Description      This function gets a pointer to the next record in the given
    315 **                  NDEF message. If the current record pointer is NULL, a pointer
    316 **                  to the first record is returned.
    317 **
    318 ** Returns          Pointer to the start of the record, or NULL if no more
    319 **
    320 *******************************************************************************/
    321 UINT8 *NDEF_MsgGetNextRec (UINT8 *p_cur_rec)
    322 {
    323     UINT8   rec_hdr, type_len, id_len;
    324     UINT32  payload_len;
    325 
    326     /* Get the current record's header */
    327     rec_hdr = *p_cur_rec++;
    328 
    329     /* If this is the last record, return NULL */
    330     if (rec_hdr & NDEF_ME_MASK)
    331         return (NULL);
    332 
    333     /* Type field length */
    334     type_len = *p_cur_rec++;
    335 
    336     /* Payload length - can be 1 or 4 bytes */
    337     if (rec_hdr & NDEF_SR_MASK)
    338         payload_len = *p_cur_rec++;
    339     else
    340         BE_STREAM_TO_UINT32 (payload_len, p_cur_rec);
    341 
    342     /* ID field Length */
    343     if (rec_hdr & NDEF_IL_MASK)
    344         id_len = *p_cur_rec++;
    345     else
    346         id_len = 0;
    347 
    348     /* Point to next record */
    349     p_cur_rec += (payload_len + type_len + id_len);
    350 
    351     return (p_cur_rec);
    352 }
    353 
    354 /*******************************************************************************
    355 **
    356 ** Function         NDEF_MsgGetRecByIndex
    357 **
    358 ** Description      This function gets a pointer to the record with the given
    359 **                  index (0-based index) in the given NDEF message.
    360 **
    361 ** Returns          Pointer to the start of the record, or NULL
    362 **
    363 *******************************************************************************/
    364 UINT8 *NDEF_MsgGetRecByIndex (UINT8 *p_msg, INT32 index)
    365 {
    366     UINT8   *p_rec = p_msg;
    367     UINT8   rec_hdr, type_len, id_len;
    368     INT32   count;
    369     UINT32  payload_len;
    370 
    371     for (count = 0; ; count++)
    372     {
    373         if (count == index)
    374             return (p_rec);
    375 
    376         rec_hdr = *p_rec++;
    377 
    378         if (rec_hdr & NDEF_ME_MASK)
    379             return (NULL);
    380 
    381         /* Type field length */
    382         type_len = *p_rec++;
    383 
    384         /* Payload length - can be 1 or 4 bytes */
    385         if (rec_hdr & NDEF_SR_MASK)
    386             payload_len = *p_rec++;
    387         else
    388             BE_STREAM_TO_UINT32 (payload_len, p_rec);
    389 
    390         /* ID field Length */
    391         if (rec_hdr & NDEF_IL_MASK)
    392             id_len = *p_rec++;
    393         else
    394             id_len = 0;
    395 
    396         /* Point to next record */
    397         p_rec += (payload_len + type_len + id_len);
    398     }
    399 
    400     /* If here, there is no record of that index */
    401     return (NULL);
    402 }
    403 
    404 
    405 /*******************************************************************************
    406 **
    407 ** Function         NDEF_MsgGetLastRecInMsg
    408 **
    409 ** Description      This function gets a pointer to the last record in the
    410 **                  given NDEF message.
    411 **
    412 ** Returns          Pointer to the start of the last record, or NULL if some problem
    413 **
    414 *******************************************************************************/
    415 UINT8 *NDEF_MsgGetLastRecInMsg (UINT8 *p_msg)
    416 {
    417     UINT8   *p_rec = p_msg;
    418     UINT8   *pRecStart;
    419     UINT8   rec_hdr, type_len, id_len;
    420     UINT32  payload_len;
    421 
    422     for ( ; ; )
    423     {
    424         pRecStart = p_rec;
    425         rec_hdr = *p_rec++;
    426 
    427         if (rec_hdr & NDEF_ME_MASK)
    428             break;
    429 
    430         /* Type field length */
    431         type_len = *p_rec++;
    432 
    433         /* Payload length - can be 1 or 4 bytes */
    434         if (rec_hdr & NDEF_SR_MASK)
    435             payload_len = *p_rec++;
    436         else
    437             BE_STREAM_TO_UINT32 (payload_len, p_rec);
    438 
    439         /* ID field Length */
    440         if (rec_hdr & NDEF_IL_MASK)
    441             id_len = *p_rec++;
    442         else
    443             id_len = 0;
    444 
    445         /* Point to next record */
    446         p_rec += (payload_len + type_len + id_len);
    447     }
    448 
    449     return (pRecStart);
    450 }
    451 
    452 
    453 /*******************************************************************************
    454 **
    455 ** Function         NDEF_MsgGetFirstRecByType
    456 **
    457 ** Description      This function gets a pointer to the first record with the given
    458 **                  record type in the given NDEF message.
    459 **
    460 ** Returns          Pointer to the start of the record, or NULL
    461 **
    462 *******************************************************************************/
    463 UINT8 *NDEF_MsgGetFirstRecByType (UINT8 *p_msg, UINT8 tnf, UINT8 *p_type, UINT8 tlen)
    464 {
    465     UINT8   *p_rec = p_msg;
    466     UINT8   *pRecStart;
    467     UINT8   rec_hdr, type_len, id_len;
    468     UINT32  payload_len;
    469 
    470     for ( ; ; )
    471     {
    472         pRecStart = p_rec;
    473 
    474         rec_hdr = *p_rec++;
    475 
    476         /* Type field length */
    477         type_len = *p_rec++;
    478 
    479         /* Payload length - can be 1 or 4 bytes */
    480         if (rec_hdr & NDEF_SR_MASK)
    481             payload_len = *p_rec++;
    482         else
    483             BE_STREAM_TO_UINT32 (payload_len, p_rec);
    484 
    485         /* ID field Length */
    486         if (rec_hdr & NDEF_IL_MASK)
    487             id_len = *p_rec++;
    488         else
    489             id_len = 0;
    490 
    491         /* At this point, p_rec points to the start of the type field. We need to */
    492         /* compare the type of the type, the length of the type and the data     */
    493         if ( ((rec_hdr & NDEF_TNF_MASK) == tnf)
    494          &&  (type_len == tlen)
    495          &&  (!memcmp (p_rec, p_type, tlen)) )
    496              return (pRecStart);
    497 
    498         /* If this was the last record, return NULL */
    499         if (rec_hdr & NDEF_ME_MASK)
    500             return (NULL);
    501 
    502         /* Point to next record */
    503         p_rec += (payload_len + type_len + id_len);
    504     }
    505 
    506     /* If here, there is no record of that type */
    507     return (NULL);
    508 }
    509 
    510 /*******************************************************************************
    511 **
    512 ** Function         NDEF_MsgGetNextRecByType
    513 **
    514 ** Description      This function gets a pointer to the next record with the given
    515 **                  record type in the given NDEF message.
    516 **
    517 ** Returns          Pointer to the start of the record, or NULL
    518 **
    519 *******************************************************************************/
    520 UINT8 *NDEF_MsgGetNextRecByType (UINT8 *p_cur_rec, UINT8 tnf, UINT8 *p_type, UINT8 tlen)
    521 {
    522     UINT8   *p_rec;
    523     UINT8   *pRecStart;
    524     UINT8   rec_hdr, type_len, id_len;
    525     UINT32  payload_len;
    526 
    527     /* If this is the last record in the message, return NULL */
    528     if ((p_rec = NDEF_MsgGetNextRec (p_cur_rec)) == NULL)
    529         return (NULL);
    530 
    531     for ( ; ; )
    532     {
    533         pRecStart = p_rec;
    534 
    535         rec_hdr = *p_rec++;
    536 
    537         /* Type field length */
    538         type_len = *p_rec++;
    539 
    540         /* Payload length - can be 1 or 4 bytes */
    541         if (rec_hdr & NDEF_SR_MASK)
    542             payload_len = *p_rec++;
    543         else
    544             BE_STREAM_TO_UINT32 (payload_len, p_rec);
    545 
    546         /* ID field Length */
    547         if (rec_hdr & NDEF_IL_MASK)
    548             id_len = *p_rec++;
    549         else
    550             id_len = 0;
    551 
    552         /* At this point, p_rec points to the start of the type field. We need to */
    553         /* compare the type of the type, the length of the type and the data     */
    554         if ( ((rec_hdr & NDEF_TNF_MASK) == tnf)
    555          &&  (type_len == tlen)
    556          &&  (!memcmp (p_rec, p_type, tlen)) )
    557              return (pRecStart);
    558 
    559         /* If this was the last record, return NULL */
    560         if (rec_hdr & NDEF_ME_MASK)
    561             break;
    562 
    563         /* Point to next record */
    564         p_rec += (payload_len + type_len + id_len);
    565     }
    566 
    567     /* If here, there is no record of that type */
    568     return (NULL);
    569 }
    570 
    571 
    572 /*******************************************************************************
    573 **
    574 ** Function         NDEF_MsgGetFirstRecById
    575 **
    576 ** Description      This function gets a pointer to the first record with the given
    577 **                  record id in the given NDEF message.
    578 **
    579 ** Returns          Pointer to the start of the record, or NULL
    580 **
    581 *******************************************************************************/
    582 UINT8 *NDEF_MsgGetFirstRecById (UINT8 *p_msg, UINT8 *p_id, UINT8 ilen)
    583 {
    584     UINT8   *p_rec = p_msg;
    585     UINT8   *pRecStart;
    586     UINT8   rec_hdr, type_len, id_len;
    587     UINT32  payload_len;
    588 
    589     for ( ; ; )
    590     {
    591         pRecStart = p_rec;
    592 
    593         rec_hdr = *p_rec++;
    594 
    595         /* Type field length */
    596         type_len = *p_rec++;
    597 
    598         /* Payload length - can be 1 or 4 bytes */
    599         if (rec_hdr & NDEF_SR_MASK)
    600             payload_len = *p_rec++;
    601         else
    602             BE_STREAM_TO_UINT32 (payload_len, p_rec);
    603 
    604         /* ID field Length */
    605         if (rec_hdr & NDEF_IL_MASK)
    606             id_len = *p_rec++;
    607         else
    608             id_len = 0;
    609 
    610         /* At this point, p_rec points to the start of the type field. Skip it */
    611         p_rec += type_len;
    612 
    613         /* At this point, p_rec points to the start of the ID field. Compare length and data */
    614         if ( (id_len == ilen) && (!memcmp (p_rec, p_id, ilen)) )
    615              return (pRecStart);
    616 
    617         /* If this was the last record, return NULL */
    618         if (rec_hdr & NDEF_ME_MASK)
    619             return (NULL);
    620 
    621         /* Point to next record */
    622         p_rec += (id_len + payload_len);
    623     }
    624 
    625     /* If here, there is no record of that ID */
    626     return (NULL);
    627 }
    628 
    629 /*******************************************************************************
    630 **
    631 ** Function         NDEF_MsgGetNextRecById
    632 **
    633 ** Description      This function gets a pointer to the next record with the given
    634 **                  record id in the given NDEF message.
    635 **
    636 ** Returns          Pointer to the start of the record, or NULL
    637 **
    638 *******************************************************************************/
    639 UINT8 *NDEF_MsgGetNextRecById (UINT8 *p_cur_rec, UINT8 *p_id, UINT8 ilen)
    640 {
    641     UINT8   *p_rec;
    642     UINT8   *pRecStart;
    643     UINT8   rec_hdr, type_len, id_len;
    644     UINT32  payload_len;
    645 
    646     /* If this is the last record in the message, return NULL */
    647     if ((p_rec = NDEF_MsgGetNextRec (p_cur_rec)) == NULL)
    648         return (NULL);
    649 
    650     for ( ; ; )
    651     {
    652         pRecStart = p_rec;
    653 
    654         rec_hdr = *p_rec++;
    655 
    656         /* Type field length */
    657         type_len = *p_rec++;
    658 
    659         /* Payload length - can be 1 or 4 bytes */
    660         if (rec_hdr & NDEF_SR_MASK)
    661             payload_len = *p_rec++;
    662         else
    663             BE_STREAM_TO_UINT32 (payload_len, p_rec);
    664 
    665         /* ID field Length */
    666         if (rec_hdr & NDEF_IL_MASK)
    667             id_len = *p_rec++;
    668         else
    669             id_len = 0;
    670 
    671         /* At this point, p_rec points to the start of the type field. Skip it */
    672         p_rec += type_len;
    673 
    674         /* At this point, p_rec points to the start of the ID field. Compare length and data */
    675         if ( (id_len == ilen) && (!memcmp (p_rec, p_id, ilen)) )
    676              return (pRecStart);
    677 
    678         /* If this was the last record, return NULL */
    679         if (rec_hdr & NDEF_ME_MASK)
    680             break;
    681 
    682         /* Point to next record */
    683         p_rec += (id_len + payload_len);
    684     }
    685 
    686     /* If here, there is no record of that ID */
    687     return (NULL);
    688 }
    689 
    690 /*******************************************************************************
    691 **
    692 ** Function         NDEF_RecGetType
    693 **
    694 ** Description      This function gets a pointer to the record type for the given NDEF record.
    695 **
    696 ** Returns          Pointer to Type (NULL if none). TNF and len are filled in.
    697 **
    698 *******************************************************************************/
    699 UINT8 *NDEF_RecGetType (UINT8 *p_rec, UINT8 *p_tnf, UINT8 *p_type_len)
    700 {
    701     UINT8   rec_hdr, type_len;
    702 
    703     /* First byte is the record header */
    704     rec_hdr = *p_rec++;
    705 
    706     /* Next byte is the type field length */
    707     type_len = *p_rec++;
    708 
    709     /* Skip the payload length */
    710     if (rec_hdr & NDEF_SR_MASK)
    711         p_rec += 1;
    712     else
    713         p_rec += 4;
    714 
    715     /* Skip ID field Length, if present */
    716     if (rec_hdr & NDEF_IL_MASK)
    717         p_rec++;
    718 
    719     /* At this point, p_rec points to the start of the type field.  */
    720     *p_type_len = type_len;
    721     *p_tnf      = rec_hdr & NDEF_TNF_MASK;
    722 
    723     if (type_len == 0)
    724         return (NULL);
    725     else
    726         return (p_rec);
    727 }
    728 
    729 /*******************************************************************************
    730 **
    731 ** Function         NDEF_RecGetId
    732 **
    733 ** Description      This function gets a pointer to the record id for the given NDEF record.
    734 **
    735 ** Returns          Pointer to Id (NULL if none). ID Len is filled in.
    736 **
    737 *******************************************************************************/
    738 UINT8 *NDEF_RecGetId (UINT8 *p_rec, UINT8 *p_id_len)
    739 {
    740     UINT8   rec_hdr, type_len;
    741 
    742     /* First byte is the record header */
    743     rec_hdr = *p_rec++;
    744 
    745     /* Next byte is the type field length */
    746     type_len = *p_rec++;
    747 
    748     /* Skip the payload length */
    749     if (rec_hdr & NDEF_SR_MASK)
    750         p_rec++;
    751     else
    752         p_rec += 4;
    753 
    754     /* ID field Length */
    755     if (rec_hdr & NDEF_IL_MASK)
    756         *p_id_len = *p_rec++;
    757     else
    758         *p_id_len = 0;
    759 
    760     /* p_rec now points to the start of the type field. The ID field follows it */
    761     if (*p_id_len == 0)
    762         return (NULL);
    763     else
    764         return (p_rec + type_len);
    765 }
    766 
    767 
    768 /*******************************************************************************
    769 **
    770 ** Function         NDEF_RecGetPayload
    771 **
    772 ** Description      This function gets a pointer to the payload for the given NDEF record.
    773 **
    774 ** Returns          a pointer to the payload (or NULL none). Payload len filled in.
    775 **
    776 *******************************************************************************/
    777 UINT8 *NDEF_RecGetPayload (UINT8 *p_rec, UINT32 *p_payload_len)
    778 {
    779     UINT8   rec_hdr, type_len, id_len;
    780     UINT32  payload_len;
    781 
    782     /* First byte is the record header */
    783     rec_hdr = *p_rec++;
    784 
    785     /* Next byte is the type field length */
    786     type_len = *p_rec++;
    787 
    788     /* Next is the payload length (1 or 4 bytes) */
    789     if (rec_hdr & NDEF_SR_MASK)
    790         payload_len = *p_rec++;
    791     else
    792         BE_STREAM_TO_UINT32 (payload_len, p_rec);
    793 
    794     *p_payload_len = payload_len;
    795 
    796     /* ID field Length */
    797     if (rec_hdr & NDEF_IL_MASK)
    798         id_len = *p_rec++;
    799     else
    800         id_len = 0;
    801 
    802     /* p_rec now points to the start of the type field. The ID field follows it, then the payload */
    803     if (payload_len == 0)
    804         return (NULL);
    805     else
    806         return (p_rec + type_len + id_len);
    807 }
    808 
    809 
    810 /*******************************************************************************
    811 **
    812 ** Function         NDEF_MsgInit
    813 **
    814 ** Description      This function initializes an NDEF message.
    815 **
    816 ** Returns          void
    817 **                  *p_cur_size is initialized to 0
    818 **
    819 *******************************************************************************/
    820 void NDEF_MsgInit (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size)
    821 {
    822     *p_cur_size = 0;
    823     memset (p_msg, 0, max_size);
    824 }
    825 
    826 /*******************************************************************************
    827 **
    828 ** Function         NDEF_MsgAddRec
    829 **
    830 ** Description      This function adds an NDEF record to the end of an NDEF message.
    831 **
    832 ** Returns          OK, or error if the record did not fit
    833 **                  *p_cur_size is updated
    834 **
    835 *******************************************************************************/
    836 extern tNDEF_STATUS  NDEF_MsgAddRec (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
    837                                      UINT8 tnf, UINT8 *p_type, UINT8 type_len,
    838                                      UINT8 *p_id, UINT8  id_len,
    839                                      UINT8 *p_payload, UINT32 payload_len)
    840 {
    841     UINT8   *p_rec = p_msg + *p_cur_size;
    842     UINT32  recSize;
    843     int     plen = (payload_len < 256) ? 1 : 4;
    844     int     ilen = (id_len == 0) ? 0 : 1;
    845 
    846     if (tnf > NDEF_TNF_RESERVED)
    847     {
    848         tnf = NDEF_TNF_UNKNOWN;
    849         type_len  = 0;
    850     }
    851 
    852     /* First, make sure the record will fit. we need at least 2 bytes for header and type length */
    853     recSize = payload_len + 2 + type_len + plen + ilen + id_len;
    854 
    855     if ((*p_cur_size + recSize) > max_size)
    856         return (NDEF_MSG_INSUFFICIENT_MEM);
    857 
    858     /* Construct the record header. For the first record, set both begin and end bits */
    859     if (*p_cur_size == 0)
    860         *p_rec = tnf | NDEF_MB_MASK | NDEF_ME_MASK;
    861     else
    862     {
    863         /* Find the previous last and clear his 'Message End' bit */
    864         UINT8  *pLast = NDEF_MsgGetLastRecInMsg (p_msg);
    865 
    866         if (!pLast)
    867             return (NDEF_MSG_NO_MSG_END);
    868 
    869         *pLast &= ~NDEF_ME_MASK;
    870         *p_rec   = tnf | NDEF_ME_MASK;
    871     }
    872 
    873     if (plen == 1)
    874         *p_rec |= NDEF_SR_MASK;
    875 
    876     if (ilen != 0)
    877         *p_rec |= NDEF_IL_MASK;
    878 
    879     p_rec++;
    880 
    881     /* The next byte is the type field length */
    882     *p_rec++ = type_len;
    883 
    884     /* Payload length - can be 1 or 4 bytes */
    885     if (plen == 1)
    886         *p_rec++ = (UINT8)payload_len;
    887     else
    888          UINT32_TO_BE_STREAM (p_rec, payload_len);
    889 
    890     /* ID field Length (optional) */
    891     if (ilen > 0)
    892         *p_rec++ = id_len;
    893 
    894     /* Next comes the type */
    895     if (type_len)
    896     {
    897         if (p_type)
    898             memcpy (p_rec, p_type, type_len);
    899 
    900         p_rec += type_len;
    901     }
    902 
    903     /* Next comes the ID */
    904     if (id_len)
    905     {
    906         if (p_id)
    907             memcpy (p_rec, p_id, id_len);
    908 
    909         p_rec += id_len;
    910     }
    911 
    912     /* And lastly the payload. If NULL, the app just wants to reserve memory */
    913     if (p_payload)
    914         memcpy (p_rec, p_payload, payload_len);
    915 
    916     *p_cur_size += recSize;
    917 
    918     return (NDEF_OK);
    919 }
    920 
    921 /*******************************************************************************
    922 **
    923 ** Function         NDEF_MsgInsertRec
    924 **
    925 ** Description      This function inserts a record at a specific index into the
    926 **                  given NDEF message
    927 **
    928 ** Returns          OK, or error if the record did not fit
    929 **                  *p_cur_size is updated
    930 **
    931 *******************************************************************************/
    932 extern tNDEF_STATUS NDEF_MsgInsertRec (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, INT32 index,
    933                                        UINT8 tnf, UINT8 *p_type, UINT8 type_len,
    934                                        UINT8 *p_id, UINT8  id_len,
    935                                        UINT8 *p_payload, UINT32 payload_len)
    936 {
    937     UINT8   *p_rec;
    938     UINT32  recSize;
    939     INT32   plen = (payload_len < 256) ? 1 : 4;
    940     INT32   ilen = (id_len == 0) ? 0 : 1;
    941 
    942     /* First, make sure the record will fit. we need at least 2 bytes for header and type length */
    943     recSize = payload_len + 2 + type_len + plen + ilen + id_len;
    944 
    945     if ((*p_cur_size + recSize) > max_size)
    946         return (NDEF_MSG_INSUFFICIENT_MEM);
    947 
    948     /* See where the new record goes. If at the end, call the 'AddRec' function */
    949     if ( (index >= NDEF_MsgGetNumRecs (p_msg))
    950       || ((p_rec = NDEF_MsgGetRecByIndex(p_msg, index)) == NULL) )
    951     {
    952         return NDEF_MsgAddRec (p_msg, max_size, p_cur_size, tnf, p_type, type_len,
    953                                p_id, id_len, p_payload, payload_len);
    954     }
    955 
    956     /* If we are inserting at the beginning, remove the MB bit from the current first */
    957     if (index == 0)
    958         *p_msg &= ~NDEF_MB_MASK;
    959 
    960     /* Make space for the new record */
    961     shiftdown (p_rec, (UINT32)(*p_cur_size - (p_rec - p_msg)), recSize);
    962 
    963     /* If adding at the beginning, set begin bit */
    964     if (index == 0)
    965         *p_rec = tnf | NDEF_MB_MASK;
    966     else
    967         *p_rec = tnf;
    968 
    969     if (plen == 1)
    970         *p_rec |= NDEF_SR_MASK;
    971 
    972     if (ilen != 0)
    973         *p_rec |= NDEF_IL_MASK;
    974 
    975     p_rec++;
    976 
    977     /* The next byte is the type field length */
    978     *p_rec++ = type_len;
    979 
    980     /* Payload length - can be 1 or 4 bytes */
    981     if (plen == 1)
    982         *p_rec++ = (UINT8)payload_len;
    983     else
    984          UINT32_TO_BE_STREAM (p_rec, payload_len);
    985 
    986     /* ID field Length (optional) */
    987     if (ilen != 0)
    988         *p_rec++ = id_len;
    989 
    990     /* Next comes the type */
    991     if (type_len)
    992     {
    993         if (p_type)
    994             memcpy (p_rec, p_type, type_len);
    995 
    996         p_rec += type_len;
    997     }
    998 
    999     /* Next comes the ID */
   1000     if (ilen != 0)
   1001     {
   1002         if (p_id)
   1003             memcpy (p_rec, p_id, id_len);
   1004 
   1005         p_rec += id_len;
   1006     }
   1007 
   1008     /* And lastly the payload. If NULL, the app just wants to reserve memory */
   1009     if (p_payload)
   1010         memcpy (p_rec, p_payload, payload_len);
   1011 
   1012     *p_cur_size += recSize;
   1013 
   1014     return (NDEF_OK);
   1015 }
   1016 
   1017 /*******************************************************************************
   1018 **
   1019 ** Function         NDEF_MsgAppendRec
   1020 **
   1021 ** Description      This function adds NDEF records to the end of an NDEF message.
   1022 **
   1023 ** Returns          OK, or error if the record did not fit
   1024 **                  *p_cur_size is updated
   1025 **
   1026 *******************************************************************************/
   1027 extern tNDEF_STATUS  NDEF_MsgAppendRec (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
   1028                                         UINT8 *p_new_rec, UINT32 new_rec_len)
   1029 {
   1030     UINT8   *p_rec;
   1031     tNDEF_STATUS    status;
   1032 
   1033     /* First, validate new records */
   1034     if ((status = NDEF_MsgValidate(p_new_rec, new_rec_len, FALSE)) != NDEF_OK)
   1035         return (status);
   1036 
   1037     /* First, make sure the record will fit */
   1038     if ((*p_cur_size + new_rec_len) > max_size)
   1039         return (NDEF_MSG_INSUFFICIENT_MEM);
   1040 
   1041     /* Find where to copy new record */
   1042     if (*p_cur_size == 0)
   1043         p_rec = p_msg;
   1044     else
   1045     {
   1046         /* Find the previous last and clear his 'Message End' bit */
   1047         UINT8  *pLast = NDEF_MsgGetLastRecInMsg (p_msg);
   1048 
   1049         if (!pLast)
   1050             return (NDEF_MSG_NO_MSG_END);
   1051 
   1052         *pLast &= ~NDEF_ME_MASK;
   1053         p_rec   = p_msg + *p_cur_size;
   1054 
   1055         /* clear 'Message Begin' bit of new record */
   1056         *p_new_rec &= ~NDEF_MB_MASK;
   1057     }
   1058 
   1059     /* append new records */
   1060     memcpy (p_rec, p_new_rec, new_rec_len);
   1061 
   1062     *p_cur_size += new_rec_len;
   1063 
   1064     return (NDEF_OK);
   1065 }
   1066 
   1067 /*******************************************************************************
   1068 **
   1069 ** Function         NDEF_MsgAppendPayload
   1070 **
   1071 ** Description      This function appends extra payload to a specific record in the
   1072 **                  given NDEF message
   1073 **
   1074 ** Returns          OK, or error if the extra payload did not fit
   1075 **                  *p_cur_size is updated
   1076 **
   1077 *******************************************************************************/
   1078 tNDEF_STATUS NDEF_MsgAppendPayload (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
   1079                                     UINT8 *p_rec, UINT8 *p_add_pl, UINT32 add_pl_len)
   1080 {
   1081     UINT32      prev_paylen, new_paylen;
   1082     UINT8       *p_prev_pl, *pp;
   1083     UINT8       incr_lenfld = 0;
   1084     UINT8       type_len, id_len;
   1085 
   1086     /* Skip header */
   1087     pp = p_rec + 1;
   1088 
   1089     /* Next byte is the type field length */
   1090     type_len = *pp++;
   1091 
   1092     /* Next is the payload length (1 or 4 bytes) */
   1093     if (*p_rec & NDEF_SR_MASK)
   1094         prev_paylen = *pp++;
   1095     else
   1096         BE_STREAM_TO_UINT32 (prev_paylen, pp);
   1097 
   1098     /* ID field Length */
   1099     if (*p_rec & NDEF_IL_MASK)
   1100         id_len = *pp++;
   1101     else
   1102         id_len = 0;
   1103 
   1104     p_prev_pl = pp + type_len + id_len;
   1105 
   1106     new_paylen = prev_paylen + add_pl_len;
   1107 
   1108     /* Previous payload may be < 256, and this addition may make it larger than 256 */
   1109     /* If that were to happen, the payload length field goes from 1 byte to 4 bytes */
   1110     if ( (prev_paylen < 256) && (new_paylen > 255) )
   1111         incr_lenfld = 3;
   1112 
   1113     /* Check that it all fits */
   1114     if ((*p_cur_size + add_pl_len + incr_lenfld) > max_size)
   1115         return (NDEF_MSG_INSUFFICIENT_MEM);
   1116 
   1117     /* Point to payload length field */
   1118     pp = p_rec + 2;
   1119 
   1120     /* If we need to increase the length field from 1 to 4 bytes, do it first */
   1121     if (incr_lenfld)
   1122     {
   1123         shiftdown (pp + 1, (UINT32)(*p_cur_size - (pp - p_msg) - 1), 3);
   1124         p_prev_pl += 3;
   1125     }
   1126 
   1127     /* Store in the new length */
   1128     if (new_paylen > 255)
   1129     {
   1130         *p_rec &= ~NDEF_SR_MASK;
   1131         UINT32_TO_BE_STREAM (pp, new_paylen);
   1132     }
   1133     else
   1134         *pp = (UINT8)new_paylen;
   1135 
   1136     /* Point to the end of the previous payload */
   1137     pp = p_prev_pl + prev_paylen;
   1138 
   1139     /* If we are not the last record, make space for the extra payload */
   1140     if ((*p_rec & NDEF_ME_MASK) == 0)
   1141         shiftdown (pp, (UINT32)(*p_cur_size - (pp - p_msg)), add_pl_len);
   1142 
   1143     /* Now copy in the additional payload data */
   1144     memcpy (pp, p_add_pl, add_pl_len);
   1145 
   1146     *p_cur_size += add_pl_len + incr_lenfld;
   1147 
   1148     return (NDEF_OK);
   1149 }
   1150 
   1151 /*******************************************************************************
   1152 **
   1153 ** Function         NDEF_MsgReplacePayload
   1154 **
   1155 ** Description      This function replaces the payload of a specific record in the
   1156 **                  given NDEF message
   1157 **
   1158 ** Returns          OK, or error if the new payload did not fit
   1159 **                  *p_cur_size is updated
   1160 **
   1161 *******************************************************************************/
   1162 tNDEF_STATUS NDEF_MsgReplacePayload (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
   1163                                      UINT8 *p_rec, UINT8 *p_new_pl, UINT32 new_pl_len)
   1164 {
   1165     UINT32      prev_paylen;
   1166     UINT8       *p_prev_pl, *pp;
   1167     UINT32      paylen_delta;
   1168     UINT8       type_len, id_len;
   1169 
   1170     /* Skip header */
   1171     pp = p_rec + 1;
   1172 
   1173     /* Next byte is the type field length */
   1174     type_len = *pp++;
   1175 
   1176     /* Next is the payload length (1 or 4 bytes) */
   1177     if (*p_rec & NDEF_SR_MASK)
   1178         prev_paylen = *pp++;
   1179     else
   1180         BE_STREAM_TO_UINT32 (prev_paylen, pp);
   1181 
   1182     /* ID field Length */
   1183     if (*p_rec & NDEF_IL_MASK)
   1184         id_len = *pp++;
   1185     else
   1186         id_len = 0;
   1187 
   1188     p_prev_pl = pp + type_len + id_len;
   1189 
   1190     /* Point to payload length field again */
   1191     pp = p_rec + 2;
   1192 
   1193     if (new_pl_len > prev_paylen)
   1194     {
   1195         /* New payload is larger than the previous */
   1196         paylen_delta = new_pl_len - prev_paylen;
   1197 
   1198         /* If the previous payload length was < 256, and new is > 255 */
   1199         /* the payload length field goes from 1 byte to 4 bytes       */
   1200         if ( (prev_paylen < 256) && (new_pl_len > 255) )
   1201         {
   1202             if ((*p_cur_size + paylen_delta + 3) > max_size)
   1203                 return (NDEF_MSG_INSUFFICIENT_MEM);
   1204 
   1205             shiftdown (pp + 1, (UINT32)(*p_cur_size - (pp - p_msg) - 1), 3);
   1206             p_prev_pl   += 3;
   1207             *p_cur_size += 3;
   1208             *p_rec      &= ~NDEF_SR_MASK;
   1209         }
   1210         else if ((*p_cur_size + paylen_delta) > max_size)
   1211             return (NDEF_MSG_INSUFFICIENT_MEM);
   1212 
   1213         /* Store in the new length */
   1214         if (new_pl_len > 255)
   1215         {
   1216             UINT32_TO_BE_STREAM (pp, new_pl_len);
   1217         }
   1218         else
   1219             *pp = (UINT8)new_pl_len;
   1220 
   1221         /* Point to the end of the previous payload */
   1222         pp = p_prev_pl + prev_paylen;
   1223 
   1224         /* If we are not the last record, make space for the extra payload */
   1225         if ((*p_rec & NDEF_ME_MASK) == 0)
   1226             shiftdown (pp, (UINT32)(*p_cur_size - (pp - p_msg)), paylen_delta);
   1227 
   1228         *p_cur_size += paylen_delta;
   1229     }
   1230     else if (new_pl_len < prev_paylen)
   1231     {
   1232         /* New payload is smaller than the previous */
   1233         paylen_delta = prev_paylen - new_pl_len;
   1234 
   1235         /* If the previous payload was > 256, and new is less than 256 */
   1236         /* the payload length field goes from 4 bytes to 1 byte        */
   1237         if ( (prev_paylen > 255) && (new_pl_len < 256) )
   1238         {
   1239             shiftup (pp + 1, pp + 4, (UINT32)(*p_cur_size - (pp - p_msg) - 3));
   1240             p_prev_pl   -= 3;
   1241             *p_cur_size -= 3;
   1242             *p_rec      |= NDEF_SR_MASK;
   1243         }
   1244 
   1245         /* Store in the new length */
   1246         if (new_pl_len > 255)
   1247         {
   1248             UINT32_TO_BE_STREAM (pp, new_pl_len);
   1249         }
   1250         else
   1251             *pp = (UINT8)new_pl_len;
   1252 
   1253         /* Point to the end of the previous payload */
   1254         pp = p_prev_pl + prev_paylen;
   1255 
   1256         /* If we are not the last record, remove the extra space from the previous payload */
   1257         if ((*p_rec & NDEF_ME_MASK) == 0)
   1258             shiftup (pp - paylen_delta, pp, (UINT32)(*p_cur_size - (pp - p_msg)));
   1259 
   1260         *p_cur_size -= paylen_delta;
   1261     }
   1262 
   1263     /* Now copy in the new payload data */
   1264     if (p_new_pl)
   1265         memcpy (p_prev_pl, p_new_pl, new_pl_len);
   1266 
   1267     return (NDEF_OK);
   1268 }
   1269 
   1270 /*******************************************************************************
   1271 **
   1272 ** Function         NDEF_MsgReplaceType
   1273 **
   1274 ** Description      This function replaces the type field of a specific record in the
   1275 **                  given NDEF message
   1276 **
   1277 ** Returns          OK, or error if the new type field did not fit
   1278 **                  *p_cur_size is updated
   1279 **
   1280 *******************************************************************************/
   1281 tNDEF_STATUS NDEF_MsgReplaceType (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
   1282                                   UINT8 *p_rec, UINT8 *p_new_type, UINT8 new_type_len)
   1283 {
   1284     UINT8       typelen_delta;
   1285     UINT8       *p_prev_type, prev_type_len;
   1286     UINT8       *pp;
   1287 
   1288     /* Skip header */
   1289     pp = p_rec + 1;
   1290 
   1291     /* Next byte is the type field length */
   1292     prev_type_len = *pp++;
   1293 
   1294     /* Skip the payload length */
   1295     if (*p_rec & NDEF_SR_MASK)
   1296         pp += 1;
   1297     else
   1298         pp += 4;
   1299 
   1300     if (*p_rec & NDEF_IL_MASK)
   1301         pp++;
   1302 
   1303     /* Save pointer to the start of the type field */
   1304     p_prev_type = pp;
   1305 
   1306     if (new_type_len > prev_type_len)
   1307     {
   1308         /* New type is larger than the previous */
   1309         typelen_delta = new_type_len - prev_type_len;
   1310 
   1311         if ((*p_cur_size + typelen_delta) > max_size)
   1312             return (NDEF_MSG_INSUFFICIENT_MEM);
   1313 
   1314         /* Point to the end of the previous type, and make space for the extra data */
   1315         pp = p_prev_type + prev_type_len;
   1316         shiftdown (pp, (UINT32)(*p_cur_size - (pp - p_msg)), typelen_delta);
   1317 
   1318         *p_cur_size += typelen_delta;
   1319     }
   1320     else if (new_type_len < prev_type_len)
   1321     {
   1322         /* New type field is smaller than the previous */
   1323         typelen_delta = prev_type_len - new_type_len;
   1324 
   1325         /* Point to the end of the previous type, and shift up to fill the the unused space */
   1326         pp = p_prev_type + prev_type_len;
   1327         shiftup (pp - typelen_delta, pp, (UINT32)(*p_cur_size - (pp - p_msg)));
   1328 
   1329         *p_cur_size -= typelen_delta;
   1330     }
   1331 
   1332     /* Save in new type length */
   1333     p_rec[1] = new_type_len;
   1334 
   1335     /* Now copy in the new type field data */
   1336     if (p_new_type)
   1337         memcpy (p_prev_type, p_new_type, new_type_len);
   1338 
   1339     return (NDEF_OK);
   1340 }
   1341 
   1342 /*******************************************************************************
   1343 **
   1344 ** Function         NDEF_MsgReplaceId
   1345 **
   1346 ** Description      This function replaces the ID field of a specific record in the
   1347 **                  given NDEF message
   1348 **
   1349 ** Returns          OK, or error if the new ID field did not fit
   1350 **                  *p_cur_size is updated
   1351 **
   1352 *******************************************************************************/
   1353 tNDEF_STATUS NDEF_MsgReplaceId (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
   1354                                 UINT8 *p_rec, UINT8 *p_new_id, UINT8 new_id_len)
   1355 {
   1356     UINT8       idlen_delta;
   1357     UINT8       *p_prev_id, *p_idlen_field;
   1358     UINT8       prev_id_len, type_len;
   1359     UINT8       *pp;
   1360 
   1361     /* Skip header */
   1362     pp = p_rec + 1;
   1363 
   1364     /* Next byte is the type field length */
   1365     type_len = *pp++;
   1366 
   1367     /* Skip the payload length */
   1368     if (*p_rec & NDEF_SR_MASK)
   1369         pp += 1;
   1370     else
   1371         pp += 4;
   1372 
   1373     p_idlen_field = pp;
   1374 
   1375     if (*p_rec & NDEF_IL_MASK)
   1376         prev_id_len = *pp++;
   1377     else
   1378         prev_id_len = 0;
   1379 
   1380     /* Save pointer to the start of the ID field (right after the type field) */
   1381     p_prev_id = pp + type_len;
   1382 
   1383     if (new_id_len > prev_id_len)
   1384     {
   1385         /* New ID field is larger than the previous */
   1386         idlen_delta = new_id_len - prev_id_len;
   1387 
   1388         /* If the previous ID length was 0, we need to add a 1-byte ID length */
   1389         if (prev_id_len == 0)
   1390         {
   1391             if ((*p_cur_size + idlen_delta + 1) > max_size)
   1392                 return (NDEF_MSG_INSUFFICIENT_MEM);
   1393 
   1394             shiftdown (p_idlen_field, (UINT32)(*p_cur_size - (p_idlen_field - p_msg)), 1);
   1395             p_prev_id   += 1;
   1396             *p_cur_size += 1;
   1397             *p_rec      |= NDEF_IL_MASK;
   1398         }
   1399         else if ((*p_cur_size + idlen_delta) > max_size)
   1400             return (NDEF_MSG_INSUFFICIENT_MEM);
   1401 
   1402         /* Point to the end of the previous ID field, and make space for the extra data */
   1403         pp = p_prev_id + prev_id_len;
   1404         shiftdown (pp, (UINT32)(*p_cur_size - (pp - p_msg)), idlen_delta);
   1405 
   1406         *p_cur_size += idlen_delta;
   1407     }
   1408     else if (new_id_len < prev_id_len)
   1409     {
   1410         /* New ID field is smaller than the previous */
   1411         idlen_delta = prev_id_len - new_id_len;
   1412 
   1413         /* Point to the end of the previous ID, and shift up to fill the the unused space */
   1414         pp = p_prev_id + prev_id_len;
   1415         shiftup (pp - idlen_delta, pp, (UINT32)(*p_cur_size - (pp - p_msg)));
   1416 
   1417         *p_cur_size -= idlen_delta;
   1418 
   1419         /* If removing the ID, make sure that length field is also removed */
   1420         if (new_id_len == 0)
   1421         {
   1422             shiftup (p_idlen_field, p_idlen_field + 1, (UINT32)(*p_cur_size - (p_idlen_field - p_msg - (UINT32)1)));
   1423             *p_rec      &= ~NDEF_IL_MASK;
   1424             *p_cur_size -= 1;
   1425         }
   1426     }
   1427 
   1428     /* Save in new ID length and data */
   1429     if (new_id_len)
   1430     {
   1431         *p_idlen_field = new_id_len;
   1432 
   1433         if (p_new_id)
   1434             memcpy (p_prev_id, p_new_id, new_id_len);
   1435     }
   1436 
   1437     return (NDEF_OK);
   1438 }
   1439 
   1440 /*******************************************************************************
   1441 **
   1442 ** Function         NDEF_MsgRemoveRec
   1443 **
   1444 ** Description      This function removes the record at the given
   1445 **                  index in the given NDEF message.
   1446 **
   1447 ** Returns          TRUE if OK, FALSE if the index was invalid
   1448 **                  *p_cur_size is updated
   1449 **
   1450 *******************************************************************************/
   1451 tNDEF_STATUS NDEF_MsgRemoveRec (UINT8 *p_msg, UINT32 *p_cur_size, INT32 index)
   1452 {
   1453     UINT8   *p_rec = NDEF_MsgGetRecByIndex (p_msg, index);
   1454     UINT8   *pNext, *pPrev;
   1455 
   1456     if (!p_rec)
   1457         return (NDEF_REC_NOT_FOUND);
   1458 
   1459     /* If this is the first record in the message... */
   1460     if (*p_rec & NDEF_MB_MASK)
   1461     {
   1462         /* Find the second record (if any) and set his 'Message Begin' bit */
   1463         if ((pNext = NDEF_MsgGetRecByIndex(p_msg, 1)) != NULL)
   1464         {
   1465             *pNext |= NDEF_MB_MASK;
   1466 
   1467             *p_cur_size -= (UINT32)(pNext - p_msg);
   1468 
   1469             shiftup (p_msg, pNext, *p_cur_size);
   1470         }
   1471         else
   1472             *p_cur_size = 0;              /* No more records, lenght must be zero */
   1473 
   1474         return (NDEF_OK);
   1475     }
   1476 
   1477     /* If this is the last record in the message... */
   1478     if (*p_rec & NDEF_ME_MASK)
   1479     {
   1480         if (index > 0)
   1481         {
   1482             /* Find the previous record and set his 'Message End' bit */
   1483             if ((pPrev = NDEF_MsgGetRecByIndex(p_msg, index - 1)) == NULL)
   1484                 return (FALSE);
   1485 
   1486             *pPrev |= NDEF_ME_MASK;
   1487         }
   1488         *p_cur_size = (UINT32)(p_rec - p_msg);
   1489 
   1490         return (NDEF_OK);
   1491     }
   1492 
   1493     /* Not the first or the last... get the address of the next record */
   1494     if ((pNext = NDEF_MsgGetNextRec (p_rec)) == NULL)
   1495         return (FALSE);
   1496 
   1497     /* We are removing p_rec, so shift from pNext to the end */
   1498     shiftup (p_rec, pNext, (UINT32)(*p_cur_size - (pNext - p_msg)));
   1499 
   1500     *p_cur_size -= (UINT32)(pNext - p_rec);
   1501 
   1502     return (NDEF_OK);
   1503 }
   1504 
   1505 
   1506 /*******************************************************************************
   1507 **
   1508 ** Function         NDEF_MsgCopyAndDechunk
   1509 **
   1510 ** Description      This function copies and de-chunks an NDEF message.
   1511 **                  It is assumed that the destination is at least as large
   1512 **                  as the source, since the source may not actually contain
   1513 **                  any chunks.
   1514 **
   1515 ** Returns          The output byte count
   1516 **
   1517 *******************************************************************************/
   1518 tNDEF_STATUS NDEF_MsgCopyAndDechunk (UINT8 *p_src, UINT32 src_len, UINT8 *p_dest, UINT32 *p_out_len)
   1519 {
   1520     UINT32          out_len, max_out_len;
   1521     UINT8           *p_rec;
   1522     UINT8           *p_prev_rec = p_dest;
   1523     UINT8           *p_type, *p_id, *p_pay;
   1524     UINT8           type_len, id_len, tnf;
   1525     UINT32          pay_len;
   1526     tNDEF_STATUS    status;
   1527 
   1528     /* First, validate the source */
   1529     if ((status = NDEF_MsgValidate(p_src, src_len, TRUE)) != NDEF_OK)
   1530         return (status);
   1531 
   1532     /* The output buffer must be at least as large as the input buffer */
   1533     max_out_len = src_len;
   1534 
   1535     /* Initialize output */
   1536     NDEF_MsgInit (p_dest, max_out_len, &out_len);
   1537 
   1538     p_rec = p_src;
   1539 
   1540     /* Now, copy record by record */
   1541     while ((p_rec != NULL) && (status == NDEF_OK))
   1542     {
   1543         p_type = NDEF_RecGetType (p_rec, &tnf, &type_len);
   1544         p_id   = NDEF_RecGetId (p_rec, &id_len);
   1545         p_pay  = NDEF_RecGetPayload (p_rec, &pay_len);
   1546 
   1547         /* If this is the continuation of a chunk, append the payload to the previous */
   1548         if (tnf == NDEF_TNF_UNCHANGED)
   1549         {
   1550             if (p_pay)
   1551             {
   1552                 status = NDEF_MsgAppendPayload (p_dest, max_out_len, &out_len, p_prev_rec, p_pay, pay_len);
   1553             }
   1554         }
   1555         else
   1556         {
   1557             p_prev_rec = p_dest + out_len;
   1558 
   1559             status = NDEF_MsgAddRec (p_dest, max_out_len, &out_len, tnf, p_type, type_len,
   1560                             p_id, id_len, p_pay, pay_len);
   1561         }
   1562 
   1563         p_rec = NDEF_MsgGetNextRec (p_rec);
   1564     }
   1565 
   1566     *p_out_len = out_len;
   1567 
   1568     return (status);
   1569 }
   1570 
   1571