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