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*******************************************************************************/
43static 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*******************************************************************************/
60static 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*******************************************************************************/
79tNDEF_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*******************************************************************************/
220INT32 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*******************************************************************************/
269UINT32 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*******************************************************************************/
321UINT8 *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*******************************************************************************/
364UINT8 *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*******************************************************************************/
415UINT8 *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*******************************************************************************/
463UINT8 *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*******************************************************************************/
520UINT8 *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*******************************************************************************/
582UINT8 *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*******************************************************************************/
639UINT8 *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*******************************************************************************/
699UINT8 *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*******************************************************************************/
738UINT8 *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*******************************************************************************/
777UINT8 *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*******************************************************************************/
820void 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*******************************************************************************/
836extern 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*******************************************************************************/
932extern 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*******************************************************************************/
1027extern 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*******************************************************************************/
1078tNDEF_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*******************************************************************************/
1162tNDEF_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*******************************************************************************/
1281tNDEF_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*******************************************************************************/
1353tNDEF_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*******************************************************************************/
1451tNDEF_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*******************************************************************************/
1518tNDEF_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