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