/*---------------------------------------------------------------------- | AP4_AtomFactory::CreateAtomFromStream +---------------------------------------------------------------------*/ AP4_Result AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, AP4_Atom*& atom) { AP4_Size bytes_available = 0; if (AP4_FAILED(stream.GetSize(bytes_available)) || bytes_available == 0) { bytes_available = (AP4_Size)((unsigned long)(-1)); } return CreateAtomFromStream(stream, bytes_available, atom, NULL); }
/*---------------------------------------------------------------------- | AP4_AtomFactory::CreateAtomFromStream +---------------------------------------------------------------------*/ AP4_Result AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, AP4_Atom*& atom) { AP4_LargeSize stream_size = 0; AP4_Position stream_position = 0; AP4_LargeSize bytes_available = (AP4_LargeSize)(-1); if (AP4_SUCCEEDED(stream.GetSize(stream_size)) && stream_size != 0 && AP4_SUCCEEDED(stream.Tell(stream_position)) && stream_position <= stream_size) { bytes_available = stream_size-stream_position; } return CreateAtomFromStream(stream, bytes_available, atom); }
/*---------------------------------------------------------------------- | AP4_AtomFactory::CreateAtomsFromStream +---------------------------------------------------------------------*/ AP4_Result AP4_AtomFactory::CreateAtomsFromStream(AP4_ByteStream& stream, AP4_LargeSize bytes_available, AP4_AtomParent& atoms) { AP4_Result result; do { AP4_Atom* atom = NULL; result = CreateAtomFromStream(stream, bytes_available, atom); if (AP4_SUCCEEDED(result) && atom != NULL) { atoms.AddChild(atom); } } while (AP4_SUCCEEDED(result)); return AP4_SUCCESS; }
/*---------------------------------------------------------------------- | AP4_AtomFactory::CreateAtomFromStream +---------------------------------------------------------------------*/ AP4_Result AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, AP4_LargeSize& bytes_available, AP4_Atom*& atom) { AP4_Result result; // NULL by default atom = NULL; // check that there are enough bytes for at least a header if (bytes_available < 8) return AP4_ERROR_EOS; // remember current stream offset AP4_Position start; stream.Tell(start); // read atom size AP4_UI32 size_32; result = stream.ReadUI32(size_32); if (AP4_FAILED(result)) { stream.Seek(start); return result; } AP4_UI64 size = size_32; // read atom type AP4_Atom::Type type; result = stream.ReadUI32(type); if (AP4_FAILED(result)) { stream.Seek(start); return result; } // handle special size values bool atom_is_large = false; bool force_64 = false; if (size == 0) { // atom extends to end of file AP4_LargeSize stream_size = 0; stream.GetSize(stream_size); if (stream_size >= start) { size = stream_size - start; } } else if (size == 1) { // 64-bit size atom_is_large = true; if (bytes_available < 16) { stream.Seek(start); return AP4_ERROR_INVALID_FORMAT; } stream.ReadUI64(size); if (size <= 0xFFFFFFFF) { force_64 = true; } } // check the size if ((size > 0 && size < 8) || size > bytes_available) { stream.Seek(start); return AP4_ERROR_INVALID_FORMAT; } // create the atom result = CreateAtomFromStream(stream, type, size_32, size, atom); if (AP4_FAILED(result)) return result; // if we failed to create an atom, use a generic version if (atom == NULL) { unsigned int payload_offset = 8; if (atom_is_large) payload_offset += 8; stream.Seek(start+payload_offset); atom = new AP4_UnknownAtom(type, size, stream); } // special case: if the atom is poorly encoded and has a 64-bit // size header but an actual size that fits on 32-bit, adjust the // object to reflect that. if (force_64) { atom->SetSize32(1); atom->SetSize64(size); } // adjust the available size bytes_available -= size; // skip to the end of the atom result = stream.Seek(start+size); if (AP4_FAILED(result)) { delete atom; atom = NULL; return result; } return AP4_SUCCESS; }