updated swedish translation from peppo
[ardour.git] / libs / taglib / taglib / ogg / oggpage.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 <tstring.h>
27 #include <tdebug.h>
28
29 #include "oggpage.h"
30 #include "oggpageheader.h"
31 #include "oggfile.h"
32
33 using namespace TagLib;
34
35 class Ogg::Page::PagePrivate
36 {
37 public:
38   PagePrivate(File *f = 0, long pageOffset = -1) :
39     file(f),
40     fileOffset(pageOffset),
41     packetOffset(0),
42     header(f, pageOffset),
43     firstPacketIndex(-1)
44   {
45     if(file) {
46       packetOffset = fileOffset + header.size();
47       packetSizes = header.packetSizes();
48       dataSize = header.dataSize();
49     }
50   }
51
52   File *file;
53   long fileOffset;
54   long packetOffset;
55   int dataSize;
56   List<int> packetSizes;
57   PageHeader header;
58   int firstPacketIndex;
59   ByteVectorList packets;
60 };
61
62 ////////////////////////////////////////////////////////////////////////////////
63 // public members
64 ////////////////////////////////////////////////////////////////////////////////
65
66 Ogg::Page::Page(Ogg::File *file, long pageOffset)
67 {
68   d = new PagePrivate(file, pageOffset);
69 }
70
71 Ogg::Page::~Page()
72 {
73   delete d;
74 }
75
76 long Ogg::Page::fileOffset() const
77 {
78   return d->fileOffset;
79 }
80
81 const Ogg::PageHeader *Ogg::Page::header() const
82 {
83   return &d->header;
84 }
85
86 int Ogg::Page::firstPacketIndex() const
87 {
88   return d->firstPacketIndex;
89 }
90
91 void Ogg::Page::setFirstPacketIndex(int index)
92 {
93   d->firstPacketIndex = index;
94 }
95
96 Ogg::Page::ContainsPacketFlags Ogg::Page::containsPacket(int index) const
97 {
98   int lastPacketIndex = d->firstPacketIndex + packetCount() - 1;
99   if(index < d->firstPacketIndex || index > lastPacketIndex)
100     return DoesNotContainPacket;
101
102   ContainsPacketFlags flags = DoesNotContainPacket;
103
104   if(index == d->firstPacketIndex)
105     flags = ContainsPacketFlags(flags | BeginsWithPacket);
106
107   if(index == lastPacketIndex)
108     flags = ContainsPacketFlags(flags | EndsWithPacket);
109
110   // If there's only one page and it's complete:
111
112   if(packetCount() == 1 &&
113      !d->header.firstPacketContinued() &&
114      d->header.lastPacketCompleted())
115   {
116     flags = ContainsPacketFlags(flags | CompletePacket);
117   }
118
119   // Or if the page is (a) the first page and it's complete or (b) the last page
120   // and it's complete or (c) a page in the middle.
121
122   else if((flags & BeginsWithPacket && !d->header.firstPacketContinued()) ||
123           (flags & EndsWithPacket && d->header.lastPacketCompleted()) ||
124           (!(flags & BeginsWithPacket) && !(flags & EndsWithPacket)))
125   {
126     flags = ContainsPacketFlags(flags | CompletePacket);
127   }
128
129   return flags;
130 }
131
132 TagLib::uint Ogg::Page::packetCount() const
133 {
134   return d->header.packetSizes().size();
135 }
136
137 ByteVectorList Ogg::Page::packets() const
138 {
139   if(!d->packets.isEmpty())
140     return d->packets;
141
142   ByteVectorList l;
143
144   if(d->file && d->header.isValid()) {
145
146     d->file->seek(d->packetOffset);
147
148     List<int> packetSizes = d->header.packetSizes();
149
150     List<int>::ConstIterator it = packetSizes.begin();
151     for(; it != packetSizes.end(); ++it)
152       l.append(d->file->readBlock(*it));
153   }
154   else
155     debug("Ogg::Page::packets() -- attempting to read packets from an invalid page.");
156
157   return l;
158 }
159
160 int Ogg::Page::size() const
161 {
162   return d->header.size() + d->header.dataSize();
163 }
164
165 ByteVector Ogg::Page::render() const
166 {
167   ByteVector data;
168
169   data.append(d->header.render());
170
171   if(d->packets.isEmpty()) {
172     if(d->file) {
173       d->file->seek(d->packetOffset);
174       data.append(d->file->readBlock(d->dataSize));
175     }
176     else
177       debug("Ogg::Page::render() -- this page is empty!");
178   }
179   else {
180     ByteVectorList::ConstIterator it = d->packets.begin();
181     for(; it != d->packets.end(); ++it)
182       data.append(*it);
183   }
184
185   // Compute and set the checksum for the Ogg page.  The checksum is taken over
186   // the entire page with the 4 bytes reserved for the checksum zeroed and then
187   // inserted in bytes 22-25 of the page header.
188
189   ByteVector checksum = ByteVector::fromUInt(data.checksum(), false);
190   for(int i = 0; i < 4; i++)
191     data[i + 22] = checksum[i];
192
193   return data;
194 }
195
196 List<Ogg::Page *> Ogg::Page::paginate(const ByteVectorList &packets,
197                                       PaginationStrategy strategy,
198                                       uint streamSerialNumber,
199                                       int firstPage,
200                                       bool firstPacketContinued,
201                                       bool lastPacketCompleted,
202                                       bool containsLastPacket)
203 {
204   List<Page *> l;
205
206   int totalSize = 0;
207
208   for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it)
209     totalSize += (*it).size();
210
211   if(strategy == Repaginate || totalSize + packets.size() > 255 * 256) {
212     debug("Ogg::Page::paginate() -- Sorry!  Repagination is not yet implemented.");
213     return l;
214   }
215
216   // TODO: Handle creation of multiple pages here with appropriate pagination.
217
218   Page *p = new Page(packets, streamSerialNumber, firstPage, firstPacketContinued,
219                      lastPacketCompleted, containsLastPacket);
220   l.append(p);
221
222   return l;
223 }
224
225 ////////////////////////////////////////////////////////////////////////////////
226 // protected members
227 ////////////////////////////////////////////////////////////////////////////////
228
229 Ogg::Page::Page(const ByteVectorList &packets,
230                 uint streamSerialNumber,
231                 int pageNumber,
232                 bool firstPacketContinued,
233                 bool lastPacketCompleted,
234                 bool containsLastPacket)
235 {
236   d = new PagePrivate;
237
238   ByteVector data;
239   List<int> packetSizes;
240
241   d->header.setFirstPageOfStream(pageNumber == 0 && !firstPacketContinued);
242   d->header.setLastPageOfStream(containsLastPacket);
243   d->header.setFirstPacketContinued(firstPacketContinued);
244   d->header.setLastPacketCompleted(lastPacketCompleted);
245   d->header.setStreamSerialNumber(streamSerialNumber);
246   d->header.setPageSequenceNumber(pageNumber);
247
248   // Build a page from the list of packets.
249
250   for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) {
251     packetSizes.append((*it).size());
252     data.append(*it);
253   }
254   d->packets = packets;
255   d->header.setPacketSizes(packetSizes);
256 }