diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/soundlib/OggStream.cpp')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/soundlib/OggStream.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/soundlib/OggStream.cpp b/Src/external_dependencies/openmpt-trunk/soundlib/OggStream.cpp new file mode 100644 index 00000000..848b47d3 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/soundlib/OggStream.cpp @@ -0,0 +1,213 @@ +/* + * OggStream.cpp + * ------------- + * Purpose: Basic Ogg stream parsing functionality + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#include "stdafx.h" +#include "OggStream.h" +#include "mpt/crc/crc.hpp" +#include "../common/FileReader.h" + + +OPENMPT_NAMESPACE_BEGIN + + +namespace Ogg +{ + + +uint16 PageInfo::GetPagePhysicalSize() const +{ + uint16 size = 0; + size += sizeof(PageHeader); + size += header.page_segments; + for(uint8 segment = 0; segment < header.page_segments; ++segment) + { + size += segment_table[segment]; + } + return size; +} + + +uint16 PageInfo::GetPageHeaderSize() const +{ + uint16 size = 0; + size += sizeof(PageHeader); + size += header.page_segments; + return size; +} + + +uint16 PageInfo::GetPageDataSize() const +{ + uint16 size = 0; + for(uint8 segment = 0; segment < header.page_segments; ++segment) + { + size += segment_table[segment]; + } + return size; +} + + +bool AdvanceToPageMagic(FileReader &file) +{ +#if MPT_COMPILER_MSVC +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif // MPT_COMPILER_MSVC + while(true) +#if MPT_COMPILER_MSVC +#pragma warning(pop) +#endif // MPT_COMPILER_MSVC + { + if(!file.CanRead(4)) + { + return false; + } + if(file.ReadMagic("OggS")) + { + file.SkipBack(4); + return true; + } + file.Skip(1); + } +} + + +bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector<uint8> *pageData) +{ + pageInfo = PageInfo(); + if(pageData) + { + (*pageData).clear(); + } + if(!file.ReadMagic("OggS")) + { + return false; + } + file.SkipBack(4); + FileReader filePageReader = file; // do not modify original file read position + if(!filePageReader.ReadStruct(pageInfo.header)) + { + return false; + } + if(!filePageReader.CanRead(pageInfo.header.page_segments)) + { + return false; + } + uint16 pageDataSize = 0; + for(uint8 segment = 0; segment < pageInfo.header.page_segments; ++segment) + { + pageInfo.segment_table[segment] = filePageReader.ReadIntLE<uint8>(); + pageDataSize += pageInfo.segment_table[segment]; + } + if(!filePageReader.CanRead(pageDataSize)) + { + return false; + } + if(pageData) + { + filePageReader.ReadVector(*pageData, pageDataSize); + } else + { + filePageReader.Skip(pageDataSize); + } + filePageReader.SkipBack(pageInfo.GetPagePhysicalSize()); + { + mpt::crc32_ogg calculatedCRC; + uint8 rawHeader[sizeof(PageHeader)]; + MemsetZero(rawHeader); + filePageReader.ReadArray(rawHeader); + std::memset(rawHeader + 22, 0, 4); // clear out old crc + calculatedCRC.process(rawHeader, rawHeader + sizeof(rawHeader)); + filePageReader.Skip(pageInfo.header.page_segments); + calculatedCRC.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments); + if(pageData) + { + filePageReader.Skip(pageDataSize); + calculatedCRC.process(*pageData); + } else + { + FileReader pageDataReader = filePageReader.ReadChunk(pageDataSize); + auto pageDataView = pageDataReader.GetPinnedView(); + calculatedCRC.process(pageDataView.GetSpan()); + } + if(calculatedCRC != pageInfo.header.CRC_checksum) + { + return false; + } + } + file.Skip(pageInfo.GetPagePhysicalSize()); + return true; +} + + +bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector<uint8> &pageData) +{ + return ReadPage(file, pageInfo, &pageData); +} + + +bool ReadPage(FileReader &file) +{ + PageInfo pageInfo; + return ReadPage(file, pageInfo); +} + + +bool ReadPageAndSkipJunk(FileReader &file, PageInfo &pageInfo, std::vector<uint8> &pageData) +{ + pageInfo = PageInfo(); + pageData.clear(); +#if MPT_COMPILER_MSVC +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant +#endif // MPT_COMPILER_MSVC + while(true) +#if MPT_COMPILER_MSVC +#pragma warning(pop) +#endif // MPT_COMPILER_MSVC + { + if(!AdvanceToPageMagic(file)) + { + return false; + } + if(ReadPage(file, pageInfo, pageData)) + { + return true; + } else + { + pageInfo = PageInfo(); + pageData.clear(); + } + file.Skip(1); + } +} + + +bool UpdatePageCRC(PageInfo &pageInfo, const std::vector<uint8> &pageData) +{ + if(pageData.size() != pageInfo.GetPageDataSize()) + { + return false; + } + mpt::crc32_ogg crc; + pageInfo.header.CRC_checksum = 0; + char rawHeader[sizeof(PageHeader)]; + std::memcpy(rawHeader, &pageInfo.header, sizeof(PageHeader)); + crc.process(rawHeader, rawHeader + sizeof(PageHeader)); + crc.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments); + crc.process(pageData); + pageInfo.header.CRC_checksum = crc; + return true; +} + + +} // namespace Ogg + + +OPENMPT_NAMESPACE_END |