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