Add M4A to files pattern
[someplayer] / src / taglib / mp4 / mp4atom.cpp
1 /**************************************************************************
2     copyright            : (C) 2007 by Lukáš Lalinský
3     email                : lalinsky@gmail.com
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 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <tdebug.h>
31 #include <tstring.h>
32 #include "mp4atom.h"
33
34 using namespace TagLib;
35
36 const char *MP4::Atom::containers[10] = {
37     "moov", "udta", "mdia", "meta", "ilst",
38     "stbl", "minf", "moof", "traf", "trak",
39 };
40
41 MP4::Atom::Atom(File *file)
42 {
43   offset = file->tell();
44   ByteVector header = file->readBlock(8);
45   if (header.size() != 8) {
46     // The atom header must be 8 bytes long, otherwise there is either
47     // trailing garbage or the file is truncated
48     debug("MP4: Couldn't read 8 bytes of data for atom header");
49     length = 0;
50     file->seek(0, File::End);
51     return;
52   }
53
54   length = header.mid(0, 4).toUInt();
55
56   if (length == 1) {
57     long long longLength = file->readBlock(8).toLongLong();
58     if (longLength >= 8 && longLength <= 0xFFFFFFFF) {
59         // The atom has a 64-bit length, but it's actually a 32-bit value
60         length = (long)longLength;
61     }
62     else {
63         debug("MP4: 64-bit atoms are not supported");
64         length = 0;
65         file->seek(0, File::End);
66         return;
67     }
68   }
69   if (length < 8) {
70     debug("MP4: Invalid atom size");
71     length = 0;
72     file->seek(0, File::End);
73     return;
74   }
75
76   name = header.mid(4, 4);
77
78   for(int i = 0; i < numContainers; i++) {
79     if(name == containers[i]) {
80       if(name == "meta") {
81         file->seek(4, File::Current);
82       }
83       while(file->tell() < offset + length) {
84         MP4::Atom *child = new MP4::Atom(file);
85         children.append(child);
86         if (child->length == 0)
87           return;
88       }
89       return;
90     }
91   }
92
93   file->seek(offset + length);
94 }
95
96 MP4::Atom::~Atom()
97 {
98   for(unsigned int i = 0; i < children.size(); i++) {
99     delete children[i];
100   }
101   children.clear();
102 }
103
104 MP4::Atom *
105 MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4)
106 {
107   if(name1 == 0) {
108     return this;
109   }
110   for(unsigned int i = 0; i < children.size(); i++) {
111     if(children[i]->name == name1) {
112       return children[i]->find(name2, name3, name4);
113     }
114   }
115   return 0;
116 }
117
118 MP4::AtomList
119 MP4::Atom::findall(const char *name, bool recursive)
120 {
121   MP4::AtomList result;
122   for(unsigned int i = 0; i < children.size(); i++) {
123     if(children[i]->name == name) {
124       result.append(children[i]);
125     }
126     if(recursive) {
127       result.append(children[i]->findall(name, recursive));
128     }
129   }
130   return result;
131 }
132
133 bool
134 MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3)
135 {
136   path.append(this);
137   if(name1 == 0) {
138     return true;
139   }
140   for(unsigned int i = 0; i < children.size(); i++) {
141     if(children[i]->name == name1) {
142       return children[i]->path(path, name2, name3);
143     }
144   }
145   return false;
146 }
147
148 MP4::Atoms::Atoms(File *file)
149 {
150   file->seek(0, File::End);
151   long end = file->tell();
152   file->seek(0);
153   while(file->tell() + 8 <= end) {
154     MP4::Atom *atom = new MP4::Atom(file);
155     atoms.append(atom);
156     if (atom->length == 0)
157       break;
158   }
159 }
160
161 MP4::Atoms::~Atoms()
162 {
163   for(unsigned int i = 0; i < atoms.size(); i++) {
164     delete atoms[i];
165   }
166   atoms.clear();
167 }
168
169 MP4::Atom *
170 MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4)
171 {
172   for(unsigned int i = 0; i < atoms.size(); i++) {
173     if(atoms[i]->name == name1) {
174       return atoms[i]->find(name2, name3, name4);
175     }
176   }
177   return 0;
178 }
179
180 MP4::AtomList
181 MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4)
182 {
183   MP4::AtomList path;
184   for(unsigned int i = 0; i < atoms.size(); i++) {
185     if(atoms[i]->name == name1) {
186       if(!atoms[i]->path(path, name2, name3, name4)) {
187         path.clear();
188       }
189       return path;
190     }
191   }
192   return path;
193 }