bool CAudioContainerSA::GetRawAudioData ( eAudioLookupIndex lookupIndex, int bankIndex, int audioIndex, uint8*& dataOut, unsigned int& lengthOut, int& iSampleRateOut ) { int numBanks = m_pLookupTable->CountIndex ( lookupIndex ); if ( numBanks == 0 ) return false; // Get archive file size std::ifstream archive ( FromUTF8( GetAudioArchiveName ( lookupIndex ) ), std::ios::binary ); SAudioLookupEntrySA* lookupEntry = m_pLookupTable->GetEntry ( lookupIndex, bankIndex ); if ( !lookupEntry ) return false; // Read audio archive bank header (an audio archieve has multiple bank headers) SAudioBankHeaderSA bankHeader; // Seek to the bank offset and read the header archive.seekg ( lookupEntry->offset ); if ( !archive.read ( reinterpret_cast<char*> ( &bankHeader ), sizeof ( SAudioBankHeaderSA ) ) ) return false; // Get offsets to calculate the length SAudioEntrySA* audioEntry = &bankHeader.sounds[audioIndex]; if ( !audioEntry ) return false; unsigned int rawLength; if ( audioIndex+1 < bankHeader.numSounds ) // hacky fix: audioIndex starts at 0 { SAudioEntrySA* nextAudioEntry = &bankHeader.sounds[audioIndex+1]; if ( !nextAudioEntry ) return false; rawLength = nextAudioEntry->offset - audioEntry->offset; } else if ( audioIndex+1 == bankHeader.numSounds ) { rawLength = lookupEntry->length - audioEntry->offset; } else return false; // 2MB check in case of user modification errors (Max length of standard audio files is 560KB) if ( rawLength > 2 * 1024 * 1024 ) return false; // Now we are ready to read the audio data :) uint8* buffer = new uint8[rawLength]; dataOut = buffer; lengthOut = rawLength; iSampleRateOut = audioEntry->sampleRate; // Seek to the correct offset and read archive.seekg ( lookupEntry->offset + sizeof(SAudioBankHeaderSA) + audioEntry->offset ); // Or just archive.seekg ( archive.tellg() + audioEntry->offset ) archive.read(reinterpret_cast<char*> ( buffer ), rawLength ); return !archive.fail(); }
bool CAudioContainerSA::ValidateContainer(eAudioLookupIndex lookupIndex) { #ifdef MTA_DEBUG return true; #endif // Open archive and place file pointer at the end std::ifstream archive(FromUTF8(GetAudioArchiveName(lookupIndex)), std::ios::binary); // Check if it does not exist if (!archive) return false; // Get the archive size divided by 10 and seek to the beginning archive.seekg(0, std::ios::end); std::streampos stepSize = archive.tellg() / 10; archive.seekg(0); // Count the zeros -> if more than 80% we assume that it has been cut (read 4KB blocks at once) uint8 buffer[VALIDATE_BUFFER_SIZE]; unsigned long long numZeros = 0; while (archive.read(reinterpret_cast<char*>(buffer), VALIDATE_BUFFER_SIZE)) { for (unsigned int i = 0; i < VALIDATE_BUFFER_SIZE; i++) { if (buffer[i] == 0) numZeros++; } archive.seekg(stepSize, std::ios::cur); } // Close the archive archive.close(); if (static_cast<float>(numZeros) / (10 * VALIDATE_BUFFER_SIZE) >= 0.8f) return false; return true; }