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