/*! DRAGONS: We use the current UTF16String SetString trait to ensure that we always have the correct handling, * even if the user wants these strings handled differently (i.e. we do it their way!) */ void SetStringArray(MDObjectPtr &Array, const std::list<std::string> &Strings) { // Abort if we are send a NULL pointer if(!Array) return; // Don't bother if we have nothing to do if(Strings.empty()) return; // Build a working string static MDTypePtr ValType = MDType::Find("UTF16String"); MDObjectPtr Value = ValType ? new MDObject(ValType) : NULL; if(!Value) { error("Can't build UTF16String value required by SetStringArray() - need this type to be defined in the dictionary file\n"); return; } // Get a buffer in which to build the final string array, make it quite granular as it will keep growing DataChunkPtr Buffer = new DataChunk(); Buffer->SetGranularity(16 * 1024); std::list<std::string>::const_iterator it = Strings.begin(); while(it != Strings.end()) { Value->SetString(*it); DataChunkPtr ThisString = Value->PutData(); Buffer->Append(ThisString); // Add terminator if required, i.e. if the sub-string we just added did not end in a zero UInt8 *p = &ThisString->Data[ThisString->Size]; // Terminate if either of the last two bytes in the current buffer is non-zero - or if the string was too short to have a terminator if((ThisString->Size) < 2 || ((*(--p) != 0) || (*(--p) != 0))) { const UInt8 Term[2] = { 0, 0}; Buffer->Set(2, Term, Buffer->Size); } it++; } // Set the value from this buffer Array->SetValue(Buffer); }
/*! \note This call will modify properties SampleRate, DataStart and DataSize */ MDObjectPtr mxflib::WAVE_PCM_EssenceSubParser::BuildWaveAudioDescriptor(FileHandle InFile, UInt64 Start /*=0*/) { const unsigned int ID_RIFF = 0x52494646; //! "RIFF" const unsigned int ID_fmt = 0x666d7420; //! "fmt " const unsigned int ID_data = 0x64617461; //! "data" MDObjectPtr Ret; FileSeek(InFile, Start); U32Pair Header = ReadRIFFHeader(InFile); // Can't build a descriptor if it isn't a RIFF file! if(Header.first != ID_RIFF) return Ret; if(Header.second < 4) return Ret; // Read the RIFF file type (always 4 bytes) DataChunkPtr ChunkData = FileReadChunk(InFile, 4); // Can't build a descriptor if it isn't a WAVE file! if(memcmp(ChunkData->Data, "WAVE", 4) != 0) return Ret; // Scan the chunks within the RIFF file // DRAGONS: To do this properly we would check the file size in the RIFF chunk // DRAGONS: "LIST" chunks are "sets" and are not yet supported for(;;) { Header = ReadRIFFHeader(InFile); // End of file? if((Header.first == 0) && (Header.second == 0)) break; if(Header.first == ID_fmt) { ChunkData = FileReadChunk(InFile, Header.second); if(ChunkData->Size < 16) return Ret; UInt16 AudioFormat = GetU16_LE(&ChunkData->Data[0]); if(AudioFormat != 1) return Ret; Ret = new MDObject(WaveAudioDescriptor_UL); if(!Ret) return Ret; // Set the sample rate char Buffer[32]; SampleRate = GetU32_LE(&ChunkData->Data[4]); sprintf(Buffer, "%d/1", SampleRate); Ret->SetString(SampleRate_UL, Buffer); Ret->SetString(AudioSamplingRate_UL, Buffer); // Must assume not locked! Ret->SetUInt(Locked_UL, 0); // Set channel count UInt16 Chan = GetU16_LE(&ChunkData->Data[2]); Ret->SetUInt(ChannelCount_UL, Chan); // Set quantization bits UInt16 Quant = GetU16_LE(&ChunkData->Data[14]); Ret->SetUInt(QuantizationBits_UL, Quant); // Calculate the number of bytes per sample SampleSize = ((Quant+7) / 8) * Chan; // Set the block alignment Ret->SetUInt(BlockAlign_UL, GetU16_LE(&ChunkData->Data[12])); // Set the byte-rate Ret->SetUInt(AvgBps_UL, GetU32_LE(&ChunkData->Data[8])); } else if(Header.first == ID_data) { // Record the location of the audio data DataStart = FileTell(InFile); DataSize = Header.second; // ...and skip the chunk value FileSeek(InFile, FileTell(InFile) + Header.second); } else { // Skip the chunk value FileSeek(InFile, FileTell(InFile) + Header.second); } } return Ret; }