bool WaveReader::FindDataOffset() { // RIFF chunks are always word (two byte) aligned. NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0, "FindDataOffset called with unaligned resource"); // The "data" chunk may not directly follow the "format" chunk, so skip // over any intermediate chunks. uint32_t length; if (!ScanForwardUntil(DATA_CHUNK_MAGIC, &length)) { return false; } int64_t offset = mDecoder->GetResource()->Tell(); if (offset <= 0 || offset > UINT32_MAX) { NS_WARNING("PCM data offset out of range"); return false; } ReentrantMonitorAutoEnter monitor(mDecoder->GetReentrantMonitor()); mWaveLength = length; mWavePCMOffset = uint32_t(offset); return true; }
bool WaveReader::LoadFormatChunk() { uint32_t fmtSize, rate, channels, frameSize, sampleFormat; char waveFormat[WAVE_FORMAT_CHUNK_SIZE]; const char* p = waveFormat; // RIFF chunks are always word (two byte) aligned. NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0, "LoadFormatChunk called with unaligned resource"); // The "format" chunk may not directly follow the "riff" chunk, so skip // over any intermediate chunks. if (!ScanForwardUntil(FRMT_CHUNK_MAGIC, &fmtSize)) { return false; } if (!ReadAll(waveFormat, sizeof(waveFormat))) { return false; } PR_STATIC_ASSERT(sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + 4 + sizeof(uint16_t) + sizeof(uint16_t) <= sizeof(waveFormat)); if (ReadUint16LE(&p) != WAVE_FORMAT_ENCODING_PCM) { NS_WARNING("WAVE is not uncompressed PCM, compressed encodings are not supported"); return false; } channels = ReadUint16LE(&p); rate = ReadUint32LE(&p); // Skip over average bytes per second field. p += 4; frameSize = ReadUint16LE(&p); sampleFormat = ReadUint16LE(&p); // PCM encoded WAVEs are not expected to have an extended "format" chunk, // but I have found WAVEs that have a extended "format" chunk with an // extension size of 0 bytes. Be polite and handle this rather than // considering the file invalid. This code skips any extension of the // "format" chunk. if (fmtSize > WAVE_FORMAT_CHUNK_SIZE) { char extLength[2]; const char* p = extLength; if (!ReadAll(extLength, sizeof(extLength))) { return false; } PR_STATIC_ASSERT(sizeof(uint16_t) <= sizeof(extLength)); uint16_t extra = ReadUint16LE(&p); if (fmtSize - (WAVE_FORMAT_CHUNK_SIZE + 2) != extra) { NS_WARNING("Invalid extended format chunk size"); return false; } extra += extra % 2; if (extra > 0) { PR_STATIC_ASSERT(UINT16_MAX + (UINT16_MAX % 2) < UINT_MAX / sizeof(char)); nsAutoArrayPtr<char> chunkExtension(new char[extra]); if (!ReadAll(chunkExtension.get(), extra)) { return false; } } } // RIFF chunks are always word (two byte) aligned. NS_ABORT_IF_FALSE(mDecoder->GetResource()->Tell() % 2 == 0, "LoadFormatChunk left resource unaligned"); // Make sure metadata is fairly sane. The rate check is fairly arbitrary, // but the channels check is intentionally limited to mono or stereo // because that's what the audio backend currently supports. unsigned int actualFrameSize = sampleFormat == 8 ? 1 : 2 * channels; if (rate < 100 || rate > 96000 || channels < 1 || channels > MAX_CHANNELS || (frameSize != 1 && frameSize != 2 && frameSize != 4) || (sampleFormat != 8 && sampleFormat != 16) || frameSize != actualFrameSize) { NS_WARNING("Invalid WAVE metadata"); return false; } ReentrantMonitorAutoEnter monitor(mDecoder->GetReentrantMonitor()); mSampleRate = rate; mChannels = channels; mFrameSize = frameSize; if (sampleFormat == 8) { mSampleFormat = FORMAT_U8; } else { mSampleFormat = FORMAT_S16; } return true; }
//----------------------------------------------------------------------------- // Purpose: Take a NULL terminated sentence, and parse any commands contained in // {}. The string is rewritten in place with those commands removed. // // Input : *pSentenceData - sentence data to be modified in place // sentenceIndex - global sentence table index for any data that is // parsed out //----------------------------------------------------------------------------- void VOX_ParseLineCommands( char *pSentenceData, int sentenceIndex ) { char tempBuffer[512]; char *pNext, *pStart; int length, tempBufferPos = 0; if( !pSentenceData ) return; pStart = pSentenceData; while( *pSentenceData ) { pNext = ScanForwardUntil( pSentenceData, '{' ); // find length of "good" portion of the string (not a {} command) length = pNext - pSentenceData; if( tempBufferPos + length > sizeof( tempBuffer )) { MsgDev( D_ERROR, "sentence too long!\n" ); return; } // Copy good string to temp buffer Q_memcpy( tempBuffer + tempBufferPos, pSentenceData, length ); // move the copy position tempBufferPos += length; pSentenceData = pNext; // skip ahead of the opening brace if( *pSentenceData ) pSentenceData++; // skip whitespace while( *pSentenceData && *pSentenceData <= 32 ) pSentenceData++; // simple comparison of string commands: switch( Q_tolower( *pSentenceData )) { case 'l': // all commands starting with the letter 'l' here if( !Q_strnicmp( pSentenceData, "len", 3 )) { g_Sentences[sentenceIndex].length = Q_atof( pSentenceData + 3 ); } break; case 0: default: break; } pSentenceData = ScanForwardUntil( pSentenceData, '}' ); // skip the closing brace if( *pSentenceData ) pSentenceData++; // skip trailing whitespace while( *pSentenceData && *pSentenceData <= 32 ) pSentenceData++; } if( tempBufferPos < sizeof( tempBuffer )) { // terminate cleaned up copy tempBuffer[tempBufferPos] = 0; // copy it over the original data Q_strcpy( pStart, tempBuffer ); } }