Tag Parser 10.3.1
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
oggiterator.cpp
Go to the documentation of this file.
1#include "./oggiterator.h"
2
3#include "../exceptions.h"
4
5#include <c++utilities/io/binaryreader.h>
6
7#include <iostream>
8#include <limits>
9
10using namespace std;
11using namespace CppUtilities;
12
13namespace TagParser {
14
32void OggIterator::clear(istream &stream, std::uint64_t startOffset, std::uint64_t streamSize)
33{
34 m_stream = &stream;
35 m_startOffset = startOffset;
36 m_streamSize = streamSize;
37 m_pages.clear();
38}
39
47{
48 for (m_page = m_segment = m_offset = 0; m_page < m_pages.size() || fetchNextPage(); ++m_page) {
49 const OggPage &page = m_pages[m_page];
50 if (!page.segmentSizes().empty() && matchesFilter(page)) {
51 // page is not empty and matches ID filter if set
52 m_offset = page.startOffset() + page.headerSize();
53 break;
54 }
55 }
56 // no matching page found -> iterator is invalid
57}
58
64{
65 while (++m_page < m_pages.size() || fetchNextPage()) {
66 const OggPage &page = m_pages[m_page];
67 if (!page.segmentSizes().empty() && matchesFilter(page)) {
68 // page is not empty and matches ID filter if set
69 m_segment = m_bytesRead = 0;
70 m_offset = page.startOffset() + page.headerSize();
71 return;
72 }
73 }
74 // no next page available -> iterator is in invalid state
75}
76
82{
83 const OggPage &page = m_pages[m_page];
84 if (matchesFilter(page) && ++m_segment < page.segmentSizes().size()) {
85 // current page has next segment
86 m_bytesRead = 0;
87 m_offset += page.segmentSizes()[m_segment - 1];
88 } else {
89 // next (matching) page has next segment
90 nextPage();
91 }
92}
93
99{
100 while (m_page) {
101 const OggPage &page = m_pages[--m_page];
102 if (matchesFilter(page)) {
103 m_offset = page.dataOffset(m_segment = page.segmentSizes().size() - 1);
104 return;
105 }
106 }
107}
108
114{
115 const OggPage &page = m_pages[m_page];
116 if (m_segment && matchesFilter(page)) {
117 m_offset -= page.segmentSizes()[m_segment--];
118 } else {
119 previousPage();
120 }
121}
122
134void OggIterator::read(char *buffer, std::size_t count)
135{
136 std::size_t bytesRead = 0;
137 while (*this && count) {
138 const auto available = remainingBytesInCurrentSegment();
139 stream().seekg(static_cast<std::streamoff>(currentCharacterOffset()));
140 if (count <= available) {
141 stream().read(buffer + bytesRead, static_cast<std::streamsize>(count));
142 m_bytesRead += count;
143 return;
144 }
145 stream().read(buffer + bytesRead, static_cast<std::streamsize>(available));
146 nextSegment();
147 bytesRead += available;
148 count -= available;
149 }
150 if (count) {
151 // still bytes to read but no more available
153 }
154}
155
169std::size_t OggIterator::readAll(char *buffer, std::size_t max)
170{
171 auto bytesRead = std::size_t(0);
172 while (*this && max) {
173 const auto available = remainingBytesInCurrentSegment();
174 stream().seekg(static_cast<std::streamoff>(currentCharacterOffset()), std::ios_base::beg);
175 if (max <= available) {
176 stream().read(buffer + bytesRead, static_cast<std::streamsize>(max));
177 m_bytesRead += max;
178 return bytesRead + max;
179 } else {
180 stream().read(buffer + bytesRead, static_cast<std::streamsize>(available));
181 nextSegment();
182 bytesRead += available;
183 max -= available;
184 }
185 }
186 return bytesRead;
187}
188
199void OggIterator::ignore(std::size_t count)
200{
201 while (*this) {
202 const auto available = currentSegmentSize() - m_bytesRead;
203 if (count <= available) {
204 m_bytesRead += count;
205 return;
206 } else {
207 nextSegment();
208 count -= available;
209 }
210 }
212}
213
237bool OggIterator::resyncAt(std::uint64_t offset)
238{
239 // check whether offset is valid
240 if (offset >= streamSize() || offset < (m_pages.empty() ? m_startOffset : m_pages.back().startOffset() + m_pages.back().totalSize())) {
241 return false;
242 }
243
244 // find capture pattern 'OggS'
245 stream().seekg(static_cast<streamoff>(offset));
246 std::uint8_t lettersFound = 0;
247 for (std::uint64_t bytesAvailable = max<std::uint64_t>(streamSize() - offset, 65307ul); bytesAvailable >= 27; --bytesAvailable) {
248 switch (static_cast<char>(stream().get())) {
249 case 'O':
250 lettersFound = 1;
251 break;
252 case 'g':
253 lettersFound = lettersFound == 1 || lettersFound == 2 ? lettersFound + 1 : 0;
254 break;
255 case 'S':
256 if (lettersFound == 3) {
257 // capture pattern found
258 const auto currentOffset = stream().tellg();
259 // -> try to parse an OGG page at this position
260 try {
261 m_pages.emplace_back(stream(), static_cast<std::uint64_t>(stream().tellg()) - 4,
262 bytesAvailable > numeric_limits<std::int32_t>::max() ? numeric_limits<std::int32_t>::max()
263 : static_cast<std::int32_t>(bytesAvailable));
264 setPageIndex(m_pages.size() - 1);
265 return true;
266 } catch (const Failure &) {
267 stream().seekg(currentOffset);
268 }
269 }
270 [[fallthrough]];
271 default:
272 lettersFound = 0;
273 }
274 }
275 return false;
276}
277
288bool OggIterator::fetchNextPage()
289{
290 if (m_page == m_pages.size()) { // can only fetch the next page if the current page is the last page
291 m_offset = m_pages.empty() ? m_startOffset : m_pages.back().startOffset() + m_pages.back().totalSize();
292 if (m_offset < m_streamSize) {
293 const std::uint64_t bytesAvailable = m_streamSize - m_offset;
294 m_pages.emplace_back(*m_stream, m_offset,
295 bytesAvailable > numeric_limits<std::int32_t>::max() ? numeric_limits<std::int32_t>::max()
296 : static_cast<std::int32_t>(bytesAvailable));
297 return true;
298 }
299 }
300 return false;
301}
302
303} // namespace TagParser
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
Definition: exceptions.h:11
void nextPage()
Increases the current position by one page.
Definition: oggiterator.cpp:63
std::uint64_t currentCharacterOffset() const
Returns the offset of the current character in the input stream if the iterator is valid; otherwise a...
Definition: oggiterator.h:222
void read(char *buffer, std::size_t count)
Reads count bytes from the OGG stream and writes it to the specified buffer.
std::uint64_t remainingBytesInCurrentSegment() const
Returns the number of bytes left to read in the current segment.
Definition: oggiterator.h:248
std::uint64_t tellg() const
Same as currentCharacterOffset(); only provided for compliance with std::istream.
Definition: oggiterator.h:230
std::size_t readAll(char *buffer, std::size_t max)
Reads all bytes from the OGG stream and writes it to the specified buffer.
void clear(std::istream &stream, std::uint64_t startOffset, std::uint64_t streamSize)
Sets the stream and related parameters and clears all available pages.
Definition: oggiterator.cpp:32
void previousPage()
Decreases the current position by one page.
Definition: oggiterator.cpp:98
bool resyncAt(std::uint64_t offset)
Fetches the next page at the specified offset.
std::istream & stream()
Returns the stream.
Definition: oggiterator.h:91
std::uint64_t startOffset() const
Returns the start offset (which has been specified when constructing the iterator).
Definition: oggiterator.h:109
void setPageIndex(std::vector< OggPage >::size_type index)
Sets the current page index.
Definition: oggiterator.h:183
std::uint32_t currentSegmentSize() const
Returns the size of the current segment.
Definition: oggiterator.h:240
void nextSegment()
Increases the current position by one segment.
Definition: oggiterator.cpp:81
void reset()
Resets the iterator to point at the first segment of the first page (matching the filter if set).
Definition: oggiterator.cpp:46
void ignore(std::size_t count=1)
Advances the position of the next character to be read from the OGG stream by count bytes.
void previousSegment()
Decreases the current position by one segment.
std::uint64_t streamSize() const
Returns the stream size (which has been specified when constructing the iterator).
Definition: oggiterator.h:117
The OggPage class is used to parse OGG pages.
Definition: oggpage.h:13
std::uint64_t dataOffset(std::vector< std::uint32_t >::size_type segmentIndex=0) const
Returns the data offset of the segment with the specified segmentIndex.
Definition: oggpage.h:257
const std::vector< std::uint32_t > & segmentSizes() const
Returns the sizes of the segments of the page in byte.
Definition: oggpage.h:218
std::uint64_t startOffset() const
Returns the start offset of the page.
Definition: oggpage.h:84
std::uint32_t headerSize() const
Returns the header size in byte.
Definition: oggpage.h:228
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