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