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 MP4V2_IMPL_MP4PROPERTY_H
23 #define MP4V2_IMPL_MP4PROPERTY_H
24 
25 namespace mp4v2 { namespace impl {
26 
27 ///////////////////////////////////////////////////////////////////////////////
28 
29 // forward declarations
30 class MP4Atom;
31 
32 class MP4Descriptor;
33 MP4ARRAY_DECL(MP4Descriptor, MP4Descriptor*);
34 
35 enum MP4PropertyType {
36     Integer8Property,
37     Integer16Property,
38     Integer24Property,
39     Integer32Property,
40     Integer64Property,
41     Float32Property,
42     StringProperty,
43     BytesProperty,
44     TableProperty,
45     DescriptorProperty,
46     LanguageCodeProperty,
47     BasicTypeProperty,
48 };
49 
50 class MP4Property {
51 public:
52     MP4Property(MP4Atom& parentAtom, const char *name = NULL);
53 
~MP4Property()54     virtual ~MP4Property() { }
55 
GetParentAtom()56     MP4Atom& GetParentAtom() {
57         return m_parentAtom;
58     }
59 
GetName()60     const char *GetName() {
61         return m_name;
62     }
63 
64     virtual MP4PropertyType GetType() = 0;
65 
IsReadOnly()66     bool IsReadOnly() {
67         return m_readOnly;
68     }
69     void SetReadOnly(bool value = true) {
70         m_readOnly = value;
71     }
72 
IsImplicit()73     bool IsImplicit() {
74         return m_implicit;
75     }
76     void SetImplicit(bool value = true) {
77         m_implicit = value;
78     }
79 
80     virtual uint32_t GetCount() = 0;
81     virtual void SetCount(uint32_t count) = 0;
82 
Generate()83     virtual void Generate() { /* default is a no-op */ };
84 
85     virtual void Read(MP4File& file, uint32_t index = 0) = 0;
86 
87     virtual void Write(MP4File& file, uint32_t index = 0) = 0;
88 
89     virtual void Dump(uint8_t indent,
90                       bool dumpImplicits, uint32_t index = 0) = 0;
91 
92     virtual bool FindProperty(const char* name,
93                               MP4Property** ppProperty, uint32_t* pIndex = NULL);
94 
95 protected:
96     MP4Atom& m_parentAtom;
97     const char* m_name;
98     bool m_readOnly;
99     bool m_implicit;
100 
101 private:
102     MP4Property();
103     MP4Property ( const MP4Property &src );
104     MP4Property &operator= ( const MP4Property &src );
105 };
106 
107 MP4ARRAY_DECL(MP4Property, MP4Property*);
108 
109 class MP4IntegerProperty : public MP4Property {
110 protected:
MP4IntegerProperty(MP4Atom & parentAtom,const char * name)111     MP4IntegerProperty(MP4Atom& parentAtom, const char* name)
112             : MP4Property(parentAtom, name) { };
113 
114 public:
115     uint64_t GetValue(uint32_t index = 0);
116 
117     void SetValue(uint64_t value, uint32_t index = 0);
118 
119     void InsertValue(uint64_t value, uint32_t index = 0);
120 
121     void DeleteValue(uint32_t index = 0);
122 
123     void IncrementValue(int32_t increment = 1, uint32_t index = 0);
124 
125 private:
126     MP4IntegerProperty();
127     MP4IntegerProperty ( const MP4IntegerProperty &src );
128     MP4IntegerProperty &operator= ( const MP4IntegerProperty &src );
129 };
130 
131 #define MP4INTEGER_PROPERTY_DECL2(isize, xsize) \
132     class MP4Integer##xsize##Property : public MP4IntegerProperty { \
133     public: \
134         MP4Integer##xsize##Property(MP4Atom& parentAtom, const char* name) \
135             : MP4IntegerProperty(parentAtom, name) { \
136             SetCount(1); \
137             m_values[0] = 0; \
138         } \
139         \
140         MP4PropertyType GetType() { \
141             return Integer##xsize##Property; \
142         } \
143         \
144         uint32_t GetCount() { \
145             return m_values.Size(); \
146         } \
147         void SetCount(uint32_t count) { \
148             m_values.Resize(count); \
149         } \
150         \
151         uint##isize##_t GetValue(uint32_t index = 0) { \
152             return m_values[index]; \
153         } \
154         \
155         void SetValue(uint##isize##_t value, uint32_t index = 0) { \
156             if (m_readOnly) { \
157                 ostringstream msg; \
158                 msg << "property is read-only: " << m_name; \
159                 throw new PlatformException(msg.str().c_str(), EACCES, __FILE__, __LINE__, __FUNCTION__); \
160             } \
161             m_values[index] = value; \
162         } \
163         void AddValue(uint##isize##_t value) { \
164             m_values.Add(value); \
165         } \
166         void InsertValue(uint##isize##_t value, uint32_t index) { \
167             m_values.Insert(value, index); \
168         } \
169         void DeleteValue(uint32_t index) { \
170             m_values.Delete(index); \
171         } \
172         void IncrementValue(int32_t increment = 1, uint32_t index = 0) { \
173             m_values[index] += increment; \
174         } \
175         void Read(MP4File& file, uint32_t index = 0) { \
176             if (m_implicit) { \
177                 return; \
178             } \
179             m_values[index] = file.ReadUInt##xsize(); \
180         } \
181         \
182         void Write(MP4File& file, uint32_t index = 0) { \
183             if (m_implicit) { \
184                 return; \
185             } \
186             file.WriteUInt##xsize(m_values[index]); \
187         } \
188         void Dump(uint8_t indent, \
189             bool dumpImplicits, uint32_t index = 0); \
190     \
191     protected: \
192         MP4Integer##isize##Array m_values; \
193     private: \
194         MP4Integer##xsize##Property(); \
195         MP4Integer##xsize##Property ( const MP4Integer##xsize##Property &src ); \
196         MP4Integer##xsize##Property &operator= ( const MP4Integer##xsize##Property &src ); \
197     };
198 
199 #define MP4INTEGER_PROPERTY_DECL(size) \
200     MP4INTEGER_PROPERTY_DECL2(size, size)
201 
202 MP4INTEGER_PROPERTY_DECL(8);
203 MP4INTEGER_PROPERTY_DECL(16);
204 MP4INTEGER_PROPERTY_DECL2(32, 24);
205 MP4INTEGER_PROPERTY_DECL(32);
206 MP4INTEGER_PROPERTY_DECL(64);
207 
208 class MP4BitfieldProperty : public MP4Integer64Property {
209 public:
MP4BitfieldProperty(MP4Atom & parentAtom,const char * name,uint8_t numBits)210     MP4BitfieldProperty(MP4Atom& parentAtom, const char* name, uint8_t numBits)
211             : MP4Integer64Property(parentAtom, name) {
212         ASSERT(numBits != 0);
213         ASSERT(numBits <= 64);
214         m_numBits = numBits;
215     }
216 
GetNumBits()217     uint8_t GetNumBits() {
218         return m_numBits;
219     }
SetNumBits(uint8_t numBits)220     void SetNumBits(uint8_t numBits) {
221         m_numBits = numBits;
222     }
223 
224     void Read(MP4File& file, uint32_t index = 0);
225     void Write(MP4File& file, uint32_t index = 0);
226     void Dump(uint8_t indent,
227               bool dumpImplicits, uint32_t index = 0);
228 
229 protected:
230     uint8_t m_numBits;
231 
232 private:
233     MP4BitfieldProperty();
234     MP4BitfieldProperty ( const MP4BitfieldProperty &src );
235     MP4BitfieldProperty &operator= ( const MP4BitfieldProperty &src );
236 };
237 
238 class MP4Float32Property : public MP4Property {
239 public:
MP4Float32Property(MP4Atom & parentAtom,const char * name)240     MP4Float32Property(MP4Atom& parentAtom, const char* name)
241             : MP4Property(parentAtom, name) {
242         m_useFixed16Format = false;
243         m_useFixed32Format = false;
244         SetCount(1);
245         m_values[0] = 0.0;
246     }
247 
GetType()248     MP4PropertyType GetType() {
249         return Float32Property;
250     }
251 
GetCount()252     uint32_t GetCount() {
253         return m_values.Size();
254     }
SetCount(uint32_t count)255     void SetCount(uint32_t count) {
256         m_values.Resize(count);
257     }
258 
259     float GetValue(uint32_t index = 0) {
260         return m_values[index];
261     }
262 
263     void SetValue(float value, uint32_t index = 0) {
264         if (m_readOnly) {
265             ostringstream msg;
266             msg << "property is read-only: " << m_name;
267             throw new PlatformException(msg.str().c_str(), EACCES, __FILE__, __LINE__, __FUNCTION__);
268         }
269         m_values[index] = value;
270     }
271 
AddValue(float value)272     void AddValue(float value) {
273         m_values.Add(value);
274     }
275 
InsertValue(float value,uint32_t index)276     void InsertValue(float value, uint32_t index) {
277         m_values.Insert(value, index);
278     }
279 
IsFixed16Format()280     bool IsFixed16Format() {
281         return m_useFixed16Format;
282     }
283 
284     void SetFixed16Format(bool useFixed16Format = true) {
285         m_useFixed16Format = useFixed16Format;
286     }
287 
IsFixed32Format()288     bool IsFixed32Format() {
289         return m_useFixed32Format;
290     }
291 
292     void SetFixed32Format(bool useFixed32Format = true) {
293         m_useFixed32Format = useFixed32Format;
294     }
295 
296     void Read(MP4File& file, uint32_t index = 0);
297     void Write(MP4File& file, uint32_t index = 0);
298     void Dump(uint8_t indent,
299               bool dumpImplicits, uint32_t index = 0);
300 
301 protected:
302     bool m_useFixed16Format;
303     bool m_useFixed32Format;
304     MP4Float32Array m_values;
305 
306 private:
307     MP4Float32Property();
308     MP4Float32Property ( const MP4Float32Property &src );
309     MP4Float32Property &operator= ( const MP4Float32Property &src );
310 };
311 
312 class MP4StringProperty : public MP4Property {
313 public:
314     MP4StringProperty(MP4Atom& parentAtom, const char* name,
315                       bool useCountedFormat = false, bool useUnicode = false, bool arrayMode = false);
316 
317     ~MP4StringProperty();
318 
GetType()319     MP4PropertyType GetType() {
320         return StringProperty;
321     }
322 
GetCount()323     uint32_t GetCount() {
324         return m_values.Size();
325     }
326 
327     void SetCount(uint32_t count);
328 
329     const char* GetValue(uint32_t index = 0) {
330         return m_values[index];
331     }
332 
333     void SetValue(const char* value, uint32_t index = 0);
334 
AddValue(const char * value)335     void AddValue(const char* value) {
336         uint32_t count = GetCount();
337         SetCount(count + 1);
338         SetValue(value, count);
339     }
340 
IsCountedFormat()341     bool IsCountedFormat() {
342         return m_useCountedFormat;
343     }
344 
SetCountedFormat(bool useCountedFormat)345     void SetCountedFormat(bool useCountedFormat) {
346         m_useCountedFormat = useCountedFormat;
347     }
348 
IsExpandedCountedFormat()349     bool IsExpandedCountedFormat() {
350         return m_useExpandedCount;
351     }
352 
SetExpandedCountedFormat(bool useExpandedCount)353     void SetExpandedCountedFormat(bool useExpandedCount) {
354         m_useExpandedCount = useExpandedCount;
355     }
356 
IsUnicode()357     bool IsUnicode() {
358         return m_useUnicode;
359     }
360 
SetUnicode(bool useUnicode)361     void SetUnicode(bool useUnicode) {
362         m_useUnicode = useUnicode;
363     }
364 
GetFixedLength()365     uint32_t GetFixedLength() {
366         return m_fixedLength;
367     }
368 
SetFixedLength(uint32_t fixedLength)369     void SetFixedLength(uint32_t fixedLength) {
370         m_fixedLength = fixedLength;
371     }
372 
373     void Read(MP4File& file, uint32_t index = 0);
374     void Write(MP4File& file, uint32_t index = 0);
375     void Dump(uint8_t indent,
376               bool dumpImplicits, uint32_t index = 0);
377 
378 protected:
379     bool m_arrayMode; // during read/write ignore index and read/write full array
380     bool m_useCountedFormat;
381     bool m_useExpandedCount;
382     bool m_useUnicode;
383     uint32_t m_fixedLength;
384 
385     MP4StringArray m_values;
386 
387 private:
388     MP4StringProperty();
389     MP4StringProperty ( const MP4StringProperty &src );
390     MP4StringProperty &operator= ( const MP4StringProperty &src );
391 };
392 
393 class MP4BytesProperty : public MP4Property {
394 public:
395     MP4BytesProperty(MP4Atom& parentAtom, const char* name, uint32_t valueSize = 0,
396                      uint32_t defaultValueSize = 0);
397 
398     ~MP4BytesProperty();
399 
GetType()400     MP4PropertyType GetType() {
401         return BytesProperty;
402     }
403 
GetCount()404     uint32_t GetCount() {
405         return m_values.Size();
406     }
407 
408     void SetCount(uint32_t count);
409 
410     void GetValue(uint8_t** ppValue, uint32_t* pValueSize,
411                   uint32_t index = 0) {
412         // N.B. caller must free memory
413         *ppValue = (uint8_t*)MP4Malloc(m_valueSizes[index]);
414         memcpy(*ppValue, m_values[index], m_valueSizes[index]);
415         *pValueSize = m_valueSizes[index];
416     }
417 
418     char* GetValueStringAlloc( uint32_t index = 0 ) {
419         char* buf = (char*)MP4Malloc( m_valueSizes[index] + 1 );
420         memcpy( buf, m_values[index], m_valueSizes[index] );
421         buf[m_valueSizes[index]] = '\0';
422         return buf;
423     }
424 
425     bool CompareToString( const string& s, uint32_t index = 0 ) {
426         return string( (const char*)m_values[index], m_valueSizes[index] ) != s;
427     }
428 
429     void CopyValue(uint8_t* pValue, uint32_t index = 0) {
430         // N.B. caller takes responsbility for valid pointer
431         // and sufficient memory at the destination
432         memcpy(pValue, m_values[index], m_valueSizes[index]);
433     }
434 
435     void SetValue(const uint8_t* pValue, uint32_t valueSize,
436                   uint32_t index = 0);
437 
AddValue(const uint8_t * pValue,uint32_t valueSize)438     void AddValue(const uint8_t* pValue, uint32_t valueSize) {
439         uint32_t count = GetCount();
440         SetCount(count + 1);
441         SetValue(pValue, valueSize, count);
442     }
443 
444     uint32_t GetValueSize( uint32_t index = 0 ) {
445         return m_valueSizes[index];
446     }
447 
448     void SetValueSize(uint32_t valueSize, uint32_t index = 0);
449 
GetFixedSize()450     uint32_t GetFixedSize() {
451         return m_fixedValueSize;
452     }
453 
454     void SetFixedSize(uint32_t fixedSize);
455 
456     void Read(MP4File& file, uint32_t index = 0);
457     void Write(MP4File& file, uint32_t index = 0);
458     void Dump(uint8_t indent,
459               bool dumpImplicits, uint32_t index = 0);
460 
461 protected:
462     uint32_t        m_fixedValueSize;
463     uint32_t        m_defaultValueSize;
464     MP4Integer32Array   m_valueSizes;
465     MP4BytesArray       m_values;
466 
467 private:
468     MP4BytesProperty();
469     MP4BytesProperty ( const MP4BytesProperty &src );
470     MP4BytesProperty &operator= ( const MP4BytesProperty &src );
471 };
472 
473 class MP4TableProperty : public MP4Property {
474 public:
475     MP4TableProperty(MP4Atom& parentAtom, const char* name, MP4IntegerProperty* pCountProperty);
476 
477     ~MP4TableProperty();
478 
GetType()479     MP4PropertyType GetType() {
480         return TableProperty;
481     }
482 
483     void AddProperty(MP4Property* pProperty);
484 
GetProperty(uint32_t index)485     MP4Property* GetProperty(uint32_t index) {
486         return m_pProperties[index];
487     }
488 
GetCount()489     virtual uint32_t GetCount() {
490         return m_pCountProperty->GetValue();
491     }
SetCount(uint32_t count)492     virtual void SetCount(uint32_t count) {
493         m_pCountProperty->SetValue(count);
494     }
495 
496     void Read(MP4File& file, uint32_t index = 0);
497     void Write(MP4File& file, uint32_t index = 0);
498     void Dump(uint8_t indent,
499               bool dumpImplicits, uint32_t index = 0);
500 
501     bool FindProperty(const char* name,
502                       MP4Property** ppProperty, uint32_t* pIndex = NULL);
503 
504 protected:
505     virtual void ReadEntry(MP4File& file, uint32_t index);
506     virtual void WriteEntry(MP4File& file, uint32_t index);
507 
508     bool FindContainedProperty(const char* name,
509                                MP4Property** ppProperty, uint32_t* pIndex);
510 
511 protected:
512     MP4IntegerProperty* m_pCountProperty;
513     MP4PropertyArray    m_pProperties;
514 
515 private:
516     MP4TableProperty();
517     MP4TableProperty ( const MP4TableProperty &src );
518     MP4TableProperty &operator= ( const MP4TableProperty &src );
519 };
520 
521 class MP4DescriptorProperty : public MP4Property {
522 public:
523     MP4DescriptorProperty(MP4Atom& parentAtom, const char* name = NULL,
524                           uint8_t tagsStart = 0, uint8_t tagsEnd = 0,
525                           bool mandatory = false, bool onlyOne = false);
526 
527     ~MP4DescriptorProperty();
528 
GetType()529     MP4PropertyType GetType() {
530         return DescriptorProperty;
531     }
532 
533     void SetParentAtom(MP4Atom* pParentAtom);
534 
SetSizeLimit(uint64_t sizeLimit)535     void SetSizeLimit(uint64_t sizeLimit) {
536         m_sizeLimit = sizeLimit;
537     }
538 
GetCount()539     uint32_t GetCount() {
540         return m_pDescriptors.Size();
541     }
SetCount(uint32_t count)542     void SetCount(uint32_t count) {
543         m_pDescriptors.Resize(count);
544     }
545 
546     void SetTags(uint8_t tagsStart, uint8_t tagsEnd = 0) {
547         m_tagsStart = tagsStart;
548         m_tagsEnd = tagsEnd ? tagsEnd : tagsStart;
549     }
550 
551     MP4Descriptor* AddDescriptor(uint8_t tag);
552 
AppendDescriptor(MP4Descriptor * pDescriptor)553     void AppendDescriptor(MP4Descriptor* pDescriptor) {
554         m_pDescriptors.Add(pDescriptor);
555     }
556 
557     void DeleteDescriptor(uint32_t index);
558 
559     void Generate();
560     void Read(MP4File& file, uint32_t index = 0);
561     void Write(MP4File& file, uint32_t index = 0);
562     void Dump(uint8_t indent,
563               bool dumpImplicits, uint32_t index = 0);
564 
565     bool FindProperty(const char* name,
566                       MP4Property** ppProperty, uint32_t* pIndex = NULL);
567 
568 protected:
569     virtual MP4Descriptor* CreateDescriptor(MP4Atom& parentAtom, uint8_t tag);
570 
571     bool FindContainedProperty(const char* name,
572                                MP4Property** ppProperty, uint32_t* pIndex);
573 
574 protected:
575     uint8_t         m_tagsStart;
576     uint8_t         m_tagsEnd;
577     uint64_t            m_sizeLimit;
578     bool                m_mandatory;
579     bool                m_onlyOne;
580     MP4DescriptorArray  m_pDescriptors;
581 
582 private:
583     MP4DescriptorProperty();
584     MP4DescriptorProperty ( const MP4DescriptorProperty &src );
585     MP4DescriptorProperty &operator= ( const MP4DescriptorProperty &src );
586 };
587 
588 class MP4QosQualifierProperty : public MP4DescriptorProperty {
589 public:
590     MP4QosQualifierProperty(MP4Atom& parentAtom, const char* name = NULL,
591                             uint8_t tagsStart = 0, uint8_t tagsEnd = 0,
592                             bool mandatory = false, bool onlyOne = false) :
MP4DescriptorProperty(parentAtom,name,tagsStart,tagsEnd,mandatory,onlyOne)593             MP4DescriptorProperty(parentAtom, name, tagsStart, tagsEnd, mandatory, onlyOne) { }
594 
595 protected:
596     MP4Descriptor* CreateDescriptor(MP4Atom& parentAtom, uint8_t tag);
597 
598 private:
599     MP4QosQualifierProperty();
600     MP4QosQualifierProperty ( const MP4QosQualifierProperty &src );
601     MP4QosQualifierProperty &operator= ( const MP4QosQualifierProperty &src );
602 };
603 
604 ///////////////////////////////////////////////////////////////////////////////
605 
606 /// ISO-639-2/T language code.
607 /// Language codes are 3-alpha (always lowercase) codes which are then
608 /// offset using 0x60 and packed as 5-bit values into 16-bits, most
609 /// significant bit is zero-padding.
610 
611 class MP4LanguageCodeProperty : public MP4Property {
612 private:
613     bmff::LanguageCode _value;
614 
615 public:
616     explicit MP4LanguageCodeProperty( MP4Atom& parentAtom, const char* , bmff::LanguageCode = bmff::ILC_UND );
617     MP4LanguageCodeProperty( MP4Atom& parentAtom, const char* , const string& );
618 
619     MP4PropertyType GetType();
620     uint32_t        GetCount();
621     void            SetCount( uint32_t );
622     void            Read( MP4File&, uint32_t = 0 );
623     void            Write( MP4File&, uint32_t = 0 );
624     void            Dump( uint8_t, bool, uint32_t = 0 );
625 
626     bmff::LanguageCode GetValue();
627     void               SetValue( bmff::LanguageCode );
628 
629 private:
630     MP4LanguageCodeProperty();
631     MP4LanguageCodeProperty ( const MP4LanguageCodeProperty &src );
632     MP4LanguageCodeProperty &operator= ( const MP4LanguageCodeProperty &src );
633 };
634 
635 ///////////////////////////////////////////////////////////////////////////////
636 
637 class MP4BasicTypeProperty : public MP4Property {
638 private:
639     itmf::BasicType _value;
640 
641 public:
642     explicit MP4BasicTypeProperty( MP4Atom& parentAtom, const char* , itmf::BasicType = itmf::BT_UNDEFINED );
643 
644     MP4PropertyType GetType();
645     uint32_t        GetCount();
646     void            SetCount( uint32_t );
647     void            Read( MP4File&, uint32_t = 0 );
648     void            Write( MP4File&, uint32_t = 0 );
649     void            Dump( uint8_t, bool, uint32_t = 0 );
650     itmf::BasicType GetValue();
651     void            SetValue( itmf::BasicType );
652 
653 private:
654     MP4BasicTypeProperty();
655     MP4BasicTypeProperty ( const MP4BasicTypeProperty &src );
656     MP4BasicTypeProperty &operator= ( const MP4BasicTypeProperty &src );
657 };
658 
659 ///////////////////////////////////////////////////////////////////////////////
660 
661 }} // namespace mp4v2::impl
662 
663 #endif // MP4V2_IMPL_MP4PROPERTY_H
664