Tag Parser  10.1.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
oggpage.cpp
Go to the documentation of this file.
1 #include "./oggpage.h"
2 
3 #include "../exceptions.h"
4 
5 #include <c++utilities/conversion/binaryconversion.h>
6 #include <c++utilities/io/binaryreader.h>
7 
8 #include <limits>
9 
10 using namespace std;
11 using namespace CppUtilities;
12 
13 namespace TagParser {
14 
27 void OggPage::parseHeader(istream &stream, std::uint64_t startOffset, std::int32_t maxSize)
28 {
29  // prepare reading
30  stream.seekg(static_cast<streamoff>(startOffset));
31  BinaryReader reader(&stream);
32  if (maxSize < 27) {
33  throw TruncatedDataException();
34  } else {
35  maxSize -= 27;
36  }
37  // read header values
38  if (reader.readUInt32LE() != 0x5367674f) {
39  throw InvalidDataException();
40  }
41  m_startOffset = startOffset;
42  m_streamStructureVersion = reader.readByte();
43  m_headerTypeFlag = reader.readByte();
44  m_absoluteGranulePosition = reader.readUInt64LE();
45  m_streamSerialNumber = reader.readUInt32LE();
46  m_sequenceNumber = reader.readUInt32LE();
47  m_checksum = reader.readUInt32LE();
48  m_segmentCount = reader.readByte();
49  m_segmentSizes.clear();
50  if (m_segmentCount > 0) {
51  if (maxSize < m_segmentCount) {
52  throw TruncatedDataException();
53  } else {
54  maxSize -= m_segmentCount;
55  }
56  // read segment size table
57  m_segmentSizes.emplace_back(0);
58  for (std::uint8_t i = 0; i < m_segmentCount;) {
59  std::uint8_t entry = reader.readByte();
60  maxSize -= entry;
61  m_segmentSizes.back() += entry;
62  if (++i < m_segmentCount && entry < 0xFF) {
63  m_segmentSizes.emplace_back(0);
64  } else if (i == m_segmentCount && entry == 0xFF) {
65  m_headerTypeFlag |= 0x80; // FIXME v11: don't abuse header type flags
66  }
67  }
68  // check whether the maximum size is exceeded
69  if (maxSize < 0) {
70  throw TruncatedDataException();
71  }
72  }
73 }
74 
79 std::uint32_t OggPage::computeChecksum(istream &stream, std::uint64_t startOffset)
80 {
81  stream.seekg(static_cast<streamoff>(startOffset));
82  std::uint32_t crc = 0x0;
83  std::uint8_t value, segmentTableSize = 0, segmentTableIndex = 0;
84  for (std::uint32_t i = 0, segmentLength = 27; i != segmentLength; ++i) {
85  switch (i) {
86  case 22:
87  // bytes 22, 23, 24, 25 hold denoted checksum and must be set to zero
88  stream.seekg(4, ios_base::cur);
89  [[fallthrough]];
90  case 23:
91  case 24:
92  case 25:
93  value = 0;
94  break;
95  case 26:
96  // byte 26 holds the number of segment sizes
97  segmentLength += (segmentTableSize = (value = static_cast<std::uint8_t>(stream.get())));
98  break;
99  default:
100  value = static_cast<std::uint8_t>(stream.get());
101  if (i > 26 && segmentTableIndex < segmentTableSize) {
102  // bytes 27 to (27 + segment size count) hold page size
103  segmentLength += value;
104  ++segmentTableIndex;
105  }
106  }
107  crc = (crc << 8) ^ BinaryReader::crc32Table[((crc >> 24) & 0xFF) ^ value];
108  }
109  return crc;
110 }
111 
116 void OggPage::updateChecksum(iostream &stream, std::uint64_t startOffset)
117 {
118  char buff[4];
119  LE::getBytes(computeChecksum(stream, startOffset), buff);
120  stream.seekp(static_cast<streamoff>(startOffset + 22));
121  stream.write(buff, sizeof(buff));
122 }
123 
129 std::uint32_t OggPage::makeSegmentSizeDenotation(ostream &stream, std::uint32_t size)
130 {
131  std::uint32_t bytesWritten = 1;
132  while (size >= 0xff) {
133  stream.put(static_cast<char>(0xff));
134  size -= 0xff;
135  ++bytesWritten;
136  }
137  stream.put(static_cast<char>(size));
138  return bytesWritten;
139 }
140 
141 } // namespace TagParser
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
Definition: exceptions.h:25
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Definition: exceptions.h:39
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10