wmatag/wmafile.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002     copyright            : (C) 2005 by Lukas Lalinsky
00003     email                : lalinsky@gmail.com
00004  ***************************************************************************/
00005 
00006 /***************************************************************************
00007  *   This library is free software; you can redistribute it and/or modify  *
00008  *   it  under the terms of the GNU Lesser General Public License version  *
00009  *   2.1 as published by the Free Software Foundation.                     *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful, but   *
00012  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the Free Software   *
00018  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,            *
00019  *   MA  02110-1301  USA                                                   *
00020  ***************************************************************************/
00021 
00022 #include <tstring.h>
00023 #include <wmafile.h>
00024 #include <wmatag.h>
00025 #include <wmaproperties.h>
00026 
00027 using namespace TagLib;
00028 
00029 class WMA::File::FilePrivate
00030 {
00031 public:
00032   FilePrivate(): size(0), offset1(0), offset2(0), size1(0), size2(0),
00033     numObjects(0), tag(0), properties(0) {}
00034   unsigned long long size;
00035   unsigned long offset1, offset2, size1, size2, numObjects;
00036   WMA::Tag *tag; 
00037   WMA::Properties *properties; 
00038 };
00039 
00040 // GUIDs
00041 
00042 struct WMA::GUID 
00043 {
00044   WMA::DWORD v1;
00045   WMA::WORD v2;
00046   WMA::WORD v3;
00047   WMA::BYTE v4[8];
00048   bool operator==(const GUID &g) const { return memcmp(this, &g, sizeof(WMA::GUID)) == 0; }
00049   bool operator!=(const GUID &g) const { return memcmp(this, &g, sizeof(WMA::GUID)) != 0; }
00050   static GUID header;
00051   static GUID fileProperties;
00052   static GUID streamProperties;
00053   static GUID contentDescription;
00054   static GUID extendedContentDescription;
00055   static GUID audioMedia;
00056 }; 
00057 
00058 WMA::GUID WMA::GUID::header = {
00059   0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }
00060 }; 
00061 
00062 WMA::GUID WMA::GUID::fileProperties = {
00063   0x8CABDCA1, 0xA947, 0x11CF, { 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
00064 }; 
00065 
00066 WMA::GUID WMA::GUID::streamProperties = {
00067   0xB7DC0791, 0xA9B7, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
00068 };
00069 
00070 WMA::GUID WMA::GUID::contentDescription = {
00071   0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
00072 }; 
00073 
00074 WMA::GUID WMA::GUID::extendedContentDescription = {
00075   0xD2D0A440, 0xE307, 0x11D2, { 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50 },
00076 }; 
00077 
00078 WMA::GUID WMA::GUID::audioMedia = {
00079   0xF8699E40, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
00080 }; 
00081 
00083 // public members
00085 
00086 WMA::File::File(const char *file, bool readProperties, Properties::ReadStyle propertiesStyle) 
00087   : TagLib::File(file)
00088 {
00089   d = new FilePrivate;
00090   read(readProperties, propertiesStyle);
00091 }
00092 
00093 WMA::File::~File()
00094 {
00095   if(d) {
00096     if (d->tag) 
00097       delete d->tag;
00098     if (d->properties) 
00099       delete d->properties;
00100     delete d;   
00101   }
00102 }
00103 
00104 TagLib::Tag *WMA::File::tag() const
00105 {
00106   return d->tag;
00107 } 
00108 
00109 WMA::Tag *WMA::File::WMATag() const
00110 {
00111   return d->tag;
00112 } 
00113 
00114 WMA::Properties *WMA::File::audioProperties() const
00115 {
00116   return d->properties;
00117 } 
00118 
00119 void WMA::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */)
00120 {
00121   WMA::GUID guid;
00122 
00123   readGUID(guid);
00124   if(guid != GUID::header) {
00125     return;
00126   }
00127 
00128   int length = 0;
00129   int bitrate = 0;
00130   int sampleRate = 0;
00131   int channels = 0;
00132   
00133   d->tag = new WMA::Tag();
00134   if(!d->tag)
00135     return;
00136   
00137   d->size = readQWORD();
00138   d->numObjects = readDWORD(); 
00139   seek(2, Current);
00140     
00141   for(int i = 0; i < (int)d->numObjects; i++) {
00142 
00143     readGUID(guid);
00144     long objectSize = (long)readQWORD();
00145       
00146     if(readProperties && guid == GUID::fileProperties) {
00147 
00148       seek(16+8+8+8, Current);
00149       length = (int)(readQWORD() / 10000000L);
00150       seek(8+8+4+4+4+4, Current);
00151       
00152     }
00153 
00154     else if(readProperties && guid == GUID::streamProperties) {
00155       
00156       long pos = tell();
00157         
00158       readGUID(guid);
00159       if(guid != GUID::audioMedia) {
00160         return; 
00161       }
00162         
00163       seek(16+8+4+4+2+4+2, Current);
00164       channels = readWORD();
00165       sampleRate = readDWORD();
00166       bitrate = readDWORD() * 8 / 1000;
00167         
00168       seek(pos + (long)objectSize - 24);
00169     }
00170       
00171     else if(guid == GUID::extendedContentDescription) {
00172 
00173       d->offset2 = tell() - 16 - 8;
00174       d->size2 = (long)objectSize;
00175 
00176       int numDescriptors = readWORD();
00177         
00178       for(int j = 0; j < numDescriptors; j++) {
00179         WMA::Attribute attr(*this);
00180         d->tag->setAttribute(attr.name().toCString(false), attr);
00181       }
00182       
00183     }
00184       
00185     else if(guid == GUID::contentDescription) {
00186 
00187       d->offset1 = tell() - 16 - 8;
00188       d->size1 = (long)objectSize;
00189 
00190       int titleLength = readWORD();
00191       int artistLength = readWORD();
00192       int copyrightLength = readWORD();
00193       int commentLength = readWORD();
00194       int ratingLength = readWORD();
00195 
00196       String value;
00197       
00198       readString(titleLength, value);
00199       d->tag->setTitle(value);
00200       
00201       readString(artistLength, value);
00202       d->tag->setArtist(value);
00203       
00204       readString(copyrightLength, value);
00205       d->tag->setCopyright(value);
00206       
00207       readString(commentLength, value);
00208       d->tag->setComment(value);
00209       
00210       readString(ratingLength, value);
00211       d->tag->setRating(value);
00212     }
00213       
00214     else {
00215       seek((long)objectSize - 24, Current);
00216     }
00217     
00218   }
00219   
00220   if(readProperties) {
00221     d->properties = new WMA::Properties();
00222     if(d->properties) 
00223       d->properties->set(length, bitrate, sampleRate, channels);
00224   }
00225   
00226 }
00227 
00228 bool WMA::File::save()
00229 {
00230   if(readOnly()) {
00231     return false;
00232   }
00233 
00234   if(d->offset1 == 0) {
00235     d->offset1 = 16 + 8 + 4 + 2;
00236     d->numObjects++;
00237   }
00238 
00239   if(d->offset2 == 0) {
00240     d->offset2 = 16 + 8 + 4 + 2;
00241     d->numObjects++;
00242   }
00243 
00244   ByteVector chunk1 = renderContentDescription();
00245   ByteVector chunk2 = renderExtendedContentDescription();
00246 
00247   if(d->offset1 > d->offset2) {
00248     insert(chunk1, d->offset1, d->size1);
00249     insert(chunk2, d->offset2, d->size2);
00250   }
00251   else {
00252     insert(chunk2, d->offset2, d->size2);
00253     insert(chunk1, d->offset1, d->size1);
00254   }
00255 
00256   insert(ByteVector::fromLongLong(d->size + 
00257                                   (int)(chunk1.size() - d->size1) + 
00258                                   (int)(chunk2.size() - d->size2), false) +
00259          ByteVector::fromUInt(d->numObjects, false), 16, 8 + 4);
00260 
00261   return true;
00262 }
00263 
00265 // protected members
00267 
00268 int WMA::File::readBYTE()
00269 {
00270   ByteVector v = readBlock(1);
00271   return v[0];
00272 }
00273 
00274 int WMA::File::readWORD()
00275 {
00276   ByteVector v = readBlock(2);
00277   return v.toShort(false);
00278 }
00279 
00280 unsigned int WMA::File::readDWORD()
00281 {
00282   ByteVector v = readBlock(4);
00283   return v.toUInt(false);
00284 }
00285 
00286 long long WMA::File::readQWORD()
00287 {
00288   ByteVector v = readBlock(8);
00289   return v.toLongLong(false);
00290 }
00291 
00292 void WMA::File::readGUID(GUID &g)
00293 {
00294   g.v1 = readDWORD();
00295   g.v2 = readWORD();
00296   g.v3 = readWORD();
00297   for(int i = 0; i < 8; i++)
00298     g.v4[i] = readBYTE(); 
00299 }
00300 
00301 void WMA::File::readString(int len, String &s)
00302 {
00303   ByteVector v = readBlock(len);
00304   if(len < 2 || v[len-1] != 0 || v[len-2] != 0)
00305     v.append(ByteVector::fromShort(0));
00306   s = String(v, String::UTF16LE);
00307 }
00308 
00309 ByteVector WMA::File::renderContentDescription()
00310 {
00311   String s;    
00312     
00313   s = d->tag->title();  
00314   ByteVector v1 = s.data(String::UTF16LE);
00315   if(s.size()) {
00316     v1.append((char)0);
00317     v1.append((char)0);
00318   }
00319   
00320   s = d->tag->artist();  
00321   ByteVector v2 = s.data(String::UTF16LE);
00322   if(s.size()) {
00323     v2.append((char)0);
00324     v2.append((char)0);
00325   }
00326   
00327   s = d->tag->copyright();  
00328   ByteVector v3 = s.data(String::UTF16LE);
00329   if(s.size()) {
00330     v3.append((char)0);
00331     v3.append((char)0);
00332   } 
00333   
00334   s = d->tag->comment();  
00335   ByteVector v4 = s.data(String::UTF16LE);
00336   if(s.size()) {
00337     v4.append((char)0);
00338     v4.append((char)0);
00339   }
00340   
00341   s = d->tag->rating();  
00342   ByteVector v5 = s.data(String::UTF16LE);
00343   if(s.size()) {
00344     v5.append((char)0);
00345     v5.append((char)0);
00346   }
00347 
00348   ByteVector data;
00349 
00350   data.append(ByteVector::fromShort(v1.size(), false));
00351   data.append(ByteVector::fromShort(v2.size(), false));
00352   data.append(ByteVector::fromShort(v3.size(), false));
00353   data.append(ByteVector::fromShort(v4.size(), false));
00354   data.append(ByteVector::fromShort(v5.size(), false));
00355 
00356   data.append(v1);
00357   data.append(v2);
00358   data.append(v3);
00359   data.append(v4);
00360   data.append(v5);
00361 
00362   data = ByteVector(reinterpret_cast<const char *>(&GUID::contentDescription), sizeof(GUID))
00363     + ByteVector::fromLongLong(data.size() + 16 + 8, false)
00364     + data;
00365 
00366   return data;
00367 }
00368 
00369 ByteVector WMA::File::renderExtendedContentDescription()
00370 {
00371   ByteVector data;
00372 
00373   data.append(ByteVector::fromShort(d->tag->attributeMap().size(), false));
00374   
00375   WMA::AttributeMap::ConstIterator it = d->tag->attributeMap().begin();
00376   for(; it != d->tag->attributeMap().end(); it++) 
00377     data.append(it->second.render());
00378   
00379   data = ByteVector(reinterpret_cast<const char *>(&GUID::extendedContentDescription), sizeof(GUID))
00380     + ByteVector::fromLongLong(data.size() + 16 + 8, false)
00381     + data;
00382 
00383   return data;
00384 }
00385 
00386 

Generated on Mon Aug 6 21:24:20 2007 for plai by  doxygen 1.5.1