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 
198 }} // namespace mp4v2::impl
199 
200 extern "C"
Base64ToBinary(const char * pData,uint32_t decodeSize,uint32_t * pDataSize)201 uint8_t *Base64ToBinary (const char *pData, uint32_t decodeSize, uint32_t *pDataSize)
202 {
203     uint8_t *ret;
204     uint32_t size, ix, groups;
205     if (pData == NULL ||  decodeSize == 0 || pDataSize == NULL)
206         return NULL;
207 
208     if ((decodeSize % 4) != 0) {
209         // must be multiples of 4 characters
210         return NULL;
211     }
212     size = (decodeSize * 3) / 4;
213     groups = decodeSize / 4;
214     ret = (uint8_t *)mp4v2::impl::MP4Calloc(size);
215     if (ret == NULL) return NULL;
216     for (ix = 0; ix < groups; ix++) {
217         uint8_t value[4];
218         for (uint8_t jx = 0; jx < 4; jx++) {
219             if (pData[jx] == '=') {
220                 if (ix != (groups - 1)) {
221                     free(ret);
222                     return NULL;
223                 }
224                 size--;
225                 value[jx] = 0;
226             } else if (mp4v2::impl::convertBase64(pData[jx], &value[jx]) == false) {
227                 free(ret);
228                 return NULL;
229             }
230         }
231         ret[(ix * 3)] = value[0] << 2 | ((value[1] >> 4) & 0x3);
232         ret[(ix * 3) + 1] = (value[1] << 4) | (value[2] >> 2 & 0xf);
233         ret[(ix * 3) + 2] = ((value[2] & 0x3) << 6) | value[3];
234         pData += 4;
235     }
236     *pDataSize = size;
237     return ret;
238 }
239 
240 namespace mp4v2 { namespace impl {
241 
242 // log2 of value, rounded up
ilog2(uint64_t value)243 static uint8_t ilog2(uint64_t value)
244 {
245     uint64_t powerOf2 = 1;
246     for (uint8_t i = 0; i < 64; i++) {
247         if (value <= powerOf2) {
248             return i;
249         }
250         powerOf2 <<= 1;
251     }
252     return 64;
253 }
254 
MP4ConvertTime(uint64_t t,uint32_t oldTimeScale,uint32_t newTimeScale)255 uint64_t MP4ConvertTime(uint64_t t,
256                         uint32_t oldTimeScale, uint32_t newTimeScale)
257 {
258     // avoid float point exception
259     if (oldTimeScale == 0) {
260         throw new Exception("division by zero", __FILE__, __LINE__, __FUNCTION__ );
261     }
262 
263     if (oldTimeScale == newTimeScale) return t;
264 
265     // check if we can safely use integer operations
266     if (ilog2(t) + ilog2(newTimeScale) <= 64) {
267         return (t * newTimeScale) / oldTimeScale;
268     }
269 
270     // final resort is to use floating point
271     double d = (double)newTimeScale;
272     d *= double(t);
273     d /= (double)oldTimeScale;
274     d += 0.5; // round up.
275 
276     return (uint64_t)d;
277 }
278 
MP4NormalizeTrackType(const char * type)279 const char* MP4NormalizeTrackType (const char* type)
280 {
281     if (!strcasecmp(type, "vide")
282             || !strcasecmp(type, "video")
283             || !strcasecmp(type, "mp4v")
284             || !strcasecmp(type, "avc1")
285             || !strcasecmp(type, "s263")  // 3GPP H.263
286             || !strcasecmp(type, "encv")) {
287         return MP4_VIDEO_TRACK_TYPE;
288     }
289 
290     if (!strcasecmp(type, "soun")
291             || !strcasecmp(type, "sound")
292             || !strcasecmp(type, "audio")
293             || !strcasecmp(type, "enca")
294             || !strcasecmp(type, "samr")  // 3GPP AMR
295             || !strcasecmp(type, "sawb")  // 3GPP AMR/WB
296             || !strcasecmp(type, "mp4a")) {
297         return MP4_AUDIO_TRACK_TYPE;
298     }
299 
300     if (!strcasecmp(type, "sdsm")
301             || !strcasecmp(type, "scene")
302             || !strcasecmp(type, "bifs")) {
303         return MP4_SCENE_TRACK_TYPE;
304     }
305 
306     if (!strcasecmp(type, "odsm")
307             || !strcasecmp(type, "od")) {
308         return MP4_OD_TRACK_TYPE;
309     }
310     if (strcasecmp(type, "cntl") == 0) {
311         return MP4_CNTL_TRACK_TYPE;
312     }
313 
314     log.verbose1f("Attempt to normalize %s did not match",type);
315 
316     return type;
317 }
318 
MP4GetAbsTimestamp()319 MP4Timestamp MP4GetAbsTimestamp() {
320     /* MP4 epoch is midnight, January 1, 1904
321      * offset from midnight, January 1, 1970 is 2082844800 seconds
322      * 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
323      */
324     return time::getLocalTimeSeconds() + 2082844800;
325 }
326 
327 ///////////////////////////////////////////////////////////////////////////////
328 
STRTOINT32(const char * s)329 uint32_t STRTOINT32( const char* s )
330 {
331 #if defined( MP4V2_INTSTRING_ALIGNMENT )
332     // it seems ARM integer instructions require 4-byte alignment so we
333     // manually copy string-data into the integer before performing ops
334     uint32_t tmp;
335     memcpy( &tmp, s, sizeof(tmp) );
336     return MP4V2_NTOHL( tmp );
337 #else
338     return MP4V2_NTOHL(*(uint32_t *)s);
339 #endif
340 }
341 
INT32TOSTR(uint32_t i,char * s)342 void INT32TOSTR( uint32_t i, char* s )
343 {
344 #if defined( MP4V2_INTSTRING_ALIGNMENT )
345     // it seems ARM integer instructions require 4-byte alignment so we
346     // manually copy string-data into the integer before performing ops
347     uint32_t tmp = MP4V2_HTONL( i );
348     memcpy( s, &tmp, sizeof(tmp) );
349 #else
350     *(uint32_t *)s = MP4V2_HTONL(i);
351 #endif
352     s[4] = 0;
353 }
354 
355 ///////////////////////////////////////////////////////////////////////////////
356 
357 }} // namespace mp4v2::impl
358