-
Notifications
You must be signed in to change notification settings - Fork 4
/
container.cc
163 lines (136 loc) · 4.63 KB
/
container.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//
// Created by wlanjie on 2018/2/7.
//
#include "container.h"
#include "atomfactory.h"
namespace mp4 {
Container *Container::Create(Type type,
UI64 size,
bool isFull,
bool force64,
ByteStream &stream,
AtomFactory &factory) {
if (isFull) {
UI08 version;
UI32 flags;
if (size < FULL_ATOM_HEADER_SIZE) return NULL;
if (FAILED(Atom::readFullHeader(stream, version, flags))) return NULL;
// special case for 'meta' atoms, because Apple sometimes creates them as
// regular (non-full) atoms. This is bogus, but we can try to detect it
if (type == ATOM_TYPE_META) {
UI32 phantom_size = (version << 24) | flags;
if (phantom_size >= 8 && size >= 16) {
// version+flags looks like a size. read the next 4 bytes just
// to be sure it is a hdlr atom
UI32 peek;
if (FAILED(stream.readUI32(peek))) return NULL;
if (peek == ATOM_TYPE_HDLR) {
// rewind the stream by 8 bytes
Position position;
stream.tell(position);
stream.seek(position - 8);
// create a non-full container
return new Container(type, size, force64, stream, factory);
} else {
// rewind the stream by 4 bytes
Position position;
stream.tell(position);
stream.seek(position - 4);
}
}
}
return new Container(type, size, force64, version, flags, stream, factory);
} else {
return new Container(type, size, force64, stream, factory);
}
}
Container::Container(Type type) :
Atom(type, ATOM_HEADER_SIZE) {
}
Container::Container(Type type, UI08 version, UI32 flags) :
Atom(type, FULL_ATOM_HEADER_SIZE, version, flags) {
}
Container::Container(Type type, UI64 size, bool force64) :
Atom(type, size, force64) {
}
Container::Container(Type type,
UI64 size,
bool force64,
UI08 version,
UI32 flags) :
Atom(type, size, force64, version, flags) {
}
Container::Container(Type type,
UI64 size,
bool force64,
ByteStream &stream,
AtomFactory &factory) :
Atom(type, size, force64) {
readChildren(factory, stream, size - getHeaderSize());
}
Container::Container(Type type,
UI64 size,
bool force64,
UI08 version,
UI32 flags,
ByteStream &stream,
AtomFactory &factory) :
Atom(type, size, force64, version, flags) {
readChildren(factory, stream, size - getHeaderSize());
}
Atom *
Container::clone() {
Container *clone;
if (isFull) {
clone = new Container(type, version, flags);
} else {
clone = new Container(type);
}
List<Atom>::Item *child_item = children.firstItem();
while (child_item) {
Atom *child_clone = child_item->getData()->clone();
if (child_clone) clone->addChild(child_clone);
child_item = child_item->getNext();
}
return clone;
}
void
Container::readChildren(AtomFactory &atom_factory,
ByteStream &stream,
UI64 size) {
Atom *atom;
LargeSize bytes_available = size;
// save and switch the factory's context
atom_factory.pushContext(type);
while (SUCCEEDED(atom_factory.createAtomFromStream(stream, bytes_available, atom))) {
atom->setParent(this);
children.add(atom);
}
// restore the saved context
atom_factory.popContext();
}
Result Container::writeFields(ByteStream &stream) {
// write all children
return children.apply(AtomListWriter(stream));
}
void Container::onChildChanged(Atom *) {
// remcompute our size
UI64 size = getHeaderSize();
children.apply(AtomSizeAdder(size));
setSize(size);
// update our parent
if (parent) parent->onChildChanged(this);
}
void Container::onChildAdded(Atom *child) {
// update our size
setSize(getSize() + child->getSize());
// update our parent
if (parent) parent->onChildChanged(this);
}
void Container::onChildRemoved(Atom *child) {
// update our size
setSize(getSize() - child->getSize());
// update our parent
if (parent) parent->onChildChanged(this);
}
}