1 /*****************************************************************************
2  * utils.c / utils.cpp
3  *****************************************************************************
4  * Copyright (C) 2012-2015 L-SMASH Works project
5  *
6  * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
7  *
8  * Permission to use, copy, modify, and/or distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  *****************************************************************************/
20 
21 /* This file is available under an ISC license. */
22 
23 #include "cpp_compat.h"
24 
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <inttypes.h>
29 #include <math.h>
30 
31 #include "utils.h"
32 
lw_malloc_zero(size_t size)33 void *lw_malloc_zero( size_t size )
34 {
35     void *p = malloc( size );
36     if( !p )
37         return NULL;
38     memset( p, 0, size );
39     return p;
40 }
41 
lw_free(void * pointer)42 void lw_free( void *pointer )
43 {
44     free( pointer );
45 }
46 
lw_freep(void * pointer)47 void lw_freep( void *pointer )
48 {
49     if( !pointer )
50         return;
51     void **p = (void **)pointer;
52     free( *p );
53     *p = NULL;
54 }
55 
lw_memdup(void * src,size_t size)56 void *lw_memdup
57 (
58     void  *src,
59     size_t size
60 )
61 {
62     if( size == 0 )
63         return NULL;
64     void *dst = malloc( size );
65     if( !dst )
66         return NULL;
67     memcpy( dst, src, size );
68     return dst;
69 }
70 
lw_log_write_message(lw_log_handler_t * lhp,lw_log_level level,char * message,const char * format,va_list args)71 static void lw_log_write_message
72 (
73     lw_log_handler_t *lhp,
74     lw_log_level      level,
75     char             *message,
76     const char       *format,
77     va_list           args
78 )
79 {
80     char *prefix;
81     switch( level )
82     {
83         case LW_LOG_FATAL:
84             prefix = "Fatal";
85             break;
86         case LW_LOG_ERROR:
87             prefix = "Error";
88             break;
89         case LW_LOG_WARNING:
90             prefix = "Warning";
91             break;
92         case LW_LOG_INFO:
93             prefix = "Info";
94             break;
95         default:
96             prefix = "Unknown";
97             break;
98     }
99     char temp[512];
100     vsprintf( temp, format, args );
101     if( lhp->name )
102         sprintf( message, "%s [%s]: %s", lhp->name, prefix, temp );
103     else
104         sprintf( message, "[%s]: %s", prefix, temp );
105 }
106 
lw_log_show(lw_log_handler_t * lhp,lw_log_level level,const char * format,...)107 void lw_log_show
108 (
109     lw_log_handler_t *lhp,
110     lw_log_level      level,
111     const char       *format,
112     ...
113 )
114 {
115     if( !lhp || !lhp->priv || !lhp->show_log || level < lhp->level )
116         return;
117     va_list args;
118     va_start( args, format );
119     char message[1024];
120     lw_log_write_message( lhp, level, message, format, args );
121     va_end( args );
122     lhp->show_log( lhp, level, message );
123 }
124 
lw_check_file_extension(const char * file_name,const char * extension)125 int lw_check_file_extension
126 (
127     const char *file_name,
128     const char *extension
129 )
130 {
131     int extension_length = strlen( extension );
132     int file_name_length = strlen( file_name );
133     if( file_name_length - extension_length <= 1 )
134         return -1;
135     const char *ext = &file_name[file_name_length - extension_length];
136     return ext[-1] != '.' || memcmp( extension, ext, extension_length ) ? -1 : 0;
137 }
138 
lw_round(double x)139 static inline double lw_round
140 (
141     double x
142 )
143 {
144     return x > 0 ? floor( x + 0.5 ) : ceil( x - 0.5 );
145 }
146 
sigexp10(double value,double * exponent)147 static inline double sigexp10
148 (
149     double  value,
150     double *exponent
151 )
152 {
153     /* This function separates significand and exp10 from double floating point. */
154     *exponent = 1;
155     while( value < 1 )
156     {
157         value *= 10;
158         *exponent /= 10;
159     }
160     while( value >= 10 )
161     {
162         value /= 10;
163         *exponent *= 10;
164     }
165     return value;
166 }
167 
lw_try_rational_framerate(double framerate,int64_t * framerate_num,int64_t * framerate_den,uint64_t timebase)168 int lw_try_rational_framerate
169 (
170     double   framerate,
171     int64_t *framerate_num,
172     int64_t *framerate_den,
173     uint64_t timebase
174 )
175 {
176 #define DOUBLE_EPSILON 5e-5
177     if( framerate == 0 )
178         return 0;
179     uint64_t fps_den[3] = { 0 };
180     uint64_t fps_num[3] = { 0 };
181     double   error[3] = { DOUBLE_EPSILON, DOUBLE_EPSILON, DOUBLE_EPSILON };
182     double   exponent;
183     double   fps_sig = sigexp10( framerate, &exponent );
184     uint64_t base[3] = { timebase, 1001, 1 };
185     for( int i = 0; i < 3; i++ )
186     {
187         if( i && base[i] == base[0] )
188             continue;
189         if( i == 2 && (error[0] < DOUBLE_EPSILON || error[1] < DOUBLE_EPSILON) )
190             break;
191         for( int j = 1; ; j++ )
192         {
193             fps_den[i] = j * base[i];
194             fps_num[i] = (uint64_t)(lw_round( fps_den[i] * fps_sig ) * exponent);
195             if( fps_num[i] > INT32_MAX )
196             {
197                 error[i] = DOUBLE_EPSILON;
198                 break;
199             }
200             error[i] = fabs( ((double)fps_num[i] / fps_den[i]) / exponent - fps_sig );
201             if( error[i] < DOUBLE_EPSILON )
202                 break;
203         }
204     }
205     double min_error = DOUBLE_EPSILON;
206     for( int i = 0; i < 3; i++ )
207         if( min_error > error[i] )
208         {
209             min_error = error[i];
210             reduce_fraction( &fps_num[i], &fps_den[i] );
211             *framerate_num = (int64_t)fps_num[i];
212             *framerate_den = (int64_t)fps_den[i];
213         }
214     return (min_error < DOUBLE_EPSILON);
215 #undef DOUBLE_EPSILON
216 }
217 
lw_tokenize_string(char * str,char separator,char ** bufs)218 const char **lw_tokenize_string
219 (
220     char * str,         /* null-terminated string: separator charactors will be replaced with '\0'. */
221     char   separator,   /* separator */
222     char **bufs         /* If NULL, allocate memory block internally, which can be deallocated by lw_freep(). */
223 )
224 {
225     if( !str )
226         return NULL;
227     char **tokens = bufs ? bufs : (char **)malloc( 2 * sizeof(char *) );
228     if( !tokens )
229         return NULL;
230     size_t i = 1;
231     tokens[0] = str;
232     tokens[1] = NULL;   /* null-terminated */
233     for( char *p = str; *p != '\0'; p++ )
234         if( *p == separator )
235         {
236             *p = '\0';
237             if( *(p + 1) != '\0' )
238             {
239                 if( !bufs )
240                 {
241                     char **tmp = (char **)realloc( tokens, (i + 2) * sizeof(char *) );
242                     if( !tmp )
243                         break;
244                     tokens = tmp;
245                 }
246                 tokens[  i] = p + 1;
247                 tokens[++i] = NULL;   /* null-terminated */
248             }
249         }
250     return (const char **)tokens;
251 }
252