1 /*
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  *
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  *
12  * The Original Code is MPEG4IP.
13  *
14  * The Initial Developer of the Original Code is Cisco Systems Inc.
15  * Portions created by Cisco Systems Inc. are
16  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
17  *
18  * Contributor(s):
19  *		Dave Mackie		dmackie@cisco.com
20  */
21 
22 #ifndef __MP4_PROPERTY_INCLUDED__
23 #define __MP4_PROPERTY_INCLUDED__
24 
25 // forward declarations
26 class MP4Atom;
27 
28 class MP4Descriptor;
29 MP4ARRAY_DECL(MP4Descriptor, MP4Descriptor*);
30 
31 enum MP4PropertyType {
32 	Integer8Property,
33 	Integer16Property,
34 	Integer24Property,
35 	Integer32Property,
36 	Integer64Property,
37 	Float32Property,
38 	StringProperty,
39 	BytesProperty,
40 	TableProperty,
41 	DescriptorProperty,
42 };
43 
44 class MP4Property {
45 public:
46 	MP4Property(const char *name = NULL);
47 
~MP4Property()48 	virtual ~MP4Property() { }
49 
GetParentAtom()50 	MP4Atom* GetParentAtom() {
51 		return m_pParentAtom;
52 	}
SetParentAtom(MP4Atom * pParentAtom)53 	virtual void SetParentAtom(MP4Atom* pParentAtom) {
54 		m_pParentAtom = pParentAtom;
55 	}
56 
GetName()57 	const char *GetName() {
58 		return m_name;
59 	}
60 
61 	virtual MP4PropertyType GetType() = 0;
62 
IsReadOnly()63 	bool IsReadOnly() {
64 		return m_readOnly;
65 	}
66 	void SetReadOnly(bool value = true) {
67 		m_readOnly = value;
68 	}
69 
IsImplicit()70 	bool IsImplicit() {
71 		return m_implicit;
72 	}
73 	void SetImplicit(bool value = true) {
74 		m_implicit = value;
75 	}
76 
77 	virtual u_int32_t GetCount() = 0;
78 	virtual void SetCount(u_int32_t count) = 0;
79 
Generate()80 	virtual void Generate() { /* default is a no-op */ };
81 
82 	virtual void Read(MP4File* pFile, u_int32_t index = 0) = 0;
83 
84 	virtual void Write(MP4File* pFile, u_int32_t index = 0) = 0;
85 
86 	virtual void Dump(FILE* pFile, u_int8_t indent,
87 		bool dumpImplicits, u_int32_t index = 0) = 0;
88 
89 	virtual bool FindProperty(const char* name,
90 		MP4Property** ppProperty, u_int32_t* pIndex = NULL);
91 
92 protected:
93 	MP4Atom* m_pParentAtom;
94 	const char* m_name;
95 	bool m_readOnly;
96 	bool m_implicit;
97 };
98 
99 MP4ARRAY_DECL(MP4Property, MP4Property*);
100 
101 class MP4IntegerProperty : public MP4Property {
102 protected:
MP4IntegerProperty(char * name)103 	MP4IntegerProperty(char* name)
104 		: MP4Property(name) { };
105 
106 public:
107 	u_int64_t GetValue(u_int32_t index = 0);
108 
109 	void SetValue(u_int64_t value, u_int32_t index = 0);
110 
111 	void InsertValue(u_int64_t value, u_int32_t index = 0);
112 
113 	void DeleteValue(u_int32_t index = 0);
114 
115 	void IncrementValue(int32_t increment = 1, u_int32_t index = 0);
116 };
117 
118 #define MP4INTEGER_PROPERTY_DECL2(isize, xsize) \
119 	class MP4Integer##xsize##Property : public MP4IntegerProperty { \
120 	public: \
121 		MP4Integer##xsize##Property(char* name) \
122 			: MP4IntegerProperty(name) { \
123 			SetCount(1); \
124 			m_values[0] = 0; \
125 		} \
126 		\
127 		MP4PropertyType GetType() { \
128 			return Integer##xsize##Property; \
129 		} \
130 		\
131 		u_int32_t GetCount() { \
132 			return m_values.Size(); \
133 		} \
134 		void SetCount(u_int32_t count) { \
135 			m_values.Resize(count); \
136 		} \
137 		\
138 		u_int##isize##_t GetValue(u_int32_t index = 0) { \
139 			return m_values[index]; \
140 		} \
141 		\
142 		void SetValue(u_int##isize##_t value, u_int32_t index = 0) { \
143 			if (m_readOnly) { \
144 				throw new MP4Error(EACCES, "property is read-only", m_name); \
145 			} \
146 			m_values[index] = value; \
147 		} \
148 		void AddValue(u_int##isize##_t value) { \
149 			m_values.Add(value); \
150 		} \
151 		void InsertValue(u_int##isize##_t value, u_int32_t index) { \
152 			m_values.Insert(value, index); \
153 		} \
154 		void DeleteValue(u_int32_t index) { \
155 			m_values.Delete(index); \
156 		} \
157 		void IncrementValue(int32_t increment = 1, u_int32_t index = 0) { \
158 			m_values[index] += increment; \
159 		} \
160 		void Read(MP4File* pFile, u_int32_t index = 0) { \
161 			if (m_implicit) { \
162 				return; \
163 			} \
164 			m_values[index] = pFile->ReadUInt##xsize(); \
165 		} \
166 		\
167 		void Write(MP4File* pFile, u_int32_t index = 0) { \
168 			if (m_implicit) { \
169 				return; \
170 			} \
171 			pFile->WriteUInt##xsize(m_values[index]); \
172 		} \
173 		void Dump(FILE* pFile, u_int8_t indent, \
174 			bool dumpImplicits, u_int32_t index = 0); \
175 	\
176 	protected: \
177 		MP4Integer##isize##Array m_values; \
178 	};
179 
180 #define MP4INTEGER_PROPERTY_DECL(size) \
181 	MP4INTEGER_PROPERTY_DECL2(size, size)
182 
183 MP4INTEGER_PROPERTY_DECL(8);
184 MP4INTEGER_PROPERTY_DECL(16);
185 MP4INTEGER_PROPERTY_DECL2(32, 24);
186 MP4INTEGER_PROPERTY_DECL(32);
187 MP4INTEGER_PROPERTY_DECL(64);
188 
189 class MP4BitfieldProperty : public MP4Integer64Property {
190 public:
MP4BitfieldProperty(char * name,u_int8_t numBits)191 	MP4BitfieldProperty(char* name, u_int8_t numBits)
192 		: MP4Integer64Property(name) {
193 		ASSERT(numBits != 0);
194 		ASSERT(numBits <= 64);
195 		m_numBits = numBits;
196 	}
197 
GetNumBits()198 	u_int8_t GetNumBits() {
199 		return m_numBits;
200 	}
SetNumBits(u_int8_t numBits)201 	void SetNumBits(u_int8_t numBits) {
202 		m_numBits = numBits;
203 	}
204 
205 	void Read(MP4File* pFile, u_int32_t index = 0);
206 	void Write(MP4File* pFile, u_int32_t index = 0);
207 	void Dump(FILE* pFile, u_int8_t indent,
208 		 bool dumpImplicits, u_int32_t index = 0);
209 
210 protected:
211 	u_int8_t m_numBits;
212 };
213 
214 class MP4Float32Property : public MP4Property {
215 public:
MP4Float32Property(char * name)216 	MP4Float32Property(char* name)
217 		: MP4Property(name) {
218 		m_useFixed16Format = false;
219 		m_useFixed32Format = false;
220 		SetCount(1);
221 		m_values[0] = 0.0;
222 	}
223 
GetType()224 	MP4PropertyType GetType() {
225 		return Float32Property;
226 	}
227 
GetCount()228 	u_int32_t GetCount() {
229 		return m_values.Size();
230 	}
SetCount(u_int32_t count)231 	void SetCount(u_int32_t count) {
232 		m_values.Resize(count);
233 	}
234 
235 	float GetValue(u_int32_t index = 0) {
236 		return m_values[index];
237 	}
238 
239 	void SetValue(float value, u_int32_t index = 0) {
240 		if (m_readOnly) {
241 			throw new MP4Error(EACCES, "property is read-only", m_name);
242 		}
243 		m_values[index] = value;
244 	}
245 
AddValue(float value)246 	void AddValue(float value) {
247 		m_values.Add(value);
248 	}
249 
InsertValue(float value,u_int32_t index)250 	void InsertValue(float value, u_int32_t index) {
251 		m_values.Insert(value, index);
252 	}
253 
IsFixed16Format()254 	bool IsFixed16Format() {
255 		return m_useFixed16Format;
256 	}
257 
258 	void SetFixed16Format(bool useFixed16Format = true) {
259 		m_useFixed16Format = useFixed16Format;
260 	}
261 
IsFixed32Format()262 	bool IsFixed32Format() {
263 		return m_useFixed32Format;
264 	}
265 
266 	void SetFixed32Format(bool useFixed32Format = true) {
267 		m_useFixed32Format = useFixed32Format;
268 	}
269 
270 	void Read(MP4File* pFile, u_int32_t index = 0);
271 	void Write(MP4File* pFile, u_int32_t index = 0);
272 	void Dump(FILE* pFile, u_int8_t indent,
273 		 bool dumpImplicits, u_int32_t index = 0);
274 
275 protected:
276 	bool m_useFixed16Format;
277 	bool m_useFixed32Format;
278 	MP4Float32Array m_values;
279 };
280 
281 class MP4StringProperty : public MP4Property {
282 public:
283 	MP4StringProperty(char* name,
284 	  bool useCountedFormat = false, bool useUnicode = false);
285 
286 	~MP4StringProperty();
287 
GetType()288 	MP4PropertyType GetType() {
289 		return StringProperty;
290 	}
291 
GetCount()292 	u_int32_t GetCount() {
293 		return m_values.Size();
294 	}
295 
296 	void SetCount(u_int32_t count);
297 
298 	const char* GetValue(u_int32_t index = 0) {
299 		return m_values[index];
300 	}
301 
302 	void SetValue(const char* value, u_int32_t index = 0);
303 
AddValue(const char * value)304 	void AddValue(const char* value) {
305 		u_int32_t count = GetCount();
306 		SetCount(count + 1);
307 		SetValue(value, count);
308 	}
309 
IsCountedFormat()310 	bool IsCountedFormat() {
311 		return m_useCountedFormat;
312 	}
313 
SetCountedFormat(bool useCountedFormat)314 	void SetCountedFormat(bool useCountedFormat) {
315 		m_useCountedFormat = useCountedFormat;
316 	}
317 
IsExpandedCountedFormat()318 	bool IsExpandedCountedFormat() {
319 		return m_useExpandedCount;
320 	}
321 
SetExpandedCountedFormat(bool useExpandedCount)322 	void SetExpandedCountedFormat(bool useExpandedCount) {
323 		m_useExpandedCount = useExpandedCount;
324 	}
325 
IsUnicode()326 	bool IsUnicode() {
327 		return m_useUnicode;
328 	}
329 
SetUnicode(bool useUnicode)330 	void SetUnicode(bool useUnicode) {
331 		m_useUnicode = useUnicode;
332 	}
333 
GetFixedLength()334 	u_int32_t GetFixedLength() {
335 		return m_fixedLength;
336 	}
337 
SetFixedLength(u_int32_t fixedLength)338 	void SetFixedLength(u_int32_t fixedLength) {
339 		m_fixedLength = fixedLength;
340 	}
341 
342 	void Read(MP4File* pFile, u_int32_t index = 0);
343 	void Write(MP4File* pFile, u_int32_t index = 0);
344 	void Dump(FILE* pFile, u_int8_t indent,
345 		 bool dumpImplicits, u_int32_t index = 0);
346 
347 protected:
348 	bool m_useCountedFormat;
349 	bool m_useExpandedCount;
350 	bool m_useUnicode;
351 	u_int32_t m_fixedLength;
352 
353 	MP4StringArray m_values;
354 };
355 
356 class MP4BytesProperty : public MP4Property {
357 public:
358 	MP4BytesProperty(char* name, u_int32_t valueSize = 0,
359                          u_int32_t defaultValueSize = 0);
360 
361 	~MP4BytesProperty();
362 
GetType()363 	MP4PropertyType GetType() {
364 		return BytesProperty;
365 	}
366 
GetCount()367 	u_int32_t GetCount() {
368 		return m_values.Size();
369 	}
370 
371 	void SetCount(u_int32_t count);
372 
373 	void GetValue(u_int8_t** ppValue, u_int32_t* pValueSize,
374 	  u_int32_t index = 0) {
375 		// N.B. caller must free memory
376 		*ppValue = (u_int8_t*)MP4Malloc(m_valueSizes[index]);
377 		memcpy(*ppValue, m_values[index], m_valueSizes[index]);
378 		*pValueSize = m_valueSizes[index];
379 	}
380 
381 	void CopyValue(u_int8_t* pValue, u_int32_t index = 0) {
382 		// N.B. caller takes responsbility for valid pointer
383 		// and sufficient memory at the destination
384 		memcpy(pValue, m_values[index], m_valueSizes[index]);
385 	}
386 
387 	void SetValue(const u_int8_t* pValue, u_int32_t valueSize,
388 		u_int32_t index = 0);
389 
AddValue(const u_int8_t * pValue,u_int32_t valueSize)390 	void AddValue(const u_int8_t* pValue, u_int32_t valueSize) {
391 		u_int32_t count = GetCount();
392 		SetCount(count + 1);
393 		SetValue(pValue, valueSize, count);
394 	}
395 
396 	u_int32_t GetValueSize(u_int32_t valueSize, u_int32_t index = 0) {
397 		return m_valueSizes[index];
398 	}
399 
400 	void SetValueSize(u_int32_t valueSize, u_int32_t index = 0);
401 
GetFixedSize()402 	u_int32_t GetFixedSize() {
403 		return m_fixedValueSize;
404 	}
405 
406 	void SetFixedSize(u_int32_t fixedSize);
407 
408 	void Read(MP4File* pFile, u_int32_t index = 0);
409 	void Write(MP4File* pFile, u_int32_t index = 0);
410 	void Dump(FILE* pFile, u_int8_t indent,
411 		 bool dumpImplicits, u_int32_t index = 0);
412 
413 protected:
414 	u_int32_t		m_fixedValueSize;
415 	u_int32_t		m_defaultValueSize;
416 	MP4Integer32Array	m_valueSizes;
417 	MP4BytesArray		m_values;
418 };
419 
420 class MP4TableProperty : public MP4Property {
421 public:
422 	MP4TableProperty(char* name, MP4IntegerProperty* pCountProperty);
423 
424 	~MP4TableProperty();
425 
GetType()426 	MP4PropertyType GetType() {
427 		return TableProperty;
428 	}
429 
SetParentAtom(MP4Atom * pParentAtom)430 	void SetParentAtom(MP4Atom* pParentAtom) {
431 		m_pParentAtom = pParentAtom;
432 		for (u_int32_t i = 0; i < m_pProperties.Size(); i++) {
433 			m_pProperties[i]->SetParentAtom(pParentAtom);
434 		}
435 	}
436 
437 	void AddProperty(MP4Property* pProperty);
438 
GetProperty(u_int32_t index)439 	MP4Property* GetProperty(u_int32_t index) {
440 		return m_pProperties[index];
441 	}
442 
GetCount()443 	virtual u_int32_t GetCount() {
444 	  return m_pCountProperty->GetValue();
445 	}
SetCount(u_int32_t count)446 	virtual void SetCount(u_int32_t count) {
447 	  m_pCountProperty->SetValue(count);
448 	}
449 
450 	void Read(MP4File* pFile, u_int32_t index = 0);
451 	void Write(MP4File* pFile, u_int32_t index = 0);
452 	void Dump(FILE* pFile, u_int8_t indent,
453 		 bool dumpImplicits, u_int32_t index = 0);
454 
455 	bool FindProperty(const char* name,
456 		MP4Property** ppProperty, u_int32_t* pIndex = NULL);
457 
458 protected:
459 	virtual void ReadEntry(MP4File* pFile, u_int32_t index);
460 	virtual void WriteEntry(MP4File* pFile, u_int32_t index);
461 
462 	bool FindContainedProperty(const char* name,
463 		MP4Property** ppProperty, u_int32_t* pIndex);
464 
465 protected:
466 	MP4IntegerProperty*	m_pCountProperty;
467 	MP4PropertyArray	m_pProperties;
468 };
469 
470 class MP4DescriptorProperty : public MP4Property {
471 public:
472 	MP4DescriptorProperty(char* name = NULL,
473 	  u_int8_t tagsStart = 0, u_int8_t tagsEnd = 0,
474 	  bool mandatory = false, bool onlyOne = false);
475 
476 	~MP4DescriptorProperty();
477 
GetType()478 	MP4PropertyType GetType() {
479 		return DescriptorProperty;
480 	}
481 
482 	void SetParentAtom(MP4Atom* pParentAtom);
483 
SetSizeLimit(u_int64_t sizeLimit)484 	void SetSizeLimit(u_int64_t sizeLimit) {
485 		m_sizeLimit = sizeLimit;
486 	}
487 
GetCount()488 	u_int32_t GetCount() {
489 		return m_pDescriptors.Size();
490 	}
SetCount(u_int32_t count)491 	void SetCount(u_int32_t count) {
492 		m_pDescriptors.Resize(count);
493 	}
494 
495 	void SetTags(u_int8_t tagsStart, u_int8_t tagsEnd = 0) {
496 		m_tagsStart = tagsStart;
497 		m_tagsEnd = tagsEnd ? tagsEnd : tagsStart;
498 	}
499 
500 	MP4Descriptor* AddDescriptor(u_int8_t tag);
501 
AppendDescriptor(MP4Descriptor * pDescriptor)502 	void AppendDescriptor(MP4Descriptor* pDescriptor) {
503 		m_pDescriptors.Add(pDescriptor);
504 	}
505 
506 	void DeleteDescriptor(u_int32_t index);
507 
508 	void Generate();
509 	void Read(MP4File* pFile, u_int32_t index = 0);
510 	void Write(MP4File* pFile, u_int32_t index = 0);
511 	void Dump(FILE* pFile, u_int8_t indent,
512 		 bool dumpImplicits, u_int32_t index = 0);
513 
514 	bool FindProperty(const char* name,
515 		MP4Property** ppProperty, u_int32_t* pIndex = NULL);
516 
517 protected:
518 	virtual MP4Descriptor* CreateDescriptor(u_int8_t tag);
519 
520 	bool FindContainedProperty(const char* name,
521 		MP4Property** ppProperty, u_int32_t* pIndex);
522 
523 protected:
524 	u_int8_t			m_tagsStart;
525 	u_int8_t			m_tagsEnd;
526 	u_int64_t			m_sizeLimit;
527 	bool				m_mandatory;
528 	bool				m_onlyOne;
529 	MP4DescriptorArray	m_pDescriptors;
530 };
531 
532 class MP4QosQualifierProperty : public MP4DescriptorProperty {
533 public:
534 	MP4QosQualifierProperty(char* name = NULL,
535 	  u_int8_t tagsStart = 0, u_int8_t tagsEnd = 0,
536 	  bool mandatory = false, bool onlyOne = false) :
MP4DescriptorProperty(name,tagsStart,tagsEnd,mandatory,onlyOne)537 	MP4DescriptorProperty(name, tagsStart, tagsEnd, mandatory, onlyOne) { }
538 
539 protected:
540 	MP4Descriptor* CreateDescriptor(u_int8_t tag);
541 };
542 
543 #endif /* __MP4_PROPERTY_INCLUDED__ */
544