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