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*******************************************************************************/
42static 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*******************************************************************************/
59static 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*******************************************************************************/
78tNDEF_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*******************************************************************************/
219INT32 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*******************************************************************************/
268UINT32 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*******************************************************************************/
320UINT8 *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*******************************************************************************/
363UINT8 *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*******************************************************************************/
414UINT8 *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*******************************************************************************/
462UINT8 *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*******************************************************************************/
519UINT8 *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*******************************************************************************/
581UINT8 *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*******************************************************************************/
638UINT8 *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*******************************************************************************/
698UINT8 *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*******************************************************************************/
737UINT8 *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*******************************************************************************/
776UINT8 *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*******************************************************************************/
819void 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*******************************************************************************/
835extern 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*******************************************************************************/
931extern 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*******************************************************************************/
1026extern 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*******************************************************************************/
1077tNDEF_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*******************************************************************************/
1161tNDEF_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*******************************************************************************/
1280tNDEF_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*******************************************************************************/
1352tNDEF_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*******************************************************************************/
1450tNDEF_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*******************************************************************************/
1517tNDEF_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