1/*
2 * Copyright (c) 2005, David McPaul
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 *  * Redistributions of source code must retain the above copyright notice,
9 *    this list of conditions and the following disclaimer.
10 *  * Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
23 * OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26
27#include "MP4Atom.h"
28
29#include <stdio.h>
30
31
32AtomBase::AtomBase(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType,
33	uint64 patomSize)
34{
35	theStream = pStream;
36	streamOffset = pstreamOffset;
37	atomType = patomType;
38	atomSize = patomSize;
39	parentAtom = NULL;
40}
41
42
43AtomBase::~AtomBase()
44{
45	theStream = NULL;
46	parentAtom = NULL;
47}
48
49
50char *
51AtomBase::GetAtomTypeAsFourcc()
52{
53	fourcc[0] = (char)((atomType >> 24) & 0xff);
54	fourcc[1] = (char)((atomType >> 16) & 0xff);
55	fourcc[2] = (char)((atomType >> 8) & 0xff);
56	fourcc[3] = (char)((atomType >> 0) & 0xff);
57	fourcc[4] = '\0';
58
59	return fourcc;
60}
61
62
63const char *
64AtomBase::GetAtomName()
65{
66	const char *_result;
67	_result = OnGetAtomName();
68	if (_result) {
69		return _result;
70	}
71
72	fourcc[0] = (char)((atomType >> 24) & 0xff);
73	fourcc[1] = (char)((atomType >> 16) & 0xff);
74	fourcc[2] = (char)((atomType >> 8) & 0xff);
75	fourcc[3] = (char)((atomType >> 0) & 0xff);
76	fourcc[4] = '\0';
77
78	return fourcc;
79}
80
81
82const char *
83AtomBase::OnGetAtomName()
84{
85	return NULL;
86}
87
88
89void
90AtomBase::ProcessMetaData()
91//	ProcessMetaData() - Reads in the basic Atom Meta Data
92//				- Calls OnProcessMetaData()
93//				- Calls ProcessMetaData on each child atom
94//				(ensures stream is correct for child via offset)
95{
96	SetAtomOffset(GetStream()->Position());
97
98	OnProcessMetaData();
99
100	MoveToEnd();
101}
102
103
104void
105AtomBase::OnProcessMetaData()
106{
107	MoveToEnd();
108}
109
110
111bool
112AtomBase::MoveToEnd()
113{
114	off_t NewPosition = streamOffset + atomSize;
115
116	if (GetStream()->Position() != NewPosition) {
117		return (GetStream()->Seek(NewPosition,0) > 0);
118	}
119	return true;
120}
121
122
123uint64
124AtomBase::GetBytesRemaining()
125{
126	off_t EndPosition = streamOffset + atomSize;
127	off_t CurrPosition = GetStream()->Position();
128
129	if (CurrPosition > EndPosition) {
130		printf("ERROR: Read past atom boundary by %Ld bytes\n",
131			CurrPosition - EndPosition);
132		return 0;
133	}
134
135	return (EndPosition - CurrPosition);
136}
137
138
139void
140AtomBase::DisplayAtoms()
141{
142	uint32 aindent = 0;
143	DisplayAtoms(aindent);
144}
145
146
147void
148AtomBase::DisplayAtoms(uint32 pindent)
149{
150	Indent(pindent);
151	printf("(%s)\n",GetAtomName());
152}
153
154
155void
156AtomBase::Indent(uint32 pindent)
157{
158	for (uint32 i=0;i<pindent;i++) {
159		printf("-");
160	}
161}
162
163
164bool
165AtomBase::IsKnown()
166{
167	return (OnGetAtomName() != NULL);
168}
169
170
171void
172AtomBase::ReadArrayHeader(array_header *pHeader)
173{
174	Read(&pHeader->NoEntries);
175}
176
177
178BPositionIO *
179AtomBase::OnGetStream()
180{
181	// default implementation
182	return theStream;
183}
184
185
186BPositionIO *
187AtomBase::GetStream()
188{
189	return OnGetStream();
190}
191
192
193void
194AtomBase::Read(uint64	*value)
195{
196	uint32	bytes_read;
197
198	bytes_read = GetStream()->Read(value,sizeof(uint64));
199
200	// Assert((bytes_read == sizeof(uint64),"Read Error");
201
202	*value = B_BENDIAN_TO_HOST_INT64(*value);
203}
204
205
206void
207AtomBase::Read(uint32	*value)
208{
209	uint32	bytes_read;
210
211	bytes_read = GetStream()->Read(value,sizeof(uint32));
212
213	// Assert((bytes_read == sizeof(uint32),"Read Error");
214
215	*value = B_BENDIAN_TO_HOST_INT32(*value);
216}
217
218
219void
220AtomBase::Read(int32	*value)
221{
222	uint32	bytes_read;
223
224	bytes_read = GetStream()->Read(value,sizeof(int32));
225
226	// Assert((bytes_read == sizeof(int32),"Read Error");
227
228	*value = B_BENDIAN_TO_HOST_INT32(*value);
229}
230
231
232void
233AtomBase::Read(uint16	*value)
234{
235	uint32	bytes_read;
236
237	bytes_read = GetStream()->Read(value,sizeof(uint16));
238
239	// Assert((bytes_read == sizeof(uint16),"Read Error");
240
241	*value = B_BENDIAN_TO_HOST_INT16(*value);
242}
243
244
245void
246AtomBase::Read(uint8	*value)
247{
248	uint32	bytes_read;
249
250	bytes_read = GetStream()->Read(value,sizeof(uint8));
251
252	// Assert((bytes_read == sizeof(uint8),"Read Error");
253}
254
255
256void
257AtomBase::Read(char	*value, uint32 maxread)
258{
259	uint32	bytes_read;
260
261	bytes_read = GetStream()->Read(value,maxread);
262
263	// Assert((bytes_read == maxread,"Read Error");
264}
265
266
267void
268AtomBase::Read(uint8 *value, uint32 maxread)
269{
270	uint32	bytes_read;
271
272	bytes_read = GetStream()->Read(value,maxread);
273
274	// Assert((bytes_read == maxread,"Read Error");
275}
276
277
278uint64
279AtomBase::GetBits(uint64 buffer, uint8 startBit, uint8 totalBits)
280{
281	// startBit should range from 0-63, totalBits should range from 1-64
282	if ((startBit < 64) && (totalBits > 0) && (totalBits <= 64)
283		&& (startBit + totalBits <= 64)) {
284		// Ok pull from the buffer the bits wanted.
285		buffer = buffer << startBit;
286		buffer = buffer >> (64 - (totalBits + startBit) + startBit);
287
288		return buffer;
289	}
290
291	return 0L;
292}
293
294
295uint32
296AtomBase::GetBits(uint32 buffer, uint8 startBit, uint8 totalBits)
297{
298	// startBit should range from 0-31, totalBits should range from 1-32
299	if ((startBit < 32) && (totalBits > 0) && (totalBits <= 32)
300		&& (startBit + totalBits <= 32)) {
301		// Ok pull from the buffer the bits wanted.
302		buffer = buffer << startBit;
303		buffer = buffer >> (32 - (startBit + totalBits) + startBit);
304
305		return buffer;
306	}
307
308	return 0;
309}
310
311
312FullAtom::FullAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType,
313	uint64 patomSize)
314	:
315	AtomBase(pStream, pstreamOffset, patomType, patomSize)
316{
317}
318
319
320FullAtom::~FullAtom()
321{
322}
323
324
325void
326FullAtom::OnProcessMetaData()
327{
328	Read(&Version);
329	Read(&Flags1);
330	Read(&Flags2);
331	Read(&Flags3);
332}
333
334
335AtomContainer::AtomContainer(BPositionIO *pStream, off_t pstreamOffset,
336	uint32 patomType, uint64 patomSize)
337	:
338	AtomBase(pStream, pstreamOffset, patomType, patomSize)
339{
340	TotalChildren = 0;
341}
342
343
344AtomContainer::~AtomContainer()
345{
346}
347
348
349void
350AtomContainer::DisplayAtoms(uint32 pindent)
351{
352	Indent(pindent);
353	printf("%ld:(%s)\n",TotalChildren,GetAtomName());
354	pindent++;
355	// for each child
356	for (uint32 i = 0;i < TotalChildren;i++) {
357		atomChildren[i]->DisplayAtoms(pindent);
358	}
359
360}
361
362
363void
364AtomContainer::ProcessMetaData()
365{
366	SetAtomOffset(GetStream()->Position());
367
368	OnProcessMetaData();
369
370	AtomBase *aChild;
371	while (IsEndOfAtom() == false) {
372		aChild = GetAtom(GetStream());
373		if (AddChild(aChild)) {
374			aChild->ProcessMetaData();
375		}
376	}
377
378	OnChildProcessingComplete();
379
380	MoveToEnd();
381}
382
383
384bool
385AtomContainer::AddChild(AtomBase *pChildAtom)
386{
387	if (pChildAtom) {
388		pChildAtom->SetParent(this);
389		atomChildren.push_back(pChildAtom);
390		TotalChildren++;
391		return true;
392	}
393	return false;
394}
395
396
397AtomBase *AtomContainer::GetChildAtom(uint32 patomType, uint32 offset)
398{
399	for (uint32 i=0;i<TotalChildren;i++) {
400		if (atomChildren[i]->IsType(patomType)) {
401			// found match, skip if offset non zero.
402			if (offset == 0) {
403				return atomChildren[i];
404			} else {
405				offset--;
406			}
407		} else {
408			if (atomChildren[i]->IsContainer()) {
409				// search container
410				AtomBase *aAtomBase = dynamic_cast<AtomContainer *>
411					(atomChildren[i])->GetChildAtom(patomType, offset);
412				if (aAtomBase) {
413					// found in container
414					return aAtomBase;
415				}
416				// not found
417			}
418		}
419	}
420	return NULL;
421}
422
423
424void
425AtomContainer::OnProcessMetaData()
426{
427}
428