1
0

ParserBase.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. #include "ParserBase.h"
  2. nsavi::ParserBase::ParserBase(nsavi::avi_reader *_reader)
  3. {
  4. reader = _reader;
  5. riff_parsed = NOT_READ;
  6. header_list_parsed = NOT_READ;
  7. riff_start = 0;
  8. avi_header = 0;
  9. stream_list = 0;
  10. stream_list_size = 0;
  11. odml_header = 0;
  12. }
  13. // reads a chunk and updates parse state variable on error
  14. static int ReadChunk(nsavi::avi_reader *reader, nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
  15. {
  16. int ret = nsavi::read_riff_chunk(reader, chunk, bytes_read);
  17. if (ret == nsavi::READ_EOF)
  18. {
  19. state = nsavi::NOT_FOUND;
  20. return nsavi::READ_NOT_FOUND;
  21. }
  22. else if (ret > nsavi::READ_OK)
  23. {
  24. state = nsavi::PARSE_ERROR;
  25. return ret;
  26. }
  27. else if (ret < nsavi::READ_OK)
  28. { // pass-thru return value from avi_reader
  29. state = nsavi::PARSE_RESYNC;
  30. return ret;
  31. }
  32. return nsavi::READ_OK;
  33. }
  34. int nsavi::ParserBase::GetRIFFType(uint32_t *type)
  35. {
  36. if (riff_parsed == PARSE_RESYNC)
  37. reader->Seek(0); // seek to the beginning if we need to
  38. if (riff_parsed == NOT_READ)
  39. {
  40. uint32_t bytes_read;
  41. // assume we are at the beginning of the file
  42. int ret = ReadChunk(reader, &riff_header, riff_parsed, &bytes_read);
  43. if (ret)
  44. return ret;
  45. if (!riff_header.type)
  46. {
  47. riff_parsed = PARSE_ERROR;
  48. return READ_INVALID_DATA;
  49. }
  50. riff_start = reader->Tell();
  51. riff_parsed = PARSED;
  52. }
  53. if (riff_parsed == PARSED)
  54. {
  55. *type = riff_header.type;
  56. return READ_OK;
  57. }
  58. // we'll only get here if GetRIFFType was called a second time after an initial failure
  59. return READ_INVALID_CALL;
  60. }
  61. // skips a chunk and updates a parser state variable on error
  62. static int SkipChunk(nsavi::avi_reader *reader, const nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
  63. {
  64. int ret = nsavi::skip_chunk(reader, chunk, bytes_read);
  65. if (ret == nsavi::READ_EOF)
  66. {
  67. state = nsavi::NOT_FOUND;
  68. return nsavi::READ_NOT_FOUND;
  69. }
  70. else if (ret > nsavi::READ_OK)
  71. {
  72. state = nsavi::PARSE_ERROR;
  73. return ret;
  74. }
  75. else if (ret < nsavi::READ_OK)
  76. { // pass-thru return value from avi_reader
  77. state = nsavi::PARSE_RESYNC;
  78. return ret;
  79. }
  80. return nsavi::READ_OK;
  81. }
  82. static int Read(nsavi::avi_reader *reader, void *buffer, uint32_t size, nsavi::ParseState &state, uint32_t *out_bytes_read)
  83. {
  84. uint32_t bytes_read;
  85. int ret = reader->Read(buffer, size, &bytes_read);
  86. if (ret > nsavi::READ_OK)
  87. {
  88. state = nsavi::PARSE_ERROR;
  89. return ret;
  90. }
  91. else if (ret < nsavi::READ_OK)
  92. { // pass-thru return value from avi_reader
  93. state = nsavi::PARSE_RESYNC;
  94. return ret;
  95. }
  96. else if (bytes_read != size)
  97. {
  98. state = nsavi::PARSE_ERROR;
  99. return nsavi::READ_EOF;
  100. }
  101. *out_bytes_read = bytes_read;
  102. return nsavi::READ_OK;
  103. }
  104. int nsavi::ParserBase::ParseStreamList(uint32_t chunk_size, STRL *stream, uint32_t *out_bytes_read)
  105. {
  106. uint32_t bytes_available = chunk_size;
  107. uint32_t stream_number = 0;
  108. while (bytes_available)
  109. {
  110. if (bytes_available < 8)
  111. {
  112. header_list_parsed = PARSE_ERROR;
  113. return READ_INVALID_DATA;
  114. }
  115. uint32_t bytes_read;
  116. riff_chunk chunk;
  117. int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);
  118. if (ret)
  119. return ret;
  120. bytes_available -= bytes_read;
  121. if (bytes_available < chunk.size)
  122. {
  123. header_list_parsed = PARSE_ERROR;
  124. return READ_INVALID_DATA;
  125. }
  126. switch(chunk.id)
  127. {
  128. case 'hrts': // strh
  129. free(stream->stream_header);
  130. stream->stream_header = (nsavi::STRH *)malloc(chunk.size + sizeof(uint32_t));
  131. if (stream->stream_header)
  132. {
  133. ret = Read(reader, ((uint8_t *)stream->stream_header) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
  134. if (ret)
  135. return ret;
  136. bytes_available-=bytes_read;
  137. stream->stream_header->size_bytes = chunk.size;
  138. if ((chunk.size & 1) && bytes_available)
  139. {
  140. bytes_available--;
  141. reader->Skip(1);
  142. }
  143. }
  144. else
  145. {
  146. return READ_OUT_OF_MEMORY;
  147. }
  148. break;
  149. case 'frts': // strf
  150. free(stream->stream_format);
  151. stream->stream_format = (nsavi::STRF *)malloc(chunk.size + sizeof(uint32_t));
  152. if (stream->stream_format)
  153. {
  154. ret = Read(reader, ((uint8_t *)stream->stream_format) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
  155. if (ret)
  156. return ret;
  157. bytes_available-=bytes_read;
  158. stream->stream_format->size_bytes = chunk.size;
  159. if ((chunk.size & 1) && bytes_available)
  160. {
  161. bytes_available--;
  162. reader->Skip(1);
  163. }
  164. }
  165. else
  166. {
  167. return READ_OUT_OF_MEMORY;
  168. }
  169. break;
  170. case 'drts': // strd
  171. free(stream->stream_data);
  172. stream->stream_data = (nsavi::STRD *)malloc(chunk.size + sizeof(uint32_t));
  173. if (stream->stream_data)
  174. {
  175. ret = Read(reader, ((uint8_t *)stream->stream_data) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
  176. if (ret)
  177. return ret;
  178. bytes_available-=bytes_read;
  179. stream->stream_data->size_bytes = chunk.size;
  180. if ((chunk.size & 1) && bytes_available)
  181. {
  182. bytes_available--;
  183. reader->Skip(1);
  184. }
  185. }
  186. else
  187. {
  188. return READ_OUT_OF_MEMORY;
  189. }
  190. break;
  191. case 'nrts': // strn
  192. free(stream->stream_name);
  193. stream->stream_name = (nsavi::STRN *)malloc(chunk.size + sizeof(uint32_t));
  194. if (stream->stream_name)
  195. {
  196. ret = Read(reader, ((uint8_t *)stream->stream_name) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
  197. if (ret)
  198. return ret;
  199. bytes_available-=bytes_read;
  200. stream->stream_name->size_bytes = chunk.size;
  201. if ((chunk.size & 1) && bytes_available)
  202. {
  203. bytes_available--;
  204. reader->Skip(1);
  205. }
  206. }
  207. else
  208. {
  209. return READ_OUT_OF_MEMORY;
  210. }
  211. break;
  212. case 'xdni': // indx
  213. free(stream->stream_index);
  214. stream->stream_index = (nsavi::INDX *)malloc(chunk.size + sizeof(uint32_t));
  215. if (stream->stream_index)
  216. {
  217. ret = Read(reader, &stream->stream_index->entry_size, chunk.size, header_list_parsed, &bytes_read);
  218. if (ret)
  219. return ret;
  220. bytes_available-=bytes_read;
  221. stream->stream_index->size_bytes = chunk.size;
  222. if ((chunk.size & 1) && bytes_available)
  223. {
  224. bytes_available--;
  225. reader->Skip(1);
  226. }
  227. }
  228. else
  229. {
  230. return READ_OUT_OF_MEMORY;
  231. }
  232. break;
  233. case nsaviFOURCC('v','p','r','p'):
  234. free(stream->video_properties);
  235. stream->video_properties = (nsavi::VPRP *)malloc(chunk.size + sizeof(uint32_t));
  236. if (stream->video_properties)
  237. {
  238. ret = Read(reader, &stream->video_properties->video_format_token, chunk.size, header_list_parsed, &bytes_read);
  239. if (ret)
  240. return ret;
  241. bytes_available-=bytes_read;
  242. stream->video_properties->size_bytes = chunk.size;
  243. if ((chunk.size & 1) && bytes_available)
  244. {
  245. bytes_available--;
  246. reader->Skip(1);
  247. }
  248. }
  249. else
  250. {
  251. return READ_OUT_OF_MEMORY;
  252. }
  253. break;
  254. default:
  255. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  256. if (ret)
  257. return ret;
  258. bytes_available -= bytes_read;
  259. break;
  260. }
  261. }
  262. if ((chunk_size & 1) && bytes_available)
  263. {
  264. bytes_available--;
  265. reader->Skip(1);
  266. }
  267. *out_bytes_read = chunk_size - bytes_available;
  268. // TODO: see what we managed to collect and return an error code accordingly
  269. return READ_OK;
  270. }
  271. int nsavi::ParserBase::ParseODML(uint32_t chunk_size, uint32_t *out_bytes_read)
  272. {
  273. uint32_t bytes_available = chunk_size;
  274. uint32_t stream_number = 0;
  275. while (bytes_available)
  276. {
  277. if (bytes_available < 8)
  278. {
  279. header_list_parsed = PARSE_ERROR;
  280. return READ_INVALID_DATA;
  281. }
  282. uint32_t bytes_read;
  283. riff_chunk chunk;
  284. int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);
  285. if (ret)
  286. return ret;
  287. bytes_available -= bytes_read;
  288. if (bytes_available < chunk.size)
  289. {
  290. header_list_parsed = PARSE_ERROR;
  291. return READ_INVALID_DATA;
  292. }
  293. switch(chunk.id)
  294. {
  295. case 'hlmd': // dmlh
  296. free(odml_header);
  297. odml_header = (nsavi::DMLH *)malloc(chunk.size + sizeof(uint32_t));
  298. if (odml_header)
  299. {
  300. ret = Read(reader, ((uint8_t *)odml_header) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
  301. if (ret)
  302. return ret;
  303. bytes_available-=bytes_read;
  304. odml_header->size_bytes = chunk.size;
  305. if ((chunk.size & 1) && bytes_available)
  306. {
  307. bytes_available--;
  308. reader->Skip(1);
  309. }
  310. }
  311. else
  312. {
  313. return READ_OUT_OF_MEMORY;
  314. }
  315. break;
  316. default:
  317. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  318. if (ret)
  319. return ret;
  320. bytes_available -= bytes_read;
  321. break;
  322. }
  323. }
  324. if ((chunk_size & 1) && bytes_available)
  325. {
  326. bytes_available--;
  327. reader->Skip(1);
  328. }
  329. *out_bytes_read = chunk_size - bytes_available;
  330. // TODO: see what we managed to collect and return an error code accordingly
  331. return READ_OK;
  332. }
  333. int nsavi::ParserBase::ParseHeaderList(uint32_t chunk_size, uint32_t *out_bytes_read)
  334. {
  335. chunk_size = (chunk_size+1) & ~1;
  336. uint32_t bytes_available = chunk_size;
  337. uint32_t stream_number = 0;
  338. while (bytes_available)
  339. {
  340. if (bytes_available < 8)
  341. {
  342. header_list_parsed = NOT_FOUND;
  343. return READ_NOT_FOUND;
  344. }
  345. uint32_t bytes_read;
  346. riff_chunk chunk;
  347. int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);
  348. if (ret)
  349. return ret;
  350. bytes_available -= bytes_read;
  351. if (bytes_available < chunk.size)
  352. {
  353. header_list_parsed = PARSE_ERROR;
  354. return READ_INVALID_DATA;
  355. }
  356. switch(chunk.id)
  357. {
  358. case 'hiva': // avih
  359. free(avi_header);
  360. avi_header = (nsavi::AVIH *)malloc(chunk.size + sizeof(uint32_t));
  361. if (avi_header)
  362. {
  363. ret = Read(reader, ((uint8_t *)avi_header) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
  364. if (ret)
  365. return ret;
  366. bytes_available-=bytes_read;
  367. avi_header->size_bytes = chunk.size;
  368. if ((chunk.size & 1) && bytes_available)
  369. {
  370. bytes_available--;
  371. reader->Skip(1);
  372. }
  373. if (avi_header->streams && !stream_list)
  374. {
  375. // if we fail to allocate, no major worry (maybe avi_header->streams was incorrect and some huge value
  376. // we'll just dynamically allocate as needed
  377. stream_list_size = 0;
  378. if (avi_header->streams < 65536) /* set a reasonable upper bound */
  379. {
  380. stream_list = (STRL *)calloc(avi_header->streams, sizeof(STRL));
  381. if (stream_list)
  382. {
  383. stream_list_size = avi_header->streams;
  384. }
  385. }
  386. }
  387. }
  388. else
  389. {
  390. header_list_parsed = PARSE_ERROR;
  391. return READ_OUT_OF_MEMORY;
  392. }
  393. break;
  394. case 'TSIL':
  395. switch(chunk.type)
  396. {
  397. case 'lrts':
  398. {
  399. if (stream_list_size <= stream_number)
  400. {
  401. stream_list = (STRL *)realloc(stream_list, (stream_number+1) * sizeof(STRL));
  402. if (!stream_list)
  403. {
  404. header_list_parsed = PARSE_ERROR;
  405. return READ_OUT_OF_MEMORY;
  406. }
  407. stream_list_size = stream_number+1;
  408. }
  409. STRL &stream = stream_list[stream_number];
  410. memset(&stream, 0, sizeof(STRL));
  411. ret = ParseStreamList(chunk.size, &stream, &bytes_read);
  412. if (ret)
  413. return ret;
  414. stream_number++;
  415. bytes_available-=bytes_read;
  416. if ((chunk.size & 1) && bytes_available)
  417. {
  418. bytes_available--;
  419. reader->Skip(1);
  420. }
  421. }
  422. break;
  423. case 'lmdo':
  424. ret = ParseODML(chunk.size, &bytes_read);
  425. if (ret)
  426. return ret;
  427. bytes_available -= bytes_read;
  428. break;
  429. default:
  430. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  431. if (ret)
  432. return ret;
  433. bytes_available -= bytes_read;
  434. break;
  435. }
  436. break;
  437. default:
  438. ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
  439. if (ret)
  440. return ret;
  441. bytes_available -= bytes_read;
  442. break;
  443. }
  444. }
  445. if ((chunk_size & 1) && bytes_available)
  446. {
  447. bytes_available--;
  448. reader->Skip(1);
  449. }
  450. stream_list_size = stream_number;
  451. *out_bytes_read = chunk_size - bytes_available;
  452. return READ_OK;
  453. // TODO: see what we managed to collect and return an error code accordingly
  454. }