123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- #include "ParserBase.h"
- nsavi::ParserBase::ParserBase(nsavi::avi_reader *_reader)
- {
- reader = _reader;
- riff_parsed = NOT_READ;
- header_list_parsed = NOT_READ;
- riff_start = 0;
- avi_header = 0;
- stream_list = 0;
- stream_list_size = 0;
- odml_header = 0;
- }
- // reads a chunk and updates parse state variable on error
- static int ReadChunk(nsavi::avi_reader *reader, nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
- {
- int ret = nsavi::read_riff_chunk(reader, chunk, bytes_read);
- if (ret == nsavi::READ_EOF)
- {
- state = nsavi::NOT_FOUND;
- return nsavi::READ_NOT_FOUND;
- }
- else if (ret > nsavi::READ_OK)
- {
- state = nsavi::PARSE_ERROR;
- return ret;
- }
- else if (ret < nsavi::READ_OK)
- { // pass-thru return value from avi_reader
- state = nsavi::PARSE_RESYNC;
- return ret;
- }
- return nsavi::READ_OK;
- }
- int nsavi::ParserBase::GetRIFFType(uint32_t *type)
- {
- if (riff_parsed == PARSE_RESYNC)
- reader->Seek(0); // seek to the beginning if we need to
- if (riff_parsed == NOT_READ)
- {
- uint32_t bytes_read;
- // assume we are at the beginning of the file
- int ret = ReadChunk(reader, &riff_header, riff_parsed, &bytes_read);
- if (ret)
- return ret;
- if (!riff_header.type)
- {
- riff_parsed = PARSE_ERROR;
- return READ_INVALID_DATA;
- }
- riff_start = reader->Tell();
- riff_parsed = PARSED;
- }
- if (riff_parsed == PARSED)
- {
- *type = riff_header.type;
- return READ_OK;
- }
- // we'll only get here if GetRIFFType was called a second time after an initial failure
- return READ_INVALID_CALL;
- }
- // skips a chunk and updates a parser state variable on error
- static int SkipChunk(nsavi::avi_reader *reader, const nsavi::riff_chunk *chunk, nsavi::ParseState &state, uint32_t *bytes_read)
- {
- int ret = nsavi::skip_chunk(reader, chunk, bytes_read);
- if (ret == nsavi::READ_EOF)
- {
- state = nsavi::NOT_FOUND;
- return nsavi::READ_NOT_FOUND;
- }
- else if (ret > nsavi::READ_OK)
- {
- state = nsavi::PARSE_ERROR;
- return ret;
- }
- else if (ret < nsavi::READ_OK)
- { // pass-thru return value from avi_reader
- state = nsavi::PARSE_RESYNC;
- return ret;
- }
- return nsavi::READ_OK;
- }
- static int Read(nsavi::avi_reader *reader, void *buffer, uint32_t size, nsavi::ParseState &state, uint32_t *out_bytes_read)
- {
- uint32_t bytes_read;
- int ret = reader->Read(buffer, size, &bytes_read);
- if (ret > nsavi::READ_OK)
- {
- state = nsavi::PARSE_ERROR;
- return ret;
- }
- else if (ret < nsavi::READ_OK)
- { // pass-thru return value from avi_reader
- state = nsavi::PARSE_RESYNC;
- return ret;
- }
- else if (bytes_read != size)
- {
- state = nsavi::PARSE_ERROR;
- return nsavi::READ_EOF;
- }
- *out_bytes_read = bytes_read;
- return nsavi::READ_OK;
- }
- int nsavi::ParserBase::ParseStreamList(uint32_t chunk_size, STRL *stream, uint32_t *out_bytes_read)
- {
- uint32_t bytes_available = chunk_size;
- uint32_t stream_number = 0;
- while (bytes_available)
- {
- if (bytes_available < 8)
- {
- header_list_parsed = PARSE_ERROR;
- return READ_INVALID_DATA;
- }
- uint32_t bytes_read;
- riff_chunk chunk;
- int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available -= bytes_read;
- if (bytes_available < chunk.size)
- {
- header_list_parsed = PARSE_ERROR;
- return READ_INVALID_DATA;
- }
- switch(chunk.id)
- {
- case 'hrts': // strh
- free(stream->stream_header);
- stream->stream_header = (nsavi::STRH *)malloc(chunk.size + sizeof(uint32_t));
- if (stream->stream_header)
- {
- ret = Read(reader, ((uint8_t *)stream->stream_header) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available-=bytes_read;
- stream->stream_header->size_bytes = chunk.size;
- if ((chunk.size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- }
- else
- {
- return READ_OUT_OF_MEMORY;
- }
- break;
- case 'frts': // strf
- free(stream->stream_format);
- stream->stream_format = (nsavi::STRF *)malloc(chunk.size + sizeof(uint32_t));
- if (stream->stream_format)
- {
- ret = Read(reader, ((uint8_t *)stream->stream_format) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available-=bytes_read;
- stream->stream_format->size_bytes = chunk.size;
- if ((chunk.size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- }
- else
- {
- return READ_OUT_OF_MEMORY;
- }
- break;
- case 'drts': // strd
- free(stream->stream_data);
- stream->stream_data = (nsavi::STRD *)malloc(chunk.size + sizeof(uint32_t));
- if (stream->stream_data)
- {
- ret = Read(reader, ((uint8_t *)stream->stream_data) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available-=bytes_read;
- stream->stream_data->size_bytes = chunk.size;
- if ((chunk.size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- }
- else
- {
- return READ_OUT_OF_MEMORY;
- }
- break;
- case 'nrts': // strn
- free(stream->stream_name);
- stream->stream_name = (nsavi::STRN *)malloc(chunk.size + sizeof(uint32_t));
- if (stream->stream_name)
- {
- ret = Read(reader, ((uint8_t *)stream->stream_name) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available-=bytes_read;
- stream->stream_name->size_bytes = chunk.size;
- if ((chunk.size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- }
- else
- {
- return READ_OUT_OF_MEMORY;
- }
- break;
- case 'xdni': // indx
- free(stream->stream_index);
- stream->stream_index = (nsavi::INDX *)malloc(chunk.size + sizeof(uint32_t));
- if (stream->stream_index)
- {
- ret = Read(reader, &stream->stream_index->entry_size, chunk.size, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available-=bytes_read;
- stream->stream_index->size_bytes = chunk.size;
- if ((chunk.size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- }
- else
- {
- return READ_OUT_OF_MEMORY;
- }
- break;
- case nsaviFOURCC('v','p','r','p'):
- free(stream->video_properties);
- stream->video_properties = (nsavi::VPRP *)malloc(chunk.size + sizeof(uint32_t));
- if (stream->video_properties)
- {
- ret = Read(reader, &stream->video_properties->video_format_token, chunk.size, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available-=bytes_read;
- stream->video_properties->size_bytes = chunk.size;
- if ((chunk.size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- }
- else
- {
- return READ_OUT_OF_MEMORY;
- }
- break;
- default:
- ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available -= bytes_read;
- break;
- }
- }
- if ((chunk_size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- *out_bytes_read = chunk_size - bytes_available;
- // TODO: see what we managed to collect and return an error code accordingly
- return READ_OK;
- }
- int nsavi::ParserBase::ParseODML(uint32_t chunk_size, uint32_t *out_bytes_read)
- {
- uint32_t bytes_available = chunk_size;
- uint32_t stream_number = 0;
- while (bytes_available)
- {
- if (bytes_available < 8)
- {
- header_list_parsed = PARSE_ERROR;
- return READ_INVALID_DATA;
- }
- uint32_t bytes_read;
- riff_chunk chunk;
- int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available -= bytes_read;
- if (bytes_available < chunk.size)
- {
- header_list_parsed = PARSE_ERROR;
- return READ_INVALID_DATA;
- }
- switch(chunk.id)
- {
- case 'hlmd': // dmlh
- free(odml_header);
- odml_header = (nsavi::DMLH *)malloc(chunk.size + sizeof(uint32_t));
- if (odml_header)
- {
- ret = Read(reader, ((uint8_t *)odml_header) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available-=bytes_read;
- odml_header->size_bytes = chunk.size;
- if ((chunk.size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- }
- else
- {
- return READ_OUT_OF_MEMORY;
- }
- break;
- default:
- ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available -= bytes_read;
- break;
- }
- }
- if ((chunk_size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- *out_bytes_read = chunk_size - bytes_available;
- // TODO: see what we managed to collect and return an error code accordingly
- return READ_OK;
- }
- int nsavi::ParserBase::ParseHeaderList(uint32_t chunk_size, uint32_t *out_bytes_read)
- {
- chunk_size = (chunk_size+1) & ~1;
- uint32_t bytes_available = chunk_size;
- uint32_t stream_number = 0;
- while (bytes_available)
- {
- if (bytes_available < 8)
- {
- header_list_parsed = NOT_FOUND;
- return READ_NOT_FOUND;
- }
- uint32_t bytes_read;
- riff_chunk chunk;
- int ret = ReadChunk(reader, &chunk, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available -= bytes_read;
- if (bytes_available < chunk.size)
- {
- header_list_parsed = PARSE_ERROR;
- return READ_INVALID_DATA;
- }
- switch(chunk.id)
- {
- case 'hiva': // avih
- free(avi_header);
- avi_header = (nsavi::AVIH *)malloc(chunk.size + sizeof(uint32_t));
- if (avi_header)
- {
- ret = Read(reader, ((uint8_t *)avi_header) + sizeof(uint32_t), chunk.size, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available-=bytes_read;
- avi_header->size_bytes = chunk.size;
- if ((chunk.size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- if (avi_header->streams && !stream_list)
- {
- // if we fail to allocate, no major worry (maybe avi_header->streams was incorrect and some huge value
- // we'll just dynamically allocate as needed
- stream_list_size = 0;
- if (avi_header->streams < 65536) /* set a reasonable upper bound */
- {
- stream_list = (STRL *)calloc(avi_header->streams, sizeof(STRL));
- if (stream_list)
- {
- stream_list_size = avi_header->streams;
- }
- }
- }
- }
- else
- {
- header_list_parsed = PARSE_ERROR;
- return READ_OUT_OF_MEMORY;
- }
- break;
- case 'TSIL':
- switch(chunk.type)
- {
- case 'lrts':
- {
- if (stream_list_size <= stream_number)
- {
- stream_list = (STRL *)realloc(stream_list, (stream_number+1) * sizeof(STRL));
- if (!stream_list)
- {
- header_list_parsed = PARSE_ERROR;
- return READ_OUT_OF_MEMORY;
- }
- stream_list_size = stream_number+1;
- }
- STRL &stream = stream_list[stream_number];
- memset(&stream, 0, sizeof(STRL));
- ret = ParseStreamList(chunk.size, &stream, &bytes_read);
- if (ret)
- return ret;
- stream_number++;
- bytes_available-=bytes_read;
- if ((chunk.size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- }
- break;
- case 'lmdo':
- ret = ParseODML(chunk.size, &bytes_read);
- if (ret)
- return ret;
- bytes_available -= bytes_read;
- break;
- default:
- ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available -= bytes_read;
- break;
- }
- break;
- default:
- ret = SkipChunk(reader, &chunk, header_list_parsed, &bytes_read);
- if (ret)
- return ret;
- bytes_available -= bytes_read;
- break;
- }
- }
- if ((chunk_size & 1) && bytes_available)
- {
- bytes_available--;
- reader->Skip(1);
- }
- stream_list_size = stream_number;
- *out_bytes_read = chunk_size - bytes_available;
- return READ_OK;
- // TODO: see what we managed to collect and return an error code accordingly
- }
|