section_buf.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * section and descriptor parser
  3. *
  4. * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include <errno.h>
  21. #include <string.h>
  22. #include "section_buf.h"
  23. #define SECTION_HDR_SIZE 3
  24. #define SECTION_PAD 0xff
  25. int section_buf_init(struct section_buf *section, int max)
  26. {
  27. if (max < SECTION_HDR_SIZE)
  28. return -EINVAL;
  29. memset(section, 0, sizeof(struct section_buf));
  30. section->max = max; /* max size of data */
  31. section->len = SECTION_HDR_SIZE;
  32. section->wait_pdu = 1;
  33. return 0;
  34. }
  35. int section_buf_add(struct section_buf *section, uint8_t* frag, int len, int *section_status)
  36. {
  37. int copy;
  38. int used = 0;
  39. uint8_t *data;
  40. uint8_t *pos = (uint8_t*) section + sizeof(struct section_buf) + section->count;
  41. /* have we finished? */
  42. if (section->header && (section->len == section->count)) {
  43. *section_status = 1;
  44. return 0;
  45. }
  46. /* skip over section padding bytes */
  47. *section_status = 0;
  48. if (section->count == 0) {
  49. while(len && (*frag == SECTION_PAD)) {
  50. frag++;
  51. len--;
  52. used++;
  53. }
  54. if (len == 0)
  55. return used;
  56. }
  57. /* grab the header to get the section length */
  58. if (!section->header) {
  59. /* copy the header frag */
  60. copy = SECTION_HDR_SIZE - section->count;
  61. if (copy > len)
  62. copy = len;
  63. memcpy(pos, frag, copy);
  64. section->count += copy;
  65. pos += copy;
  66. frag += copy;
  67. used += copy;
  68. len -= copy;
  69. /* we need 3 bytes for the section header */
  70. if (section->count != SECTION_HDR_SIZE)
  71. return used;
  72. /* work out the length & check it isn't too big */
  73. data = (uint8_t*) section + sizeof(struct section_buf);
  74. section->len = SECTION_HDR_SIZE + (((data[1] & 0x0f) << 8) | data[2]);
  75. if (section->len > section->max) {
  76. *section_status = -ERANGE;
  77. return len + used;
  78. }
  79. /* update fields */
  80. section->header = 1;
  81. }
  82. /* accumulate frag */
  83. copy = section->len - section->count;
  84. if (copy > len)
  85. copy = len;
  86. memcpy(pos, frag, copy);
  87. section->count += copy;
  88. used += copy;
  89. /* have we finished? */
  90. if (section->header && (section->len == section->count))
  91. *section_status = 1;
  92. /* return number of bytes used */
  93. return used;
  94. }
  95. int section_buf_add_transport_payload(struct section_buf *section,
  96. uint8_t* payload, int len,
  97. int pdu_start, int *section_status)
  98. {
  99. int used = 0;
  100. int tmp;
  101. /* have we finished? */
  102. if (section->header && (section->len == section->count)) {
  103. *section_status = 1;
  104. return 0;
  105. }
  106. /* don't bother if we're waiting for a PDU */
  107. *section_status = 0;
  108. if (section->wait_pdu && (!pdu_start))
  109. return len;
  110. /* if we're at a PDU start, we need extra handling for the extra first
  111. * byte giving the offset to the start of the next section. */
  112. if (pdu_start) {
  113. /* we have received a pdu */
  114. section->wait_pdu = 0;
  115. /* work out the offset to the _next_ payload */
  116. int offset = payload[0];
  117. if ((offset+1) > len) {
  118. section->wait_pdu = 1;
  119. *section_status = -EINVAL;
  120. return len;
  121. }
  122. /* accumulate the end if we need to */
  123. if (section->count != 0) {
  124. /* add the final fragment. */
  125. tmp = section_buf_add(section, payload + 1, offset, section_status);
  126. /* the stream said this was the final fragment
  127. * (PDU START bit) - check that it really was! */
  128. if ((tmp != offset) || section_buf_remaining(section) || (*section_status != 1)) {
  129. *section_status = -ERANGE;
  130. section->wait_pdu = 1;
  131. return 1 + tmp;
  132. }
  133. /* it is complete - return the number of bytes we used */
  134. return 1 + tmp;
  135. }
  136. /* otherwise, we skip the end of the previous section, and
  137. * start accumulating the new data. */
  138. used = 1 + offset;
  139. }
  140. /* ok, just accumulate the data as normal */
  141. tmp = section_buf_add(section, payload+used, len - used, section_status);
  142. if (*section_status < 0) {
  143. section->wait_pdu = 1;
  144. }
  145. return used + tmp;
  146. }