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