1 /***************************************************************************
2 copyright : (C) 2004-2005 by Allan Sandfeld Jensen
3 email : kde@carewolf.org
4 ***************************************************************************/
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. *
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. *
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 *
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 ***************************************************************************/
26 #include <tbytevector.h>
30 #include <xiphcomment.h>
31 #include "oggflacfile.h"
33 using namespace TagLib;
34 using TagLib::FLAC::Properties;
36 class Ogg::FLAC::File::FilePrivate
45 hasXiphComment(false),
54 Ogg::XiphComment *comment;
56 Properties *properties;
57 ByteVector streamInfoData;
58 ByteVector xiphCommentData;
67 ////////////////////////////////////////////////////////////////////////////////
69 ////////////////////////////////////////////////////////////////////////////////
71 Ogg::FLAC::File::File(FileName file, bool readProperties,
72 Properties::ReadStyle propertiesStyle) : Ogg::File(file)
75 read(readProperties, propertiesStyle);
78 Ogg::FLAC::File::~File()
83 Ogg::XiphComment *Ogg::FLAC::File::tag() const
88 Properties *Ogg::FLAC::File::audioProperties() const
94 bool Ogg::FLAC::File::save()
96 d->xiphCommentData = d->comment->render(false);
98 // Create FLAC metadata-block:
100 // Put the size in the first 32 bit (I assume no more than 24 bit are used)
102 ByteVector v = ByteVector::fromUInt(d->xiphCommentData.size());
104 // Set the type of the metadata-block to be a Xiph / Vorbis comment
108 // Append the comment-data after the 32 bit header
110 v.append(d->xiphCommentData);
112 // Save the packet at the old spot
113 // FIXME: Use padding if size is increasing
115 setPacket(d->commentPacket, v);
117 return Ogg::File::save();
120 ////////////////////////////////////////////////////////////////////////////////
122 ////////////////////////////////////////////////////////////////////////////////
124 void Ogg::FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
126 // Sanity: Check if we really have an Ogg/FLAC file
129 ByteVector oggHeader = packet(0);
131 if (oggHeader.mid(28,4) != "fLaC") {
132 debug("Ogg::FLAC::File::read() -- Not an Ogg/FLAC file");
137 // Look for FLAC metadata, including vorbis comments
147 if(d->hasXiphComment)
148 d->comment = new Ogg::XiphComment(xiphCommentData());
150 d->comment = new Ogg::XiphComment;
154 d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle);
157 ByteVector Ogg::FLAC::File::streamInfoData()
160 return d->streamInfoData;
163 ByteVector Ogg::FLAC::File::xiphCommentData()
166 return d->xiphCommentData;
169 long Ogg::FLAC::File::streamLength()
172 return d->streamLength;
175 void Ogg::FLAC::File::scan()
177 // Scan the metadata pages
188 ByteVector metadataHeader = packet(ipacket);
189 if(metadataHeader.isNull())
194 if (!metadataHeader.startsWith("fLaC")) {
196 if (metadataHeader.mid(1,4) != "FLAC") return;
198 if (metadataHeader[5] != 1) return; // not version 1
200 metadataHeader = metadataHeader.mid(13);
203 // FLAC 1.1.0 & 1.1.1
204 metadataHeader = packet(++ipacket);
206 if(metadataHeader.isNull())
211 header = metadataHeader.mid(0,4);
212 // Header format (from spec):
213 // <1> Last-metadata-block flag
218 // 4 : VORBIS_COMMENT
220 // <24> Length of metadata to follow
222 char blockType = header[0] & 0x7f;
223 bool lastBlock = (header[0] & 0x80) != 0;
224 uint length = header.mid(1, 3).toUInt();
227 // Sanity: First block should be the stream_info metadata
230 debug("Ogg::FLAC::File::scan() -- Invalid Ogg/FLAC stream");
234 d->streamInfoData = metadataHeader.mid(4,length);
236 // Search through the remaining metadata
239 metadataHeader = packet(++ipacket);
241 if(metadataHeader.isNull())
244 header = metadataHeader.mid(0, 4);
245 blockType = header[0] & 0x7f;
246 lastBlock = (header[0] & 0x80) != 0;
247 length = header.mid(1, 3).toUInt();
251 // debug("Ogg::FLAC::File::scan() -- Padding found");
253 else if(blockType == 4) {
254 // debug("Ogg::FLAC::File::scan() -- Vorbis-comments found");
255 d->xiphCommentData = metadataHeader.mid(4, length);
256 d->hasXiphComment = true;
257 d->commentPacket = ipacket;
259 else if(blockType > 5)
260 debug("Ogg::FLAC::File::scan() -- Unknown metadata block");
264 // End of metadata, now comes the datastream
265 d->streamStart = overhead;
266 d->streamLength = File::length() - d->streamStart;