OggStream.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * OggStream.cpp
  3. * -------------
  4. * Purpose: Basic Ogg stream parsing functionality
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "OggStream.h"
  11. #include "mpt/crc/crc.hpp"
  12. #include "../common/FileReader.h"
  13. OPENMPT_NAMESPACE_BEGIN
  14. namespace Ogg
  15. {
  16. uint16 PageInfo::GetPagePhysicalSize() const
  17. {
  18. uint16 size = 0;
  19. size += sizeof(PageHeader);
  20. size += header.page_segments;
  21. for(uint8 segment = 0; segment < header.page_segments; ++segment)
  22. {
  23. size += segment_table[segment];
  24. }
  25. return size;
  26. }
  27. uint16 PageInfo::GetPageHeaderSize() const
  28. {
  29. uint16 size = 0;
  30. size += sizeof(PageHeader);
  31. size += header.page_segments;
  32. return size;
  33. }
  34. uint16 PageInfo::GetPageDataSize() const
  35. {
  36. uint16 size = 0;
  37. for(uint8 segment = 0; segment < header.page_segments; ++segment)
  38. {
  39. size += segment_table[segment];
  40. }
  41. return size;
  42. }
  43. bool AdvanceToPageMagic(FileReader &file)
  44. {
  45. #if MPT_COMPILER_MSVC
  46. #pragma warning(push)
  47. #pragma warning(disable:4127) // conditional expression is constant
  48. #endif // MPT_COMPILER_MSVC
  49. while(true)
  50. #if MPT_COMPILER_MSVC
  51. #pragma warning(pop)
  52. #endif // MPT_COMPILER_MSVC
  53. {
  54. if(!file.CanRead(4))
  55. {
  56. return false;
  57. }
  58. if(file.ReadMagic("OggS"))
  59. {
  60. file.SkipBack(4);
  61. return true;
  62. }
  63. file.Skip(1);
  64. }
  65. }
  66. bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector<uint8> *pageData)
  67. {
  68. pageInfo = PageInfo();
  69. if(pageData)
  70. {
  71. (*pageData).clear();
  72. }
  73. if(!file.ReadMagic("OggS"))
  74. {
  75. return false;
  76. }
  77. file.SkipBack(4);
  78. FileReader filePageReader = file; // do not modify original file read position
  79. if(!filePageReader.ReadStruct(pageInfo.header))
  80. {
  81. return false;
  82. }
  83. if(!filePageReader.CanRead(pageInfo.header.page_segments))
  84. {
  85. return false;
  86. }
  87. uint16 pageDataSize = 0;
  88. for(uint8 segment = 0; segment < pageInfo.header.page_segments; ++segment)
  89. {
  90. pageInfo.segment_table[segment] = filePageReader.ReadIntLE<uint8>();
  91. pageDataSize += pageInfo.segment_table[segment];
  92. }
  93. if(!filePageReader.CanRead(pageDataSize))
  94. {
  95. return false;
  96. }
  97. if(pageData)
  98. {
  99. filePageReader.ReadVector(*pageData, pageDataSize);
  100. } else
  101. {
  102. filePageReader.Skip(pageDataSize);
  103. }
  104. filePageReader.SkipBack(pageInfo.GetPagePhysicalSize());
  105. {
  106. mpt::crc32_ogg calculatedCRC;
  107. uint8 rawHeader[sizeof(PageHeader)];
  108. MemsetZero(rawHeader);
  109. filePageReader.ReadArray(rawHeader);
  110. std::memset(rawHeader + 22, 0, 4); // clear out old crc
  111. calculatedCRC.process(rawHeader, rawHeader + sizeof(rawHeader));
  112. filePageReader.Skip(pageInfo.header.page_segments);
  113. calculatedCRC.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments);
  114. if(pageData)
  115. {
  116. filePageReader.Skip(pageDataSize);
  117. calculatedCRC.process(*pageData);
  118. } else
  119. {
  120. FileReader pageDataReader = filePageReader.ReadChunk(pageDataSize);
  121. auto pageDataView = pageDataReader.GetPinnedView();
  122. calculatedCRC.process(pageDataView.GetSpan());
  123. }
  124. if(calculatedCRC != pageInfo.header.CRC_checksum)
  125. {
  126. return false;
  127. }
  128. }
  129. file.Skip(pageInfo.GetPagePhysicalSize());
  130. return true;
  131. }
  132. bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector<uint8> &pageData)
  133. {
  134. return ReadPage(file, pageInfo, &pageData);
  135. }
  136. bool ReadPage(FileReader &file)
  137. {
  138. PageInfo pageInfo;
  139. return ReadPage(file, pageInfo);
  140. }
  141. bool ReadPageAndSkipJunk(FileReader &file, PageInfo &pageInfo, std::vector<uint8> &pageData)
  142. {
  143. pageInfo = PageInfo();
  144. pageData.clear();
  145. #if MPT_COMPILER_MSVC
  146. #pragma warning(push)
  147. #pragma warning(disable:4127) // conditional expression is constant
  148. #endif // MPT_COMPILER_MSVC
  149. while(true)
  150. #if MPT_COMPILER_MSVC
  151. #pragma warning(pop)
  152. #endif // MPT_COMPILER_MSVC
  153. {
  154. if(!AdvanceToPageMagic(file))
  155. {
  156. return false;
  157. }
  158. if(ReadPage(file, pageInfo, pageData))
  159. {
  160. return true;
  161. } else
  162. {
  163. pageInfo = PageInfo();
  164. pageData.clear();
  165. }
  166. file.Skip(1);
  167. }
  168. }
  169. bool UpdatePageCRC(PageInfo &pageInfo, const std::vector<uint8> &pageData)
  170. {
  171. if(pageData.size() != pageInfo.GetPageDataSize())
  172. {
  173. return false;
  174. }
  175. mpt::crc32_ogg crc;
  176. pageInfo.header.CRC_checksum = 0;
  177. char rawHeader[sizeof(PageHeader)];
  178. std::memcpy(rawHeader, &pageInfo.header, sizeof(PageHeader));
  179. crc.process(rawHeader, rawHeader + sizeof(PageHeader));
  180. crc.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments);
  181. crc.process(pageData);
  182. pageInfo.header.CRC_checksum = crc;
  183. return true;
  184. }
  185. } // namespace Ogg
  186. OPENMPT_NAMESPACE_END