Tag Parser 12.3.1
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
Loading...
Searching...
No Matches
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...
void nextPage()
Increases the current position by one page.
std::uint64_t currentCharacterOffset() const
Returns the offset of the current character in the input stream if the iterator is valid; otherwise a...
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.
std::uint64_t tellg() const
Same as currentCharacterOffset(); only provided for compliance with std::istream.
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.
void previousPage()
Decreases the current position by one page.
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).
void setPageIndex(std::vector< OggPage >::size_type index)
Sets the current page index.
std::uint32_t currentSegmentSize() const
Returns the size of the current segment.
void nextSegment()
Increases the current position by one segment.
void reset()
Resets the iterator to point at the first segment of the first page (matching the filter if set).
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).
The OggPage class is used to parse Ogg pages.
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:259
const std::vector< std::uint32_t > & segmentSizes() const
Returns the sizes of the segments of the page in byte.
Definition oggpage.h:220
std::uint64_t startOffset() const
Returns the start offset of the page.
Definition oggpage.h:86
std::uint32_t headerSize() const
Returns the header size in byte.
Definition oggpage.h:230
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Contains all classes and functions of the TagInfo library.
Definition aaccodebook.h:10