SeekTable.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #include "SeekTable.h"
  2. #include "read.h"
  3. #include "global_elements.h"
  4. #include "vint.h"
  5. #include <stdio.h>
  6. #include <assert.h>
  7. #ifdef WA_VALIDATE
  8. extern uint32_t num_seekhead_elements_found;
  9. extern uint32_t num_seek_elements_found;
  10. #endif
  11. bool nsmkv::SeekTable::GetEntry(uint64_t id, uint64_t *position)
  12. {
  13. return EnumEntry(0, id, position);
  14. }
  15. bool nsmkv::SeekTable::EnumEntry(size_t i, uint64_t id, uint64_t *position)
  16. {
  17. SeekMap::iterator found = seekMap.find(id);
  18. if (found != seekMap.end())
  19. {
  20. SeekEntries *entries = found->second;
  21. if (entries && entries->size() > i)
  22. {
  23. *position = entries->at(i).position;
  24. return true;
  25. }
  26. }
  27. return false;
  28. }
  29. bool nsmkv::SeekTable::EnumEntry(size_t i, uint64_t id, SeekEntry **seek_entry)
  30. {
  31. SeekMap::iterator found = seekMap.find(id);
  32. if (found != seekMap.end())
  33. {
  34. SeekEntries *entries = found->second;
  35. if (entries && entries->size() > i)
  36. {
  37. *seek_entry = &entries->at(i);
  38. return true;
  39. }
  40. }
  41. return false;
  42. }
  43. void nsmkv::SeekTable::AddEntry(nsmkv::SeekEntry &entry, int flags)
  44. {
  45. // check for duplicates
  46. size_t i=0;
  47. SeekEntry *seek_entry;
  48. while (EnumEntry(i++, entry.id, &seek_entry))
  49. {
  50. if (flags & ADDENTRY_SINGLE)
  51. {
  52. if (flags & ADDENTRY_FOUND)
  53. seek_entry->position = entry.position;
  54. return;
  55. }
  56. if (entry.position == seek_entry->position)
  57. {
  58. return;
  59. }
  60. }
  61. SeekEntries *&entries = seekMap[entry.id];
  62. if (!entries)
  63. {
  64. entries = new SeekEntries;
  65. }
  66. entries->push_back(entry);
  67. #ifdef WA_VALIDATE
  68. num_seek_elements_found++;
  69. #endif
  70. }
  71. void nsmkv::SeekTable::Dump()
  72. {
  73. SeekMap::iterator itr;
  74. for (itr=seekMap.begin();itr!=seekMap.end();itr++)
  75. {
  76. SeekEntries *entries = itr->second;
  77. if (entries)
  78. {
  79. SeekEntries::iterator seekItr;
  80. for (seekItr=entries->begin();seekItr!=entries->end();seekItr++)
  81. {
  82. SeekEntry &entry = *seekItr;
  83. printf("Seek Entry -> id=%I64x, position=%I64u\n", entry.id, entry.position);
  84. }
  85. }
  86. }
  87. }
  88. // returns bytes read. 0 means EOF
  89. static uint64_t ReadSeek(nsmkv::MKVReader *reader, uint64_t size, nsmkv::SeekTable &seekTable)
  90. {
  91. uint64_t total_bytes_read=0;
  92. nsmkv::SeekEntry entry;
  93. enum
  94. {
  95. ID_FIELD_PARSED = 0x1,
  96. POSITION_FIELD_PARSED = 0x2,
  97. };
  98. int fields_parsed=0;
  99. while (size)
  100. {
  101. ebml_node node;
  102. uint64_t bytes_read = read_ebml_node(reader, &node);
  103. if (bytes_read == 0)
  104. return 0;
  105. // benski> checking bytes_read and node.size separately prevents possible integer overflow attack
  106. if (bytes_read > size)
  107. return 0;
  108. total_bytes_read+=bytes_read;
  109. size-=bytes_read;
  110. if (node.size > size)
  111. return 0;
  112. total_bytes_read+=node.size;
  113. size-=node.size;
  114. switch(node.id)
  115. {
  116. case mkv_metaseek_seekid:
  117. {
  118. uint8_t binary[9] = {0};
  119. if (!node.size || node.size > 9)
  120. {
  121. #ifdef WA_VALIDATE
  122. printf(" SeekID size invalid, size=%d\n",node.size);
  123. #endif
  124. assert(node.size<9);
  125. return 0;
  126. }
  127. size_t bytes_read;
  128. reader->Read(binary, (size_t)node.size, &bytes_read);
  129. if (bytes_read != (size_t)node.size)
  130. return 0;
  131. #ifdef WA_VALIDATE
  132. printf(" SeekID: %I64x\n", vint_read_ptr_len(node.size-1, binary));
  133. #endif
  134. entry.id = vint_read_ptr_len((uint8_t)node.size-1, binary);
  135. fields_parsed |= ID_FIELD_PARSED;
  136. }
  137. break;
  138. case mkv_metaseek_seekposition:
  139. {
  140. uint64_t val;
  141. if (read_unsigned(reader, node.size, &val) == 0)
  142. return 0;
  143. #ifdef WA_VALIDATE
  144. printf(" SeekPosition: %I64u\n", val);
  145. #endif
  146. entry.position = val;
  147. fields_parsed |= POSITION_FIELD_PARSED;
  148. }
  149. break;
  150. default:
  151. nsmkv::ReadGlobal(reader, node.id, node.size);
  152. }
  153. }
  154. if (fields_parsed == 0x3)
  155. {
  156. //entry.state = nsmkv::NOT_READ;
  157. seekTable.AddEntry(entry);
  158. }
  159. #ifdef WA_VALIDATE
  160. else if (fields_parsed == 0x2)
  161. {
  162. printf(" Seek only contains SeekPosition\n");
  163. } else if (fields_parsed == 0x01)
  164. {
  165. printf(" Seek element only contains SeekID\n");
  166. }
  167. #endif
  168. return total_bytes_read;
  169. }
  170. // returns bytes read. 0 means EOF
  171. uint64_t nsmkv::ReadSeekHead(nsmkv::MKVReader *reader, uint64_t size, nsmkv::SeekTable &seekTable)
  172. {
  173. uint64_t total_bytes_read=0;
  174. #ifdef WA_VALIDATE
  175. num_seekhead_elements_found++;
  176. #endif
  177. while (size)
  178. {
  179. ebml_node node;
  180. uint64_t bytes_read = read_ebml_node(reader, &node);
  181. if (bytes_read == 0)
  182. return 0;
  183. // benski> checking bytes_read and node.size separately prevents possible integer overflow attack
  184. if (bytes_read > size)
  185. return 0;
  186. total_bytes_read+=bytes_read;
  187. size-=bytes_read;
  188. if (node.size > size)
  189. return 0;
  190. total_bytes_read+=node.size;
  191. size-=node.size;
  192. switch(node.id)
  193. {
  194. case mkv_metaseek_seek:
  195. {
  196. #ifdef WA_VALIDATE
  197. printf(" Seek\n");
  198. #endif
  199. ReadSeek(reader, node.size, seekTable);
  200. }
  201. break;
  202. default:
  203. ReadGlobal(reader, node.id, node.size);
  204. }
  205. }
  206. return total_bytes_read;
  207. }