a9793ba02a1c0f9d41e91341a50c8ec2b6000504
[libdcp.git] / asdcplib / src / KM_util.h
1 /*
2 Copyright (c) 2005-2012, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27   /*! \file    KM_util.h
28     \version $Id: KM_util.h,v 1.32 2012/02/21 02:09:30 jhurst Exp $
29     \brief   Utility functions
30   */
31
32 #ifndef _KM_UTIL_H_
33 #define _KM_UTIL_H_
34
35 #include <KM_memio.h>
36 #include <KM_error.h>
37 #include <KM_tai.h>
38 #include <string.h>
39 #include <string>
40 #include <list>
41
42 namespace Kumu
43 {
44   extern bool libdcp_test;
45         
46   // The version number declaration and explanation are in ../configure.ac
47   const char* Version();
48
49   // a class that represents the string form of a value
50   template <class T, int SIZE = 16>
51     class IntPrinter : public std::string
52   {
53     KM_NO_COPY_CONSTRUCT(IntPrinter);
54     IntPrinter();
55
56     protected:
57     const char* m_format;
58     char m_strbuf[SIZE];
59     
60     public:
61     IntPrinter(const char* format, T value) {
62       assert(format);
63       m_format = format;
64       snprintf(m_strbuf, SIZE, m_format, value);
65     }
66
67     inline operator const char*() { return m_strbuf; }
68     inline const char* c_str() { return m_strbuf; }
69     inline const char* set_value(T value) {
70       snprintf(m_strbuf, SIZE, m_format, value);
71       return m_strbuf;
72     }
73   };
74
75   struct i8Printer : public IntPrinter<i8_t> {
76     i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {}
77   };
78
79   struct ui8Printer : public IntPrinter<ui8_t> {
80     ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {}
81   };
82
83   struct i16Printer : public IntPrinter<i16_t> {
84     i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {}
85   };
86
87   struct ui16Printer : public IntPrinter<ui16_t> {
88     ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {}
89   };
90
91   struct i32Printer : public IntPrinter<i32_t> {
92     i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {}
93   };
94
95   struct ui32Printer : public IntPrinter<ui32_t> {
96     ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {}
97   };
98
99 #ifdef KM_WIN32
100   struct i64Printer : public IntPrinter<i64_t, 32> {
101     i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {}
102   };
103
104   struct ui64Printer : public IntPrinter<ui64_t, 32> {
105     ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {}
106   };
107 #else
108   struct i64Printer : public IntPrinter<i64_t, 32> {
109     i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {}
110   };
111
112   struct ui64Printer : public IntPrinter<ui64_t, 32> {
113     ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {}
114   };
115 #endif
116
117   // Convert NULL-terminated UTF-8 hexadecimal string to binary, returns 0 if
118   // the binary buffer was large enough to hold the result. The output parameter
119   // 'char_count' will contain the length of the converted string. If the output
120   // buffer is too small or any of the pointer arguments are NULL, the subroutine
121   // will return -1 and set 'char_count' to the required buffer size. No data will
122   // be written to 'buf' if the subroutine fails.
123   i32_t       hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
124
125   // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
126   // if the output buffer was large enough to hold the result. If the output buffer
127   // is too small or any of the pointer arguments are NULL, the subroutine will
128   // return 0.
129   //
130   const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
131
132   const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
133
134   // same as above for base64 text
135   i32_t       base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
136   const char* base64encode(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
137
138   // returns the length of a Base64 encoding of a buffer of the given length
139   inline ui32_t base64_encode_length(ui32_t length) {
140     while ( ( length % 3 ) != 0 )
141       length++;
142
143     return ( length / 3 ) * 4;
144   }
145
146   // print buffer contents to a stream as hexadecimal values in numbered
147   // rows of 16-bytes each.
148   //
149   void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0);
150
151   // Return the length in bytes of a BER encoded value
152   inline ui32_t BER_length(const byte_t* buf)
153     {
154       if ( buf == 0 || (*buf & 0xf0) != 0x80 )
155         return 0;
156
157       return (*buf & 0x0f) + 1;
158     }
159
160   // Return the BER length required to encode value. A return value of zero
161   // indicates a value too large for this library.
162   ui32_t get_BER_length_for_value(ui64_t valuse);
163
164   // read a BER value
165   bool read_BER(const byte_t* buf, ui64_t* val);
166
167   // decode a ber value and compare it to a test value
168   bool read_test_BER(byte_t **buf, ui64_t test_value);
169
170   // create BER encoding of integer value
171   bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0);
172
173   //----------------------------------------------------------------
174   //
175
176   // an abstract base class that objects implement to serialize state
177   // to and from a binary stream.
178   class IArchive
179     {
180     public:
181       virtual ~IArchive(){}
182       virtual bool   HasValue() const = 0;
183       virtual ui32_t ArchiveLength() const = 0;
184       virtual bool   Archive(MemIOWriter* Writer) const = 0;
185       virtual bool   Unarchive(MemIOReader* Reader) = 0;
186     };
187
188   //
189   template <class T>
190   class ArchivableList : public std::list<T>, public IArchive
191     {
192     public:
193       ArchivableList() {}
194       virtual ~ArchivableList() {}
195
196       bool HasValue() const { return ! this->empty(); }
197
198       ui32_t ArchiveLength() const
199       {
200         ui32_t arch_size = sizeof(ui32_t);
201
202         typename ArchivableList<T>::const_iterator i = this->begin();
203         for ( ; i != this->end(); i++ )
204           arch_size += i->ArchiveLength();
205
206         return arch_size;
207       }
208
209       bool Unarchive(Kumu::MemIOReader* Reader)
210         {
211           if ( Reader == 0 ) return false;
212           ui32_t read_size = 0;
213           if ( ! Reader->ReadUi32BE(&read_size) ) return false;
214           for ( ui32_t i = 0; i < read_size; i++ )
215             {
216               T TmpTP;
217               if ( ! TmpTP.Unarchive(Reader) ) return false;
218               this->push_back(TmpTP);
219             }
220
221           return true;
222         }
223
224       bool Archive(Kumu::MemIOWriter* Writer) const
225         {
226           if ( Writer == 0 ) return false;
227           if ( ! Writer->WriteUi32BE(static_cast<ui32_t>(this->size())) ) return false;
228           typename ArchivableList<T>::const_iterator i = this->begin();
229           for ( ; i != this->end(); i++ )
230             if ( ! i->Archive(Writer) ) return false;
231
232           return true;
233         }
234     };
235
236   // archivable version of std::string
237
238   //
239   class ArchivableString : public std::string, public Kumu::IArchive
240     {
241
242     public:
243       ArchivableString() {}
244       ArchivableString(const char* sz) : std::string(sz) {}
245       ArchivableString(const std::string& s) : std::string(s) {}
246       virtual ~ArchivableString() {}
247
248       bool   HasValue() const { return ! this->empty(); }
249       ui32_t ArchiveLength() const { return static_cast<ui32_t>((sizeof(ui32_t) + this->size())|0xffffffff); }
250
251       bool   Archive(MemIOWriter* Writer) const {
252         if ( Writer == 0 ) return false;
253         return Writer->WriteString(*this);
254       }
255
256       bool   Unarchive(MemIOReader* Reader) {
257         if ( Reader == 0 ) return false;
258         return Reader->ReadString(*this);
259       }
260     };
261
262   //
263   typedef Kumu::ArchivableList<ArchivableString> StringList;
264
265   //
266   // the base of all identifier classes, Identifier is not usually used directly
267   // see UUID and SymmetricKey below for more detail.
268   //
269   template <ui32_t SIZE>
270     class Identifier : public IArchive
271     {
272     protected:
273       bool   m_HasValue;
274       byte_t m_Value[SIZE];
275
276     public:
277       Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); }
278       Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); }
279       Identifier(const Identifier& rhs) : IArchive() {
280         m_HasValue = rhs.m_HasValue;
281         memcpy(m_Value, rhs.m_Value, SIZE);
282       }
283
284       virtual ~Identifier() {}
285
286       const Identifier& operator=(const Identifier& rhs) {
287         m_HasValue = rhs.m_HasValue;
288         memcpy(m_Value, rhs.m_Value, SIZE);
289         return *this;
290       }
291
292       inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); }
293       inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); }
294       inline const byte_t* Value() const { return m_Value; }
295       inline ui32_t Size() const { return SIZE; }
296
297       inline bool operator<(const Identifier& rhs) const {
298         ui32_t test_size = xmin(rhs.Size(), SIZE);
299
300         for ( ui32_t i = 0; i < test_size; i++ )
301           {
302             if ( m_Value[i] != rhs.m_Value[i] )
303               return m_Value[i] < rhs.m_Value[i];
304           }
305         
306         return false;
307       }
308
309       inline bool operator==(const Identifier& rhs) const {
310         if ( rhs.Size() != SIZE ) return false;
311         return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
312       }
313
314       inline bool operator!=(const Identifier& rhs) const {
315         if ( rhs.Size() != SIZE ) return true;
316         return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
317       }
318
319       inline bool DecodeHex(const char* str) {
320         ui32_t char_count;
321         m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
322         if ( m_HasValue && char_count != SIZE )
323           m_HasValue = false;
324         return m_HasValue;
325       }
326
327       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
328         return bin2hex(m_Value, SIZE, buf, buf_len);
329       }
330
331       inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
332         return EncodeHex(str_buf, buf_len);
333       }
334
335       inline bool DecodeBase64(const char* str) {
336         ui32_t char_count;
337         m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
338         if ( m_HasValue && char_count != SIZE )
339           m_HasValue = false;
340         return m_HasValue;
341       }
342
343       inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
344         return base64encode(m_Value, SIZE, buf, buf_len);
345       }
346
347       inline bool HasValue() const { return m_HasValue; }
348
349       inline ui32_t ArchiveLength() const { return SIZE; }
350
351       inline bool Unarchive(Kumu::MemIOReader* Reader) {
352         m_HasValue = Reader->ReadRaw(m_Value, SIZE);
353         return m_HasValue;
354       }
355
356       inline bool Archive(Kumu::MemIOWriter* Writer) const {
357         return Writer->WriteRaw(m_Value, SIZE);
358       }
359     };
360
361
362   // UUID
363   //
364   const ui32_t UUID_Length = 16;
365   class UUID : public Identifier<UUID_Length>
366     {
367     public:
368       UUID() {}
369       UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
370       UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
371       virtual ~UUID() {}
372
373       inline const char* EncodeString(char* buf, ui32_t buf_len) const {
374         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
375       }
376
377       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
378         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
379       }
380     };
381   
382   void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
383   void GenRandomValue(UUID&);
384 #ifdef LIBDCP_POSIX     
385   void ResetTestRNG();
386 #endif  
387   
388   typedef ArchivableList<UUID> UUIDList;
389
390   // a self-wiping key container
391   //
392   const ui32_t SymmetricKey_Length = 16;
393   const byte_t NilKey[SymmetricKey_Length] = {
394     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce,
395     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce
396   };
397
398   class SymmetricKey : public Identifier<SymmetricKey_Length>
399     {
400     public:
401       SymmetricKey() {}
402       SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {}
403       SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {}
404       virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; }
405     };
406
407   void GenRandomValue(SymmetricKey&);
408
409   //
410   // 2004-05-01T13:20:00+00:00
411   const ui32_t DateTimeLen = 25; //  the number of chars in the xs:dateTime format (sans milliseconds)
412
413   // UTC time+date representation
414   class Timestamp : public IArchive
415     {
416       TAI::tai m_Timestamp; // always UTC
417       i32_t m_TZOffsetMinutes;
418
419    public:
420       Timestamp();
421       Timestamp(const Timestamp& rhs);
422       Timestamp(const char* datestr);
423       Timestamp(const ui16_t& Year, const ui8_t&  Month, const ui8_t&  Day);
424       Timestamp(const ui16_t& Year, const ui8_t&  Month, const ui8_t&  Day,
425                 const ui8_t&  Hour, const ui8_t&  Minute, const ui8_t&  Second);
426       virtual ~Timestamp();
427
428       const Timestamp& operator=(const Timestamp& rhs);
429       bool operator<(const Timestamp& rhs) const;
430       bool operator>(const Timestamp& rhs) const;
431       bool operator==(const Timestamp& rhs) const;
432       bool operator!=(const Timestamp& rhs) const;
433
434       // always UTC
435       void GetComponents(ui16_t& Year, ui8_t&  Month, ui8_t&  Day,
436                          ui8_t&  Hour, ui8_t&  Minute, ui8_t&  Second) const;      
437       void SetComponents(const ui16_t& Year, const ui8_t&  Month, const ui8_t&  Day,
438                          const ui8_t&  Hour, const ui8_t&  Minute, const ui8_t&  Second);
439
440       // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00+00:00
441       // returns 0 if the buffer is smaller than DateTimeLen
442       const char* EncodeString(char* str_buf, ui32_t buf_len) const;
443
444       // decode and set value from string formatted by EncodeString
445       bool        DecodeString(const char* datestr);
446
447       // Add the given number of days, hours, minutes, or seconds to the timestamp value.
448       // Values less than zero will cause the timestamp to decrease
449       inline void AddDays(const i32_t& d) { m_Timestamp.add_days(d); }
450       inline  void AddHours(const i32_t& h) { m_Timestamp.add_hours(h); }
451       inline  void AddMinutes(const i32_t& m) { m_Timestamp.add_minutes(m); }
452       inline  void AddSeconds(const i32_t& s) { m_Timestamp.add_seconds(s); }
453
454       // returns false if the requested adjustment is out of range
455       bool SetTZOffsetMinutes(const i32_t& minutes);
456       inline i32_t GetTZOffsetMinutes() const { return m_TZOffsetMinutes; }
457
458       // Return the number of seconds since the Unix epoch UTC (1970-01-01T00:00:00+00:00)
459       ui64_t GetCTime() const;
460
461       // Read and write the timestamp (always UTC) value as a byte string having
462       // the following format:
463       // | 16 bits int, big-endian |    8 bits   |   8 bits  |   8 bits   |    8 bits    |    8 bits    |
464       // |        Year A.D         | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
465       //
466       virtual bool   HasValue() const;
467       virtual ui32_t ArchiveLength() const { return 8L; }
468       virtual bool   Archive(MemIOWriter* Writer) const;
469       virtual bool   Unarchive(MemIOReader* Reader);
470     };
471
472   //
473   class ByteString : public IArchive
474     {
475       KM_NO_COPY_CONSTRUCT(ByteString);
476         
477     protected:
478       byte_t* m_Data;          // pointer to memory area containing frame data
479       ui32_t  m_Capacity;      // size of memory area pointed to by m_Data
480       ui32_t  m_Length;        // length of byte string in memory area pointed to by m_Data
481         
482     public:
483       ByteString();
484       ByteString(ui32_t cap);
485       virtual ~ByteString();
486
487       // Sets or resets the size of the internally allocated buffer.
488       Result_t Capacity(ui32_t cap);
489
490       Result_t Append(const ByteString&);
491       Result_t Append(const byte_t* buf, ui32_t buf_len);
492         
493       // returns the size of the buffer
494       inline ui32_t  Capacity() const { return m_Capacity; }
495
496       // returns a const pointer to the essence data
497       inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
498         
499       // returns a non-const pointer to the essence data
500       inline byte_t* Data() { assert(m_Data); return m_Data; }
501         
502       // set the length of the buffer's contents
503       inline ui32_t  Length(ui32_t l) { return m_Length = l; }
504         
505       // returns the length of the buffer's contents
506       inline ui32_t  Length() const { return m_Length; }
507
508       // copy the given data into the ByteString, set Length value.
509       // Returns error if the ByteString is too small.
510       Result_t Set(const byte_t* buf, ui32_t buf_len);
511       Result_t Set(const ByteString& Buf);
512
513       inline virtual bool HasValue() const { return m_Length > 0; }
514
515       inline virtual ui32_t ArchiveLength() const { return m_Length; }
516
517       inline virtual bool Archive(MemIOWriter* Writer) const {
518         assert(Writer);
519         if ( ! Writer->WriteUi32BE(m_Length) ) return false;
520         if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
521         return true;
522       }
523
524       inline virtual bool Unarchive(MemIOReader* Reader) {
525         assert(Reader);
526         ui32_t tmp_len;
527         if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
528         if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
529         if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
530         m_Length = tmp_len;
531         return true;
532       }
533     };
534
535   inline void hexdump(const ByteString& buf, FILE*) {
536     hexdump(buf.RoData(), buf.Length());
537   }
538
539
540 } // namespace Kumu
541
542
543 #endif // _KM_UTIL_H_
544
545 //
546 // end KM_util.h
547 //