#include "../../Minecraft.World/Platform/stdafx.h" #include #include #include #include "DLCManager.h" #include "DLCAudioFile.h" #if defined _XBOX || defined _WINDOWS64 #include "../../Minecraft.Client/Platform/Xbox/XML/ATGXmlParser.h" #include "../../Minecraft.Client/Platform/Xbox/XML/xmlFilesCallback.h" #endif namespace { constexpr std::size_t AUDIO_DLC_WCHAR_BIN_SIZE = 2; #if WCHAR_MAX > 0xFFFF static std::wstring ReadAudioDlcWString(const void* data) { const std::uint16_t* chars = static_cast(data); const std::uint16_t* end = chars; while (*end != 0) { ++end; } std::wstring out(static_cast(end - chars), 0); for (std::size_t i = 0; i < out.size(); ++i) { out[i] = static_cast(chars[i]); } return out; } #else static std::wstring ReadAudioDlcWString(const void* data) { return std::wstring(static_cast(data)); } #endif template T ReadAudioDlcValue(const std::uint8_t* data, unsigned int offset = 0) { T value; std::memcpy(&value, data + offset, sizeof(value)); return value; } template void ReadAudioDlcStruct(T* out, const std::uint8_t* data, unsigned int offset = 0) { std::memcpy(out, data + offset, sizeof(*out)); } inline unsigned int AudioParamAdvance(unsigned int wcharCount) { return static_cast(sizeof(C4JStorage::DLC_FILE_PARAM) + wcharCount * AUDIO_DLC_WCHAR_BIN_SIZE); } inline unsigned int AudioDetailAdvance(unsigned int wcharCount) { return static_cast(sizeof(C4JStorage::DLC_FILE_DETAILS) + wcharCount * AUDIO_DLC_WCHAR_BIN_SIZE); } inline std::wstring ReadAudioParamString(const std::uint8_t* data, unsigned int offset) { return ReadAudioDlcWString(data + offset + offsetof(C4JStorage::DLC_FILE_PARAM, wchData)); } } // namespace DLCAudioFile::DLCAudioFile(const std::wstring& path) : DLCFile(DLCManager::e_DLCType_Audio, path) { m_pbData = NULL; m_dataBytes = 0; } void DLCAudioFile::addData(std::uint8_t* pbData, std::uint32_t dataBytes) { m_pbData = pbData; m_dataBytes = dataBytes; processDLCDataFile(pbData, dataBytes); } std::uint8_t* DLCAudioFile::getData(std::uint32_t& dataBytes) { dataBytes = m_dataBytes; return m_pbData; } const WCHAR* DLCAudioFile::wchTypeNamesA[] = { L"CUENAME", L"CREDIT", }; DLCAudioFile::EAudioParameterType DLCAudioFile::getParameterType( const std::wstring& paramName) { EAudioParameterType type = e_AudioParamType_Invalid; for (int i = 0; i < e_AudioParamType_Max; ++i) { if (paramName.compare(wchTypeNamesA[i]) == 0) { type = (EAudioParameterType)i; break; } } return type; } void DLCAudioFile::addParameter(EAudioType type, EAudioParameterType ptype, const std::wstring& value) { switch (ptype) { case e_AudioParamType_Credit: // If this parameter exists, then mark // this as free // add it to the DLC credits list // we'll need to justify this text since we don't have a lot of room // for lines of credits { // don't look for duplicate in the music credits // if(app.AlreadySeenCreditText(value)) break; int maximumChars = 55; bool bIsSDMode = !RenderManager.IsHiDef() && !RenderManager.IsWidescreen(); if (bIsSDMode) { maximumChars = 45; } switch (XGetLanguage()) { case XC_LANGUAGE_JAPANESE: case XC_LANGUAGE_TCHINESE: case XC_LANGUAGE_KOREAN: maximumChars = 35; break; } std::wstring creditValue = value; while (creditValue.length() > maximumChars) { unsigned int i = 1; while (i < creditValue.length() && (i + 1) <= maximumChars) { i++; } int iLast = (int)creditValue.find_last_of(L" ", i); switch (XGetLanguage()) { case XC_LANGUAGE_JAPANESE: case XC_LANGUAGE_TCHINESE: case XC_LANGUAGE_KOREAN: iLast = maximumChars; break; default: iLast = (int)creditValue.find_last_of(L" ", i); break; } // if a space was found, include the space on this line if (iLast != i) { iLast++; } app.AddCreditText((creditValue.substr(0, iLast)).c_str()); creditValue = creditValue.substr(iLast); } app.AddCreditText(creditValue.c_str()); } break; case e_AudioParamType_Cuename: m_parameters[type].push_back(value); // m_parameters[(int)type] = value; break; default: break; } } bool DLCAudioFile::processDLCDataFile(std::uint8_t* pbData, std::uint32_t dataLength) { std::unordered_map parameterMapping; unsigned int uiCurrentByte = 0; // File format defined in the AudioPacker // File format: Version 1 unsigned int uiVersion = ReadAudioDlcValue(pbData, uiCurrentByte); uiCurrentByte += sizeof(int); if (uiVersion < CURRENT_AUDIO_VERSION_NUM) { if (pbData != NULL) delete[] pbData; app.DebugPrintf("DLC version of %d is too old to be read\n", uiVersion); return false; } unsigned int uiParameterTypeCount = ReadAudioDlcValue(pbData, uiCurrentByte); uiCurrentByte += sizeof(int); C4JStorage::DLC_FILE_PARAM paramBuf; ReadAudioDlcStruct(¶mBuf, pbData, uiCurrentByte); for (unsigned int i = 0; i < uiParameterTypeCount; i++) { // Map DLC strings to application strings, then store the DLC index // mapping to application index std::wstring parameterName = ReadAudioParamString(pbData, uiCurrentByte); EAudioParameterType type = getParameterType(parameterName); if (type != e_AudioParamType_Invalid) { parameterMapping[paramBuf.dwType] = type; } uiCurrentByte += AudioParamAdvance(paramBuf.dwWchCount); ReadAudioDlcStruct(¶mBuf, pbData, uiCurrentByte); } unsigned int uiFileCount = ReadAudioDlcValue(pbData, uiCurrentByte); uiCurrentByte += sizeof(int); C4JStorage::DLC_FILE_DETAILS fileBuf; ReadAudioDlcStruct(&fileBuf, pbData, uiCurrentByte); unsigned int tempByteOffset = uiCurrentByte; for (unsigned int i = 0; i < uiFileCount; i++) { tempByteOffset += AudioDetailAdvance(fileBuf.dwWchCount); ReadAudioDlcStruct(&fileBuf, pbData, tempByteOffset); } std::uint8_t* pbTemp = &pbData[tempByteOffset]; ReadAudioDlcStruct(&fileBuf, pbData, uiCurrentByte); for (unsigned int i = 0; i < uiFileCount; i++) { EAudioType type = (EAudioType)fileBuf.dwType; // Params unsigned int uiParameterCount = ReadAudioDlcValue(pbTemp); pbTemp += sizeof(int); ReadAudioDlcStruct(¶mBuf, pbTemp); for (unsigned int j = 0; j < uiParameterCount; j++) { // EAudioParameterType paramType = e_AudioParamType_Invalid; AUTO_VAR(it, parameterMapping.find(paramBuf.dwType)); if (it != parameterMapping.end()) { addParameter(type, (EAudioParameterType)paramBuf.dwType, ReadAudioParamString(pbTemp, 0)); } pbTemp += AudioParamAdvance(paramBuf.dwWchCount); ReadAudioDlcStruct(¶mBuf, pbTemp); } // Move the pointer to the start of the next files data; pbTemp += fileBuf.uiFileSize; uiCurrentByte += AudioDetailAdvance(fileBuf.dwWchCount); ReadAudioDlcStruct(&fileBuf, pbData, uiCurrentByte); } return true; } int DLCAudioFile::GetCountofType(DLCAudioFile::EAudioType eType) { return m_parameters[eType].size(); } std::wstring& DLCAudioFile::GetSoundName(int iIndex) { int iWorldType = e_AudioType_Overworld; while (iIndex >= m_parameters[iWorldType].size()) { iIndex -= m_parameters[iWorldType].size(); iWorldType++; } return m_parameters[iWorldType].at(iIndex); }