Added TagLib (with AUTORS and COPYING files)
[someplayer] / src / taglib / ogg / oggpageheader.cpp
1 /***************************************************************************
2     copyright            : (C) 2002 - 2008 by Scott Wheeler
3     email                : wheeler@kde.org
4  ***************************************************************************/
5
6 /***************************************************************************
7  *   This library is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU Lesser General Public License version   *
9  *   2.1 as published by the Free Software Foundation.                     *
10  *                                                                         *
11  *   This library is distributed in the hope that it will be useful, but   *
12  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
14  *   Lesser General Public License for more details.                       *
15  *                                                                         *
16  *   You should have received a copy of the GNU Lesser General Public      *
17  *   License along with this library; if not, write to the Free Software   *
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
19  *   USA                                                                   *
20  *                                                                         *
21  *   Alternatively, this file is available under the Mozilla Public        *
22  *   License Version 1.1.  You may obtain a copy of the License at         *
23  *   http://www.mozilla.org/MPL/                                           *
24  ***************************************************************************/
25
26 #include <stdlib.h>
27
28 #include <bitset>
29
30 #include <tstring.h>
31 #include <tdebug.h>
32 #include <taglib.h>
33
34 #include "oggpageheader.h"
35 #include "oggfile.h"
36
37 using namespace TagLib;
38
39 class Ogg::PageHeader::PageHeaderPrivate
40 {
41 public:
42   PageHeaderPrivate(File *f, long pageOffset) :
43     file(f),
44     fileOffset(pageOffset),
45     isValid(false),
46     firstPacketContinued(false),
47     lastPacketCompleted(false),
48     firstPageOfStream(false),
49     lastPageOfStream(false),
50     absoluteGranularPosition(0),
51     streamSerialNumber(0),
52     pageSequenceNumber(-1),
53     size(0),
54     dataSize(0)
55     {}
56
57   File *file;
58   long fileOffset;
59   bool isValid;
60   List<int> packetSizes;
61   bool firstPacketContinued;
62   bool lastPacketCompleted;
63   bool firstPageOfStream;
64   bool lastPageOfStream;
65   long long absoluteGranularPosition;
66   uint streamSerialNumber;
67   int pageSequenceNumber;
68   int size;
69   int dataSize;
70 };
71
72 ////////////////////////////////////////////////////////////////////////////////
73 // public members
74 ////////////////////////////////////////////////////////////////////////////////
75
76 Ogg::PageHeader::PageHeader(Ogg::File *file, long pageOffset)
77 {
78   d = new PageHeaderPrivate(file, pageOffset);
79   if(file && pageOffset >= 0)
80       read();
81 }
82
83 Ogg::PageHeader::~PageHeader()
84 {
85   delete d;
86 }
87
88 bool Ogg::PageHeader::isValid() const
89 {
90   return d->isValid;
91 }
92
93 List<int> Ogg::PageHeader::packetSizes() const
94 {
95   return d->packetSizes;
96 }
97
98 void Ogg::PageHeader::setPacketSizes(const List<int> &sizes)
99 {
100   d->packetSizes = sizes;
101 }
102
103 bool Ogg::PageHeader::firstPacketContinued() const
104 {
105   return d->firstPacketContinued;
106 }
107
108 void Ogg::PageHeader::setFirstPacketContinued(bool continued)
109 {
110   d->firstPacketContinued = continued;
111 }
112
113 bool Ogg::PageHeader::lastPacketCompleted() const
114 {
115   return d->lastPacketCompleted;
116 }
117
118 void Ogg::PageHeader::setLastPacketCompleted(bool completed)
119 {
120   d->lastPacketCompleted = completed;
121 }
122
123 bool Ogg::PageHeader::firstPageOfStream() const
124 {
125   return d->firstPageOfStream;
126 }
127
128 void Ogg::PageHeader::setFirstPageOfStream(bool first)
129 {
130   d->firstPageOfStream = first;
131 }
132
133 bool Ogg::PageHeader::lastPageOfStream() const
134 {
135   return d->lastPageOfStream;
136 }
137
138 void Ogg::PageHeader::setLastPageOfStream(bool last)
139 {
140   d->lastPageOfStream = last;
141 }
142
143 long long Ogg::PageHeader::absoluteGranularPosition() const
144 {
145   return d->absoluteGranularPosition;
146 }
147
148 void Ogg::PageHeader::setAbsoluteGranularPosition(long long agp)
149 {
150   d->absoluteGranularPosition = agp;
151 }
152
153 int Ogg::PageHeader::pageSequenceNumber() const
154 {
155   return d->pageSequenceNumber;
156 }
157
158 void Ogg::PageHeader::setPageSequenceNumber(int sequenceNumber)
159 {
160   d->pageSequenceNumber = sequenceNumber;
161 }
162
163 TagLib::uint Ogg::PageHeader::streamSerialNumber() const
164 {
165   return d->streamSerialNumber;
166 }
167
168 void Ogg::PageHeader::setStreamSerialNumber(uint n)
169 {
170   d->streamSerialNumber = n;
171 }
172
173 int Ogg::PageHeader::size() const
174 {
175   return d->size;
176 }
177
178 int Ogg::PageHeader::dataSize() const
179 {
180   return d->dataSize;
181 }
182
183 ByteVector Ogg::PageHeader::render() const
184 {
185   ByteVector data;
186
187   // capture patern
188
189   data.append("OggS");
190
191   // stream structure version
192
193   data.append(char(0));
194
195   // header type flag
196
197   std::bitset<8> flags;
198   flags[0] = d->firstPacketContinued;
199   flags[1] = d->pageSequenceNumber == 0;
200   flags[2] = d->lastPageOfStream;
201
202   data.append(char(flags.to_ulong()));
203
204   // absolute granular position
205
206   data.append(ByteVector::fromLongLong(d->absoluteGranularPosition, false));
207
208   // stream serial number
209
210   data.append(ByteVector::fromUInt(d->streamSerialNumber, false));
211
212   // page sequence number
213
214   data.append(ByteVector::fromUInt(d->pageSequenceNumber, false));
215
216   // checksum -- this is left empty and should be filled in by the Ogg::Page
217   // class
218
219   data.append(ByteVector(4, 0));
220
221   // page segment count and page segment table
222
223   ByteVector pageSegments = lacingValues();
224
225   data.append(char(uchar(pageSegments.size())));
226   data.append(pageSegments);
227
228   return data;
229 }
230
231 ////////////////////////////////////////////////////////////////////////////////
232 // private members
233 ////////////////////////////////////////////////////////////////////////////////
234
235 void Ogg::PageHeader::read()
236 {
237   d->file->seek(d->fileOffset);
238
239   // An Ogg page header is at least 27 bytes, so we'll go ahead and read that
240   // much and then get the rest when we're ready for it.
241
242   ByteVector data = d->file->readBlock(27);
243
244   // Sanity check -- make sure that we were in fact able to read as much data as
245   // we asked for and that the page begins with "OggS".
246
247   if(data.size() != 27 || !data.startsWith("OggS")) {
248     debug("Ogg::PageHeader::read() -- error reading page header");
249     return;
250   }
251
252   std::bitset<8> flags(data[5]);
253
254   d->firstPacketContinued = flags.test(0);
255   d->firstPageOfStream = flags.test(1);
256   d->lastPageOfStream = flags.test(2);
257
258   d->absoluteGranularPosition = data.mid(6, 8).toLongLong(false);
259   d->streamSerialNumber = data.mid(14, 4).toUInt(false);
260   d->pageSequenceNumber = data.mid(18, 4).toUInt(false);
261
262   // Byte number 27 is the number of page segments, which is the only variable
263   // length portion of the page header.  After reading the number of page
264   // segments we'll then read in the corresponding data for this count.
265
266   int pageSegmentCount = uchar(data[26]);
267
268   ByteVector pageSegments = d->file->readBlock(pageSegmentCount);
269
270   // Another sanity check.
271
272   if(pageSegmentCount < 1 || int(pageSegments.size()) != pageSegmentCount)
273     return;
274
275   // The base size of an Ogg page 27 bytes plus the number of lacing values.
276
277   d->size = 27 + pageSegmentCount;
278
279   int packetSize = 0;
280
281   for(int i = 0; i < pageSegmentCount; i++) {
282     d->dataSize += uchar(pageSegments[i]);
283     packetSize += uchar(pageSegments[i]);
284
285     if(uchar(pageSegments[i]) < 255) {
286       d->packetSizes.append(packetSize);
287       packetSize = 0;
288     }
289   }
290
291   if(packetSize > 0) {
292     d->packetSizes.append(packetSize);
293     d->lastPacketCompleted = false;
294   }
295   else
296     d->lastPacketCompleted = true;
297
298   d->isValid = true;
299 }
300
301 ByteVector Ogg::PageHeader::lacingValues() const
302 {
303   ByteVector data;
304
305   List<int> sizes = d->packetSizes;
306   for(List<int>::ConstIterator it = sizes.begin(); it != sizes.end(); ++it) {
307
308     // The size of a packet in an Ogg page is indicated by a series of "lacing
309     // values" where the sum of the values is the packet size in bytes.  Each of
310     // these values is a byte.  A value of less than 255 (0xff) indicates the end
311     // of the packet.
312
313     div_t n = div(*it, 255);
314
315     for(int i = 0; i < n.quot; i++)
316       data.append(char(uchar(255)));
317
318     if(it != --sizes.end() || d->lastPacketCompleted)
319       data.append(char(uchar(n.rem)));
320   }
321
322   return data;
323 }