bool WaveReader::LoadRIFFChunk() { char riffHeader[RIFF_INITIAL_SIZE]; const char* p = riffHeader; MOZ_ASSERT(mDecoder->GetResource()->Tell() == 0, "LoadRIFFChunk called when resource in invalid state"); if (!ReadAll(riffHeader, sizeof(riffHeader))) { return false; } static_assert(sizeof(uint32_t) * 3 <= RIFF_INITIAL_SIZE, "Reads would overflow riffHeader buffer."); if (ReadUint32BE(&p) != RIFF_CHUNK_MAGIC) { NS_WARNING("resource data not in RIFF format"); return false; } // Skip over RIFF size field. p += sizeof(uint32_t); if (ReadUint32BE(&p) != WAVE_CHUNK_MAGIC) { NS_WARNING("Expected WAVE chunk"); return false; } return true; }
bool WaveReader::LoadRIFFChunk() { char riffHeader[RIFF_INITIAL_SIZE]; const char* p = riffHeader; NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() == 0, "LoadRIFFChunk called when resource in invalid state"); if (!ReadAll(riffHeader, sizeof(riffHeader))) { return false; } PR_STATIC_ASSERT(sizeof(uint32_t) * 2 <= RIFF_INITIAL_SIZE); if (ReadUint32BE(&p) != RIFF_CHUNK_MAGIC) { NS_WARNING("resource data not in RIFF format"); return false; } // Skip over RIFF size field. p += 4; if (ReadUint32BE(&p) != WAVE_CHUNK_MAGIC) { NS_WARNING("Expected WAVE chunk"); return false; } return true; }
bool WaveReader::GetNextChunk(uint32_t* aChunk, uint32_t* aChunkSize) { NS_ABORT_IF_FALSE(aChunk, "Must have aChunk"); NS_ABORT_IF_FALSE(aChunkSize, "Must have aChunkSize"); NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0, "GetNextChunk called with unaligned resource"); char chunkHeader[CHUNK_HEADER_SIZE]; const char* p = chunkHeader; if (!ReadAll(chunkHeader, sizeof(chunkHeader))) { return false; } PR_STATIC_ASSERT(sizeof(uint32_t) * 2 <= CHUNK_HEADER_SIZE); *aChunk = ReadUint32BE(&p); *aChunkSize = ReadUint32LE(&p); return true; }
bool WaveReader::GetNextChunk(uint32_t* aChunk, uint32_t* aChunkSize) { MOZ_ASSERT(aChunk, "Must have aChunk"); MOZ_ASSERT(aChunkSize, "Must have aChunkSize"); MOZ_ASSERT(mDecoder->GetResource()->Tell() % 2 == 0, "GetNextChunk called with unaligned resource"); char chunkHeader[CHUNK_HEADER_SIZE]; const char* p = chunkHeader; if (!ReadAll(chunkHeader, sizeof(chunkHeader))) { return false; } static_assert(sizeof(uint32_t) * 2 <= CHUNK_HEADER_SIZE, "Reads would overflow chunkHeader buffer."); *aChunk = ReadUint32BE(&p); *aChunkSize = ReadUint32LE(&p); return true; }
bool WaveReader::ScanForwardUntil(uint32_t aWantedChunk, uint32_t* aChunkSize) { NS_ABORT_IF_FALSE(aChunkSize, "Require aChunkSize argument"); *aChunkSize = 0; for (;;) { static const unsigned int CHUNK_HEADER_SIZE = 8; char chunkHeader[CHUNK_HEADER_SIZE]; const char* p = chunkHeader; if (!ReadAll(chunkHeader, sizeof(chunkHeader))) { return false; } PR_STATIC_ASSERT(sizeof(uint32_t) * 2 <= CHUNK_HEADER_SIZE); uint32_t magic = ReadUint32BE(&p); uint32_t chunkSize = ReadUint32LE(&p); if (magic == aWantedChunk) { *aChunkSize = chunkSize; return true; } // RIFF chunks are two-byte aligned, so round up if necessary. chunkSize += chunkSize % 2; static const unsigned int MAX_CHUNK_SIZE = 1 << 16; PR_STATIC_ASSERT(MAX_CHUNK_SIZE < UINT_MAX / sizeof(char)); nsAutoArrayPtr<char> chunk(new char[MAX_CHUNK_SIZE]); while (chunkSize > 0) { uint32_t size = NS_MIN(chunkSize, MAX_CHUNK_SIZE); if (!ReadAll(chunk.get(), size)) { return false; } chunkSize -= size; } } }
bool WaveReader::LoadAllChunks(nsAutoPtr<dom::HTMLMediaElement::MetadataTags> &aTags) { // Chunks are always word (two byte) aligned. MOZ_ASSERT(mDecoder->GetResource()->Tell() % 2 == 0, "LoadAllChunks called with unaligned resource"); bool loadFormatChunk = false; bool findDataOffset = false; for (;;) { static const unsigned int CHUNK_HEADER_SIZE = 8; char chunkHeader[CHUNK_HEADER_SIZE]; const char* p = chunkHeader; if (!ReadAll(chunkHeader, sizeof(chunkHeader))) { return false; } static_assert(sizeof(uint32_t) * 2 <= CHUNK_HEADER_SIZE, "Reads would overflow chunkHeader buffer."); uint32_t magic = ReadUint32BE(&p); uint32_t chunkSize = ReadUint32LE(&p); int64_t chunkStart = GetPosition(); switch (magic) { case FRMT_CHUNK_MAGIC: loadFormatChunk = LoadFormatChunk(chunkSize); if (!loadFormatChunk) { return false; } break; case LIST_CHUNK_MAGIC: if (!aTags) { LoadListChunk(chunkSize, aTags); } break; case DATA_CHUNK_MAGIC: findDataOffset = FindDataOffset(chunkSize); return loadFormatChunk && findDataOffset; default: break; } // RIFF chunks are two-byte aligned, so round up if necessary. chunkSize += chunkSize % 2; // Move forward to next chunk CheckedInt64 forward = CheckedInt64(chunkStart) + chunkSize - GetPosition(); if (!forward.isValid() || forward.value() < 0) { return false; } static const int64_t MAX_CHUNK_SIZE = 1 << 16; static_assert(uint64_t(MAX_CHUNK_SIZE) < UINT_MAX / sizeof(char), "MAX_CHUNK_SIZE too large for enumerator."); nsAutoArrayPtr<char> chunk(new char[MAX_CHUNK_SIZE]); while (forward.value() > 0) { int64_t size = std::min(forward.value(), MAX_CHUNK_SIZE); if (!ReadAll(chunk.get(), size)) { return false; } forward -= size; } } return false; }
bool WaveReader::LoadListChunk(uint32_t aChunkSize, nsAutoPtr<dom::HTMLMediaElement::MetadataTags> &aTags) { // List chunks are always word (two byte) aligned. MOZ_ASSERT(mDecoder->GetResource()->Tell() % 2 == 0, "LoadListChunk called with unaligned resource"); static const unsigned int MAX_CHUNK_SIZE = 1 << 16; static_assert(uint64_t(MAX_CHUNK_SIZE) < UINT_MAX / sizeof(char), "MAX_CHUNK_SIZE too large for enumerator."); if (aChunkSize > MAX_CHUNK_SIZE || aChunkSize < 4) { return false; } nsAutoArrayPtr<char> chunk(new char[aChunkSize]); if (!ReadAll(chunk.get(), aChunkSize)) { return false; } static const uint32_t INFO_LIST_MAGIC = 0x494e464f; const char* p = chunk.get(); if (ReadUint32BE(&p) != INFO_LIST_MAGIC) { return false; } const waveIdToName ID_TO_NAME[] = { { 0x49415254, NS_LITERAL_CSTRING("artist") }, // IART { 0x49434d54, NS_LITERAL_CSTRING("comments") }, // ICMT { 0x49474e52, NS_LITERAL_CSTRING("genre") }, // IGNR { 0x494e414d, NS_LITERAL_CSTRING("name") }, // INAM }; const char* const end = chunk.get() + aChunkSize; aTags = new dom::HTMLMediaElement::MetadataTags; while (p + 8 < end) { uint32_t id = ReadUint32BE(&p); // Uppercase tag id, inspired by GStreamer's Wave parser. id &= 0xDFDFDFDF; uint32_t length = ReadUint32LE(&p); // Subchunk shall not exceed parent chunk. if (uint32_t(end - p) < length) { break; } // Wrap the string, adjusting length to account for optional // null termination in the chunk. nsCString val(p, length); if (length > 0 && val[length - 1] == '\0') { val.SetLength(length - 1); } // Chunks in List::INFO are always word (two byte) aligned. So round up if // necessary. length += length % 2; p += length; if (!IsUTF8(val)) { continue; } for (size_t i = 0; i < mozilla::ArrayLength(ID_TO_NAME); ++i) { if (id == ID_TO_NAME[i].id) { aTags->Put(ID_TO_NAME[i].name, val); break; } } } return true; }