1 /*****************************************************************************
2 *
3 * Copyright 2016 Varol Okan. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ****************************************************************************/
18
19 #include <iostream>
20 #include <assert.h>
21 #include <string.h>
22
23 #include "constants.h"
24 #include "container.h"
25
26 #include "sa3d.h"
27
28
Container(uint32_t iPadding)29 Container::Container ( uint32_t iPadding )
30 : Box ( )
31 {
32 m_iType = constants::Container;
33 m_iPadding = iPadding;
34 }
35
~Container()36 Container::~Container ( )
37 {
38 }
39
load(std::fstream & fs,uint32_t iPos,uint32_t iEnd)40 Box *Container::load ( std::fstream &fs, uint32_t iPos, uint32_t iEnd )
41 {
42 // if ( iPos == 0 )
43 // iPos = fs.tellg ( );
44
45 fs.seekg ( iPos );
46 uint32_t iHeaderSize = 8;
47 uint32_t iSize = readUint32 ( fs );
48 char name[4];
49 fs.read ( name, 4 );
50
51 int32_t iArrSize = (int32_t)(sizeof(constants::CONTAINERS_LIST)/sizeof(constants::CONTAINERS_LIST[0]));
52 bool bIsBox = true;
53 for ( auto t=0; t<iArrSize; t++ ) {
54 if ( memcmp ( name, constants::CONTAINERS_LIST[t], 4 ) == 0 ) {
55 bIsBox = false;
56 break;
57 }
58 }
59
60 // Handle the mp4a decompressor setting (wave -> mp4a).
61 if ( memcmp ( name, constants::TAG_MP4A, 4 ) == 0 && iSize == 12 )
62 bIsBox = true;
63
64 if ( bIsBox ) {
65 if ( memcmp ( name, constants::TAG_SA3D, 4 ) == 0 )
66 return SA3DBox::load ( fs, iPos, iEnd );
67 return Box::load ( fs, iPos, iEnd );
68 }
69
70 if( iSize == 1 ) {
71 iSize = (uint32_t)readUint64 ( fs );
72 iHeaderSize = 16;
73 }
74
75 if ( iSize < 8 ) {
76 std::cerr << "Error, invalid size " << iSize << " in " << name << " at " << iPos << std::endl;
77 return NULL;
78 }
79
80 if ( iPos + iSize > iEnd ) {
81 std::cerr << "Error: Container box size exceeds bounds." << std::endl;
82 return NULL;
83 }
84
85 uint32_t iPadding = 0;
86 if ( memcmp ( name, constants::TAG_STSD, 4 ) == 0 )
87 iPadding = 8;
88
89 uint32_t iCurrentPos = 0;
90 int16_t iSampleDescVersion = 0;
91 iArrSize = (int32_t)(sizeof(constants::SOUND_SAMPLE_DESCRIPTIONS)/sizeof(constants::SOUND_SAMPLE_DESCRIPTIONS[0]));
92 for ( auto t=0; t<iArrSize; t++ ) {
93 if ( memcmp ( name, constants::SOUND_SAMPLE_DESCRIPTIONS[t], 4 ) == 0 ) {
94 iCurrentPos = fs.tellg ( );
95 fs.seekg ( iCurrentPos + 8 );
96 fs.read ( (char *)&iSampleDescVersion, 2 );
97 iSampleDescVersion = be16toh ( iSampleDescVersion );
98 fs.seekg ( iCurrentPos );
99
100 switch ( iSampleDescVersion ) {
101 case 0:
102 iPadding = 28;
103 break;
104 case 1:
105 iPadding = 28 + 16;
106 break;
107 case 2:
108 iPadding = 64;
109 break;
110 default:
111 std::cerr << "Unsupported sample description version:" << iSampleDescVersion << std::endl;
112 break;
113 }
114 }
115 }
116 Container *pNewBox = new Container ( );
117 memcpy ( pNewBox->m_name, name, 4 );
118 pNewBox->m_iPosition = iPos;
119 pNewBox->m_iHeaderSize = iHeaderSize;
120 pNewBox->m_iContentSize = iSize - iHeaderSize;
121 pNewBox->m_iPadding = iPadding;
122 pNewBox->m_listContents = load_multiple ( fs, iPos + iHeaderSize + iPadding, iPos + iSize );
123
124 if ( pNewBox->m_listContents.empty ( ) ) {
125 delete pNewBox;
126 return NULL;
127 }
128
129 return pNewBox;
130 }
131
load_multiple(std::fstream & fs,uint32_t iPos,uint32_t iEnd)132 std::vector<Box *> Container::load_multiple ( std::fstream &fs, uint32_t iPos, uint32_t iEnd )
133 {
134 std::vector<Box *> list, empty;
135 while ( iPos < iEnd ) {
136 Box *pBox = load ( fs, iPos, iEnd );
137 if ( ! pBox ) {
138 std::cerr << "Error, failed to load box." << std::endl;
139 clear ( list );
140 return empty;
141 }
142 list.push_back ( pBox );
143 iPos = pBox->m_iPosition + pBox->size ( );
144 }
145 return list;
146 }
147
resize()148 void Container::resize ( )
149 {
150 // Recomputes the box size and recurses on contents."""
151 m_iContentSize = m_iPadding;
152 std::vector<Box *>::iterator it = m_listContents.begin ( );
153 while ( it != m_listContents.end ( ) ) {
154 Box *pBox = *it++;
155 if ( pBox->type ( ) == constants::Container ) {
156 Container *p = (Container *)pBox;
157 p->resize ( );
158 }
159 m_iContentSize += pBox->size ( );
160 }
161 }
162
print_structure(const char * pIndent)163 void Container::print_structure ( const char *pIndent )
164 {
165 // Prints the box structure and recurses on contents."""
166 uint32_t iSize1 = m_iHeaderSize;
167 uint32_t iSize2 = m_iContentSize;
168 std::cout << "{" << pIndent << "} {" << name ( ) << "} [{" << iSize1 << "}, {" << iSize2 << "}]" << std::endl;
169
170 int32_t iCount = m_listContents.size ( );
171 std::string strIndent = pIndent;
172 std::vector<Box *>::iterator it = m_listContents.begin ( );
173 while ( it != m_listContents.end ( ) ) {
174 Box *pBox = *it++;
175 if ( ! pBox )
176 continue;
177 strIndent.replace ( strIndent.begin ( ), strIndent.end ( ), "├", "│" );
178 strIndent.replace ( strIndent.begin ( ), strIndent.end ( ), "└", " " );
179 strIndent.replace ( strIndent.begin ( ), strIndent.end ( ), "─", " " );
180
181 if ( --iCount <= 0 )
182 strIndent += " └──";
183 else
184 strIndent += " ├──";
185 pBox->print_structure ( strIndent.c_str ( ) );
186 }
187 }
188
remove(const char * pName)189 void Container::remove ( const char *pName )
190 {
191 std::vector<Box *> list;
192 m_iContentSize = 0;
193 std::vector<Box *>::iterator it = m_listContents.begin ( );
194 while ( it != m_listContents.end ( ) ) {
195 Box *pBox = *it++;
196 if ( ! pBox )
197 continue;
198 if ( memcmp ( pName, pBox->m_name, 4 ) != 0 ) {
199 list.push_back ( pBox );
200
201 if ( pBox->type ( ) == constants::Container ) {
202 Container *p = (Container *)pBox;
203 p->remove ( pName );
204 }
205 m_iContentSize += pBox->size ( );
206 }
207 else
208 delete pBox;
209 }
210 m_listContents = list;
211 }
212
add(Box * pElement)213 bool Container::add ( Box *pElement )
214 {
215 // Adds an element, merging with containers of the same type.
216 std::vector<Box *>::iterator it = m_listContents.begin ( );
217 while ( it != m_listContents.end ( ) ) {
218 Box *pBox = *it++;
219 if ( memcmp ( pElement->m_name, pBox->m_name, 4 ) == 0 ) {
220 if ( pBox->type ( ) == constants::ContainerLeaf ) {
221 Container *p = (Container *)pBox;
222 return p->merge ( pElement );
223 }
224 std::cerr << "Error, cannot merge leafs." << std::endl;
225 return false;
226 }
227 }
228 m_listContents.push_back ( pElement );
229 return true;
230 }
231
merge(Box * pElem)232 bool Container::merge ( Box *pElem )
233 {
234 assert ( pElem->type ( ) == constants::Container ); // isinstance(element, container_box))
235 Container *pElement = (Container *)pElem;
236 // Merges structure with container.
237 int iRet = memcmp ( m_name, pElement->m_name, 4 );
238 assert ( iRet == 0 );
239 std::vector<Box *>::iterator it = pElement->m_listContents.begin ( );
240 while ( it != pElement->m_listContents.end ( ) ) {
241 Box *pSubElement = *it++;
242 if ( ! add ( pSubElement ) )
243 return false;
244 }
245 return true;
246 }
247
save(std::fstream & fsIn,std::fstream & fsOut,int32_t iDelta)248 void Container::save ( std::fstream &fsIn, std::fstream &fsOut, int32_t iDelta )
249 {
250 // Saves box to out_fh reading uncached content from in_fh.
251 // iDelta : file change size for updating stco and co64 files.
252 if ( m_iHeaderSize == 16 ) {
253 writeUint32 ( fsOut, 1 );
254 fsOut.write ( m_name, 4 );
255 writeUint64 ( fsOut, size ( ) );
256 }
257 else if ( m_iHeaderSize == 8 ) {
258 writeUint32 ( fsOut, size ( ) );
259 fsOut.write ( m_name, 4 );
260 }
261 if ( m_iPadding > 0 ) {
262 fsIn.seekg ( content_start ( ) );
263 Box::tag_copy ( fsIn, fsOut, m_iPadding );
264 }
265
266 std::vector<Box *>::iterator it = m_listContents.begin ( );
267 while ( it != m_listContents.end ( ) ) {
268 Box *pElement = *it++;
269 if ( ! pElement )
270 continue;
271 pElement->save ( fsIn, fsOut, iDelta );
272 }
273 }
274
275