Tag Parser: ogg/oggiterator.cpp Source File

Tag Parser 12.5.3 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
27
32 void 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
46 void OggIterator::reset()
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
63 void OggIterator::nextPage()
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
81 void OggIterator::nextSegment()
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
98 void OggIterator::previousPage()
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
113 void OggIterator::previousSegment()
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
134 void 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
152 throw TruncatedDataException();
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
199 void 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 }
211 throw TruncatedDataException();
212}
213
237 bool 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
TagParser::Failure
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
Definition exceptions.h:11
TagParser::OggIterator::nextPage
void nextPage()
Increases the current position by one page.
Definition oggiterator.cpp:63
TagParser::OggIterator::currentCharacterOffset
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
TagParser::OggIterator::read
void read(char *buffer, std::size_t count)
Reads count bytes from the Ogg stream and writes it to the specified buffer.
Definition oggiterator.cpp:134
TagParser::OggIterator::remainingBytesInCurrentSegment
std::uint64_t remainingBytesInCurrentSegment() const
Returns the number of bytes left to read in the current segment.
Definition oggiterator.h:248
TagParser::OggIterator::tellg
std::uint64_t tellg() const
Same as currentCharacterOffset(); only provided for compliance with std::istream.
Definition oggiterator.h:230
TagParser::OggIterator::readAll
std::size_t readAll(char *buffer, std::size_t max)
Reads all bytes from the Ogg stream and writes it to the specified buffer.
Definition oggiterator.cpp:169
TagParser::OggIterator::clear
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
TagParser::OggIterator::previousPage
void previousPage()
Decreases the current position by one page.
Definition oggiterator.cpp:98
TagParser::OggIterator::resyncAt
bool resyncAt(std::uint64_t offset)
Fetches the next page at the specified offset.
Definition oggiterator.cpp:237
TagParser::OggIterator::stream
std::istream & stream()
Returns the stream.
Definition oggiterator.h:91
TagParser::OggIterator::startOffset
std::uint64_t startOffset() const
Returns the start offset (which has been specified when constructing the iterator).
Definition oggiterator.h:109
TagParser::OggIterator::setPageIndex
void setPageIndex(std::vector< OggPage >::size_type index)
Sets the current page index.
Definition oggiterator.h:183
TagParser::OggIterator::currentSegmentSize
std::uint32_t currentSegmentSize() const
Returns the size of the current segment.
Definition oggiterator.h:240
TagParser::OggIterator::nextSegment
void nextSegment()
Increases the current position by one segment.
Definition oggiterator.cpp:81
TagParser::OggIterator::reset
void reset()
Resets the iterator to point at the first segment of the first page (matching the filter if set).
Definition oggiterator.cpp:46
TagParser::OggIterator::ignore
void ignore(std::size_t count=1)
Advances the position of the next character to be read from the Ogg stream by count bytes.
Definition oggiterator.cpp:199
TagParser::OggIterator::previousSegment
void previousSegment()
Decreases the current position by one segment.
Definition oggiterator.cpp:113
TagParser::OggIterator::streamSize
std::uint64_t streamSize() const
Returns the stream size (which has been specified when constructing the iterator).
Definition oggiterator.h:117
TagParser::OggPage
The OggPage class is used to parse Ogg pages.
Definition oggpage.h:13
TagParser::OggPage::dataOffset
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
TagParser::OggPage::segmentSizes
const std::vector< std::uint32_t > & segmentSizes() const
Returns the sizes of the segments of the page in byte.
Definition oggpage.h:220
TagParser::OggPage::startOffset
std::uint64_t startOffset() const
Returns the start offset of the page.
Definition oggpage.h:86
TagParser::OggPage::headerSize
std::uint32_t headerSize() const
Returns the header size in byte.
Definition oggpage.h:230
TagParser::TruncatedDataException
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Definition exceptions.h:39
exceptions.h
CppUtilities
Definition abstractcontainer.h:16
TagParser
Contains all classes and functions of the TagInfo library.
Definition aaccodebook.h:10
oggiterator.h