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-2005.  All Rights Reserved.
17  *
18  * Contributor(s):
19  *      Dave Mackie     dmackie@cisco.com
20  *              Bill May                wmay@cisco.com
21  */
22 
23 #include "src/impl.h"
24 
25 namespace mp4v2 { namespace impl {
26 
27 ///////////////////////////////////////////////////////////////////////////////
28 
MP4NameFirstMatches(const char * s1,const char * s2)29 bool MP4NameFirstMatches(const char* s1, const char* s2)
30 {
31     if (s1 == NULL || *s1 == '\0' || s2 == NULL || *s2 == '\0') {
32         return false;
33     }
34 
35     if (*s2 == '*') {
36         return true;
37     }
38 
39     while (*s1 != '\0') {
40         if (*s2 == '\0' || strchr("[.", *s2)) {
41             break;
42         }
43         if (tolower(*s1) != tolower(*s2)) {
44             return false;
45         }
46         s1++;
47         s2++;
48     }
49     return true;
50 }
51 
MP4NameFirstIndex(const char * s,uint32_t * pIndex)52 bool MP4NameFirstIndex(const char* s, uint32_t* pIndex)
53 {
54     if (s == NULL) {
55         return false;
56     }
57 
58     while (*s != '\0' && *s != '.') {
59         if (*s == '[') {
60             s++;
61             ASSERT(pIndex);
62             if (sscanf(s, "%u", pIndex) != 1) {
63                 return false;
64             }
65             return true;
66         }
67         s++;
68     }
69     return false;
70 }
71 
MP4NameFirst(const char * s)72 char* MP4NameFirst(const char *s)
73 {
74     if (s == NULL) {
75         return NULL;
76     }
77 
78     const char* end = s;
79 
80     while (*end != '\0' && *end != '.') {
81         end++;
82     }
83 
84     char* first = (char*)MP4Calloc((end - s) + 1);
85 
86     if (first) {
87         strncpy(first, s, end - s);
88     }
89 
90     return first;
91 }
92 
MP4NameAfterFirst(const char * s)93 const char* MP4NameAfterFirst(const char *s)
94 {
95     if (s == NULL) {
96         return NULL;
97     }
98 
99     while (*s != '\0') {
100         if (*s == '.') {
101             s++;
102             if (*s == '\0') {
103                 return NULL;
104             }
105             return s;
106         }
107         s++;
108     }
109     return NULL;
110 }
111 
MP4ToBase16(const uint8_t * pData,uint32_t dataSize)112 char* MP4ToBase16(const uint8_t* pData, uint32_t dataSize)
113 {
114     if (dataSize) {
115         ASSERT(pData);
116     }
117     uint32_t size = 2 * dataSize + 1;
118     char* s = (char*)MP4Calloc(size);
119 
120     uint32_t i, j;
121     for (i = 0, j = 0; i < dataSize; i++) {
122         size -= snprintf(&s[j], size, "%02x", pData[i]);
123         j += 2;
124     }
125 
126     return s;   /* N.B. caller is responsible for free'ing s */
127 }
128 
MP4ToBase64(const uint8_t * pData,uint32_t dataSize)129 char* MP4ToBase64(const uint8_t* pData, uint32_t dataSize)
130 {
131     if (pData == NULL || dataSize == 0) return NULL;
132 
133     static const char encoding[64] = {
134         'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
135         'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
136         'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
137         'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
138     };
139 
140     char* s = (char*)MP4Calloc((((dataSize + 2) * 4) / 3) + 1);
141 
142     const uint8_t* src = pData;
143     if (pData == NULL) return NULL;
144     char* dest = s;
145     uint32_t numGroups = dataSize / 3;
146 
147     for (uint32_t i = 0; i < numGroups; i++) {
148         *dest++ = encoding[src[0] >> 2];
149         *dest++ = encoding[((src[0] & 0x03) << 4) | (src[1] >> 4)];
150         *dest++ = encoding[((src[1] & 0x0F) << 2) | (src[2] >> 6)];
151         *dest++ = encoding[src[2] & 0x3F];
152         src += 3;
153     }
154 
155     if (dataSize % 3 == 1) {
156         *dest++ = encoding[src[0] >> 2];
157         *dest++ = encoding[((src[0] & 0x03) << 4)];
158         *dest++ = '=';
159         *dest++ = '=';
160     } else if (dataSize % 3 == 2) {
161         *dest++ = encoding[src[0] >> 2];
162         *dest++ = encoding[((src[0] & 0x03) << 4) | (src[1] >> 4)];
163         *dest++ = encoding[((src[1] & 0x0F) << 2)];
164         *dest++ = '=';
165     }
166     *dest = '\0';
167     return s;   /* N.B. caller is responsible for free'ing s */
168 }
169 
convertBase64(const char data,uint8_t * value)170 static bool convertBase64 (const char data, uint8_t *value)
171 {
172     static const uint8_t decodingarr64[128] = {
173         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
174         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
175         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
176         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
177         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
178         0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
179         0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
180         0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
181         0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
182         0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
183         0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
184         0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
185         0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
186         0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
187         0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
188         0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
189     };
190     uint8_t index = (uint8_t)data;
191     if ((index & 0x80) != 0) return false;
192 
193     if (decodingarr64[index] == 0xff) return false;
194     *value = decodingarr64[index];
195     return true;
196 }
197 
Base64ToBinary(const char * pData,uint32_t decodeSize,uint32_t * pDataSize)198 uint8_t *Base64ToBinary (const char *pData, uint32_t decodeSize, uint32_t *pDataSize)
199 {
200     uint8_t *ret;
201     uint32_t size, ix, groups;
202     if (pData == NULL ||  decodeSize == 0 || pDataSize == NULL)
203         return NULL;
204 
205     if ((decodeSize % 4) != 0) {
206         // must be multiples of 4 characters
207         return NULL;
208     }
209     size = (decodeSize * 3) / 4;
210     groups = decodeSize / 4;
211     ret = (uint8_t *)MP4Calloc(size);
212     if (ret == NULL) return NULL;
213     for (ix = 0; ix < groups; ix++) {
214         uint8_t value[4];
215         for (uint8_t jx = 0; jx < 4; jx++) {
216             if (pData[jx] == '=') {
217                 if (ix != (groups - 1)) {
218                     free(ret);
219                     return NULL;
220                 }
221                 size--;
222                 value[jx] = 0;
223             } else if (convertBase64(pData[jx], &value[jx]) == false) {
224                 free(ret);
225                 return NULL;
226             }
227         }
228         ret[(ix * 3)] = value[0] << 2 | ((value[1] >> 4) & 0x3);
229         ret[(ix * 3) + 1] = (value[1] << 4) | (value[2] >> 2 & 0xf);
230         ret[(ix * 3) + 2] = ((value[2] & 0x3) << 6) | value[3];
231         pData += 4;
232     }
233     *pDataSize = size;
234     return ret;
235 }
236 
237 // log2 of value, rounded up
ilog2(uint64_t value)238 static uint8_t ilog2(uint64_t value)
239 {
240     uint64_t powerOf2 = 1;
241     for (uint8_t i = 0; i < 64; i++) {
242         if (value <= powerOf2) {
243             return i;
244         }
245         powerOf2 <<= 1;
246     }
247     return 64;
248 }
249 
MP4ConvertTime(uint64_t t,uint32_t oldTimeScale,uint32_t newTimeScale)250 uint64_t MP4ConvertTime(uint64_t t,
251                         uint32_t oldTimeScale, uint32_t newTimeScale)
252 {
253     // avoid float point exception
254     if (oldTimeScale == 0) {
255         throw new Exception("division by zero", __FILE__, __LINE__, __FUNCTION__ );
256     }
257 
258     if (oldTimeScale == newTimeScale) return t;
259 
260     // check if we can safely use integer operations
261     if (ilog2(t) + ilog2(newTimeScale) <= 64) {
262         return (t * newTimeScale) / oldTimeScale;
263     }
264 
265     // final resort is to use floating point
266     double d = (double)newTimeScale;
267     d *= double(t);
268     d /= (double)oldTimeScale;
269     d += 0.5; // round up.
270 
271     return (uint64_t)d;
272 }
273 
MP4NormalizeTrackType(const char * type)274 const char* MP4NormalizeTrackType (const char* type)
275 {
276     if (!strcasecmp(type, "vide")
277             || !strcasecmp(type, "video")
278             || !strcasecmp(type, "mp4v")
279             || !strcasecmp(type, "avc1")
280             || !strcasecmp(type, "s263")  // 3GPP H.263
281             || !strcasecmp(type, "encv")) {
282         return MP4_VIDEO_TRACK_TYPE;
283     }
284 
285     if (!strcasecmp(type, "soun")
286             || !strcasecmp(type, "sound")
287             || !strcasecmp(type, "audio")
288             || !strcasecmp(type, "enca")
289             || !strcasecmp(type, "samr")  // 3GPP AMR
290             || !strcasecmp(type, "sawb")  // 3GPP AMR/WB
291             || !strcasecmp(type, "mp4a")) {
292         return MP4_AUDIO_TRACK_TYPE;
293     }
294 
295     if (!strcasecmp(type, "sdsm")
296             || !strcasecmp(type, "scene")
297             || !strcasecmp(type, "bifs")) {
298         return MP4_SCENE_TRACK_TYPE;
299     }
300 
301     if (!strcasecmp(type, "odsm")
302             || !strcasecmp(type, "od")) {
303         return MP4_OD_TRACK_TYPE;
304     }
305     if (strcasecmp(type, "cntl") == 0) {
306         return MP4_CNTL_TRACK_TYPE;
307     }
308 
309     log.verbose1f("Attempt to normalize %s did not match",type);
310 
311     return type;
312 }
313 
MP4GetAbsTimestamp()314 MP4Timestamp MP4GetAbsTimestamp() {
315     /* MP4 epoch is midnight, January 1, 1904
316      * offset from midnight, January 1, 1970 is 2082844800 seconds
317      * 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
318      */
319     return time::getLocalTimeSeconds() + 2082844800;
320 }
321 
322 ///////////////////////////////////////////////////////////////////////////////
323 
STRTOINT32(const char * s)324 uint32_t STRTOINT32( const char* s )
325 {
326 #if defined( MP4V2_INTSTRING_ALIGNMENT )
327     // it seems ARM integer instructions require 4-byte alignment so we
328     // manually copy string-data into the integer before performing ops
329     uint32_t tmp;
330     memcpy( &tmp, s, sizeof(tmp) );
331     return MP4V2_NTOHL( tmp );
332 #else
333     return MP4V2_NTOHL(*(uint32_t *)s);
334 #endif
335 }
336 
INT32TOSTR(uint32_t i,char * s)337 void INT32TOSTR( uint32_t i, char* s )
338 {
339 #if defined( MP4V2_INTSTRING_ALIGNMENT )
340     // it seems ARM integer instructions require 4-byte alignment so we
341     // manually copy string-data into the integer before performing ops
342     uint32_t tmp = MP4V2_HTONL( i );
343     memcpy( s, &tmp, sizeof(tmp) );
344 #else
345     *(uint32_t *)s = MP4V2_HTONL(i);
346 #endif
347     s[4] = 0;
348 }
349 
350 ///////////////////////////////////////////////////////////////////////////////
351 
352 }} // namespace mp4v2::impl
353