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#include <stdio.h>
26
27#include "MOVAtom.h"
28
29AtomBase::AtomBase(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize)
30{
31	theStream = pStream;
32	streamOffset = pstreamOffset;
33	atomType = patomType;
34	atomSize = patomSize;
35	parentAtom = NULL;
36}
37
38AtomBase::~AtomBase()
39{
40	theStream = NULL;
41	parentAtom = NULL;
42}
43
44char *AtomBase::getAtomName()
45{
46	char *_result;
47	_result = OnGetAtomName();
48	if (_result) {
49		return _result;
50	}
51
52	fourcc[0] = (char)((atomType >> 24) & 0xff);
53	fourcc[1] = (char)((atomType >> 16) & 0xff);
54	fourcc[2] = (char)((atomType >> 8) & 0xff);
55	fourcc[3] = (char)((atomType >> 0) & 0xff);
56	fourcc[4] = '\0';
57
58	return fourcc;
59}
60
61char *AtomBase::OnGetAtomName()
62{
63	return NULL;
64}
65
66void AtomBase::ProcessMetaData()
67//	ProcessMetaData() - Reads in the basic Atom Meta Data
68//				- Calls OnProcessMetaData()
69//				- Calls ProcessMetaData on each child atom
70//				(ensures stream is correct for child via offset)
71{
72	setAtomOffset(getStream()->Position());
73
74	OnProcessMetaData();
75
76	MoveToEnd();
77}
78
79void AtomBase::OnProcessMetaData()
80{
81	MoveToEnd();
82}
83
84bool AtomBase::MoveToEnd()
85{
86	off_t NewPosition = streamOffset + atomSize;
87
88	if (getStream()->Position() != NewPosition) {
89		return (getStream()->Seek(NewPosition,SEEK_SET) > 0);
90	}
91	return true;
92}
93
94uint64	AtomBase::getBytesRemaining()
95{
96	off_t EndPosition = streamOffset + atomSize;
97
98	return (EndPosition - getStream()->Position());
99}
100
101void	AtomBase::DisplayAtoms()
102{
103	uint32 aindent = 0;
104	DisplayAtoms(aindent);
105}
106
107void	AtomBase::DisplayAtoms(uint32 pindent)
108{
109	Indent(pindent);
110	printf("%s\n",getAtomName());
111}
112
113void	AtomBase::Indent(uint32 pindent)
114{
115	for (uint32 i=0;i<pindent;i++) {
116		printf("-");
117	}
118}
119
120bool AtomBase::IsKnown()
121{
122	return (OnGetAtomName() != NULL);
123}
124
125void AtomBase::ReadArrayHeader(array_header *pHeader)
126{
127	Read(&pHeader->Version);
128	Read(&pHeader->Flags1);
129	Read(&pHeader->Flags2);
130	Read(&pHeader->Flags3);
131	Read(&pHeader->NoEntries);
132}
133
134BPositionIO *AtomBase::OnGetStream()
135{
136	// default implementation
137	return theStream;
138}
139
140BPositionIO *AtomBase::getStream()
141{
142	return OnGetStream();
143}
144
145void	AtomBase::Read(uint64	*value)
146{
147	uint32	bytes_read;
148
149	bytes_read = getStream()->Read(value,sizeof(uint64));
150
151	// Assert((bytes_read == sizeof(uint64),"Read Error");
152
153	*value = B_BENDIAN_TO_HOST_INT64(*value);
154}
155
156void	AtomBase::Read(uint32	*value)
157{
158	uint32	bytes_read;
159
160	bytes_read = getStream()->Read(value,sizeof(uint32));
161
162	// Assert((bytes_read == sizeof(uint32),"Read Error");
163
164	*value = B_BENDIAN_TO_HOST_INT32(*value);
165}
166
167void	AtomBase::Read(uint16	*value)
168{
169	uint32	bytes_read;
170
171	bytes_read = getStream()->Read(value,sizeof(uint16));
172
173	// Assert((bytes_read == sizeof(uint16),"Read Error");
174
175	*value = B_BENDIAN_TO_HOST_INT16(*value);
176}
177
178void	AtomBase::Read(uint8	*value)
179{
180	uint32	bytes_read;
181
182	bytes_read = getStream()->Read(value,sizeof(uint8));
183
184	// Assert((bytes_read == sizeof(uint8),"Read Error");
185}
186
187void	AtomBase::Read(char	*value, uint32 maxread)
188{
189	uint32	bytes_read;
190
191	bytes_read = getStream()->Read(value,maxread);
192
193	// Assert((bytes_read == maxread,"Read Error");
194}
195
196void	AtomBase::Read(uint8 *value, uint32 maxread)
197{
198	uint32	bytes_read;
199
200	bytes_read = getStream()->Read(value,maxread);
201
202	// Assert((bytes_read == maxread,"Read Error");
203}
204
205AtomContainer::AtomContainer(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
206{
207	TotalChildren = 0;
208}
209
210AtomContainer::~AtomContainer()
211{
212}
213
214void	AtomContainer::DisplayAtoms(uint32 pindent)
215{
216	Indent(pindent);
217	printf("%ld:%s\n",TotalChildren,getAtomName());
218	pindent++;
219	// for each child
220	for (uint32 i = 0;i < TotalChildren;i++) {
221		atomChildren[i]->DisplayAtoms(pindent);
222	}
223
224}
225
226void	AtomContainer::ProcessMetaData()
227{
228	setAtomOffset(getStream()->Position());
229
230	OnProcessMetaData();
231
232	AtomBase *aChild;
233	while (IsEndOfAtom() == false) {
234		aChild = getAtom(getStream());
235		if (AddChild(aChild)) {
236			aChild->ProcessMetaData();
237		}
238	}
239
240	OnChildProcessingComplete();
241
242	MoveToEnd();
243}
244
245bool	AtomContainer::AddChild(AtomBase *pChildAtom)
246{
247	if (pChildAtom) {
248		pChildAtom->setParent(this);
249		atomChildren[TotalChildren++] = pChildAtom;
250		return true;
251	}
252	return false;
253}
254
255AtomBase *AtomContainer::GetChildAtom(uint32 patomType, uint32 offset)
256{
257	for (uint32 i=0;i<TotalChildren;i++) {
258		if (atomChildren[i]->IsType(patomType)) {
259			// found match, skip if offset non zero.
260			if (offset == 0) {
261				return atomChildren[i];
262			} else {
263				offset--;
264			}
265		} else {
266			if (atomChildren[i]->IsContainer()) {
267				// search container
268				AtomBase *aAtomBase = (dynamic_cast<AtomContainer *>(atomChildren[i])->GetChildAtom(patomType, offset));
269				if (aAtomBase) {
270					// found in container
271					return aAtomBase;
272				}
273				// not found
274			}
275		}
276	}
277	return NULL;
278}
279
280void	AtomContainer::OnProcessMetaData()
281{
282}
283