1 /*
2 (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
3 (c) Copyright 2000-2004 Convergence (integrated media) GmbH
4
5 All rights reserved.
6
7 Written by Denis Oliver Kropp <dok@directfb.org>,
8 Andreas Hundt <andi@fischlustig.de>,
9 Sven Neumann <neo@directfb.org>,
10 Ville Syrjälä <syrjala@sci.fi> and
11 Claudio Ciccani <klan@users.sf.net>.
12
13 This library is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 2 of the License, or (at your option) any later version.
17
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
22
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the
25 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 Boston, MA 02111-1307, USA.
27 */
28
29 #include <config.h>
30
31 #include <string.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <unistd.h>
35
36 #include <direct/debug.h>
37 #include <direct/mem.h>
38 #include <direct/messages.h>
39 #include <direct/util.h>
40
41 /*
42 * translates errno to DirectResult
43 */
44 DirectResult
errno2result(int erno)45 errno2result( int erno )
46 {
47 switch (erno) {
48 case 0:
49 return DR_OK;
50 case ENOENT:
51 return DR_FILENOTFOUND;
52 case EACCES:
53 case EPERM:
54 return DR_ACCESSDENIED;
55 case EBUSY:
56 case EAGAIN:
57 return DR_BUSY;
58 case ECONNREFUSED:
59 return DR_ACCESSDENIED;
60 case ENODEV:
61 case ENXIO:
62 #ifdef ENOTSUP
63 /* ENOTSUP is not defined on NetBSD */
64 case ENOTSUP:
65 #endif
66 return DR_UNSUPPORTED;
67 }
68
69 return DR_FAILURE;
70 }
71
72 const char *
DirectResultString(DirectResult result)73 DirectResultString( DirectResult result )
74 {
75 if (!D_RESULT_TYPE_IS( result, 0, 0, 0 ))
76 return "UNKNOWN RESULT CODE TYPE!";
77
78 switch (result) {
79 case DR_OK:
80 return "OK";
81 case DR_FAILURE:
82 return "General failure!";
83 case DR_INIT:
84 return "Initialization error!";
85 case DR_BUG:
86 return "Internal bug!";
87 case DR_DEAD:
88 return "Interface was released!";
89 case DR_UNSUPPORTED:
90 return "Not supported!";
91 case DR_UNIMPLEMENTED:
92 return "Not implemented!";
93 case DR_ACCESSDENIED:
94 return "Access denied!";
95 case DR_INVARG:
96 return "Invalid argument!";
97 case DR_NOLOCALMEMORY:
98 return "Out of memory!";
99 case DR_LOCKED:
100 return "Resource is locked!";
101 case DR_BUFFEREMPTY:
102 return "Buffer is empty!";
103 case DR_FILENOTFOUND:
104 return "File not found!";
105 case DR_IO:
106 return "General I/O error!";
107 case DR_NOIMPL:
108 return "No (suitable) implementation found!";
109 case DR_TIMEOUT:
110 return "Operation timed out!";
111 case DR_BUSY:
112 return "Resource is busy!";
113 case DR_THIZNULL:
114 return "'thiz' argument is NULL!";
115 case DR_IDNOTFOUND:
116 return "Requested ID not found!";
117 case DR_INVAREA:
118 return "Invalid area present!";
119 case DR_DESTROYED:
120 return "Resource was destroyed!";
121 case DR_FUSION:
122 return "Fusion IPC error detected!";
123 case DR_BUFFERTOOLARGE:
124 return "Buffer is too large!";
125 case DR_INTERRUPTED:
126 return "Operation has been interrupted!";
127 case DR_NOCONTEXT:
128 return "No context available!";
129 case DR_TEMPUNAVAIL:
130 return "Resource temporarily unavailable!";
131 case DR_LIMITEXCEEDED:
132 return "Limit has been exceeded!";
133 case DR_NOSUCHMETHOD:
134 return "No such (remote) method!";
135 case DR_NOSUCHINSTANCE:
136 return "No such (remote) instance!";
137 case DR_ITEMNOTFOUND:
138 return "Appropriate item not found!";
139 case DR_VERSIONMISMATCH:
140 return "Some versions didn't match!";
141 case DR_NOSHAREDMEMORY:
142 return "Out of shared memory!";
143 case DR_EOF:
144 return "End of file!";
145 case DR_SUSPENDED:
146 return "Object is suspended!";
147 case DR_INCOMPLETE:
148 return "Operation incomplete!";
149 case DR_NOCORE:
150 return "No core (loaded)!";
151 default:
152 break;
153 }
154
155 return "UNKNOWN RESULT CODE!";
156 }
157
158 int
direct_safe_dup(int fd)159 direct_safe_dup( int fd )
160 {
161 int n = 0;
162 int fc[3];
163
164 while (fd >= 0 && fd <= 2) {
165 fc[n++] = fd;
166 fd = dup (fd);
167 }
168
169 while (n)
170 close (fc[--n]);
171
172 return fd;
173 }
174
175 int
direct_try_open(const char * name1,const char * name2,int flags,bool error_msg)176 direct_try_open( const char *name1, const char *name2, int flags, bool error_msg )
177 {
178 int fd;
179
180 fd = open (name1, flags);
181 if (fd >= 0)
182 return direct_safe_dup (fd);
183
184 if (errno != ENOENT) {
185 if (error_msg)
186 D_PERROR( "Direct/Util: opening '%s' failed\n", name1 );
187 return -1;
188 }
189
190 fd = open (name2, flags);
191 if (fd >= 0)
192 return direct_safe_dup (fd);
193
194 if (error_msg) {
195 if (errno == ENOENT)
196 D_PERROR( "Direct/Util: opening '%s' and '%s' failed\n", name1, name2 );
197 else
198 D_PERROR( "Direct/Util: opening '%s' failed\n", name2 );
199 }
200
201 return -1;
202 }
203
204 void
direct_trim(char ** s)205 direct_trim( char **s )
206 {
207 int i;
208 int len = strlen( *s );
209
210 for (i = len-1; i >= 0; i--)
211 if ((*s)[i] <= ' ')
212 (*s)[i] = 0;
213 else
214 break;
215
216 while (**s)
217 if (**s <= ' ')
218 (*s)++;
219 else
220 return;
221 }
222
223 /*
224 * Utility function to initialize recursive mutexes.
225 */
226 int
direct_util_recursive_pthread_mutex_init(pthread_mutex_t * mutex)227 direct_util_recursive_pthread_mutex_init( pthread_mutex_t *mutex )
228 {
229 int ret;
230 pthread_mutexattr_t attr;
231
232 pthread_mutexattr_init( &attr );
233 #if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE
234 pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
235 #endif
236 ret = pthread_mutex_init( mutex, &attr );
237 if (ret)
238 D_PERROR( "Direct/Lock: Could not initialize recursive mutex!\n" );
239
240 pthread_mutexattr_destroy( &attr );
241
242 return ret;
243 }
244
245 /*
246 * Encode/Decode Base-64.
247 */
248 char*
direct_base64_encode(const void * data,int size)249 direct_base64_encode( const void *data, int size )
250 {
251 static const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
252 "abcdefghijklmnopqrstuvwxyz"
253 "0123456789+/=";
254 const unsigned char *src = (const unsigned char*)data;
255 char *ret;
256 char *buf;
257
258 D_ASSERT( data != NULL );
259
260 buf = ret = D_MALLOC( (size + 2) / 3 * 4 + 1 );
261 if (!ret)
262 return NULL;
263
264 for (; size >= 3; size -= 3) {
265 buf[0] = enc[((src[0] & 0xfc) >> 2)];
266 buf[1] = enc[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)];
267 buf[2] = enc[((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)];
268 buf[3] = enc[((src[2] & 0x3f))];
269 buf += 4;
270 src += 3;
271 }
272
273 if (size > 0) {
274 buf[0] = enc[(src[0] & 0xfc) >> 2];
275
276 if (size > 1) {
277 buf[1] = enc[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)];
278 buf[2] = enc[((src[1] & 0x0f) << 2)];
279 } else {
280 buf[1] = enc[(src[0] & 0x03) << 4];
281 buf[2] = '=';
282 }
283
284 buf[3] = '=';
285 buf += 4;
286 }
287
288 *buf = '\0';
289
290 return ret;
291 }
292
293 void*
direct_base64_decode(const char * string,int * ret_size)294 direct_base64_decode( const char *string, int *ret_size )
295 {
296 unsigned char dec[256];
297 unsigned char *ret;
298 unsigned char *buf;
299 int len;
300 int i, j;
301
302 D_ASSERT( string != NULL );
303
304 len = strlen( string );
305 buf = ret = D_MALLOC( len * 3 / 4 + 3 );
306 if (!ret)
307 return NULL;
308
309 /* generate decode table */
310 for (i = 0; i < 255; i++)
311 dec[i] = 0x80;
312 for (i = 'A'; i <= 'Z'; i++)
313 dec[i] = 0 + (i - 'A');
314 for (i = 'a'; i <= 'z'; i++)
315 dec[i] = 26 + (i - 'a');
316 for (i = '0'; i <= '9'; i++)
317 dec[i] = 52 + (i - '0');
318 dec['+'] = 62;
319 dec['/'] = 63;
320 dec['='] = 0;
321
322 /* decode */
323 for (j = 0; j < len; j += 4) {
324 unsigned char a[4], b[4];
325
326 for (i = 0; i < 4; i++) {
327 int c = string[i+j];
328 a[i] = c;
329 b[i] = dec[c];
330 }
331
332 *buf++ = (b[0] << 2) | (b[1] >> 4);
333 *buf++ = (b[1] << 4) | (b[2] >> 2);
334 *buf++ = (b[2] << 6) | (b[3] );
335 if (a[2] == '=' || a[3] == '=')
336 break;
337 }
338
339 *buf = '\0';
340
341 if (ret_size)
342 *ret_size = buf - ret;
343
344 return ret;
345 }
346
347 /*
348 * Compute MD5 sum.
349 */
350 static const u8 S[4][4] = {
351 { 7, 12, 17, 22 }, /* Round 1 */
352 { 5, 9, 14, 20 }, /* Round 2 */
353 { 4, 11, 16, 23 }, /* Round 3 */
354 { 6, 10, 15, 21 } /* Round 4 */
355 };
356
357 static const u32 T[64] = {
358 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */
359 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
360 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
361 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
362
363 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */
364 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
365 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
366 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
367
368 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */
369 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
370 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
371 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
372
373 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* Round 4 */
374 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
375 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
376 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
377 };
378
379 static void
md5_hash(u32 ABCD[4],u32 X[16])380 md5_hash( u32 ABCD[4], u32 X[16] )
381 {
382 u32 a = ABCD[3];
383 u32 b = ABCD[2];
384 u32 c = ABCD[1];
385 u32 d = ABCD[0];
386 int t;
387 int i;
388
389 #ifdef WORDS_BIGENDIAN
390 for (i = 0; i < 16; i++)
391 X[i] = BSWAP32(X[i]);
392 #endif
393
394 for (i = 0; i < 64; i++) {
395 t = S[i>>4][i&3];
396 a += T[i];
397 switch (i>>4) {
398 case 0: a += (d ^ (b&(c^d))) + X[ i &15]; break;
399 case 1: a += (c ^ (d&(c^b))) + X[(1+5*i)&15]; break;
400 case 2: a += (b^c^d) + X[(5+3*i)&15]; break;
401 case 3: a += (c^(b|~d)) + X[( 7*i)&15]; break;
402 }
403 a = b + ((a << t) | (a >> (32 - t)));
404 t = d; d = c; c = b; b = a; a = t;
405 }
406
407 ABCD[0] += d;
408 ABCD[1] += c;
409 ABCD[2] += b;
410 ABCD[3] += a;
411 }
412
413 void
direct_md5_sum(void * dst,const void * src,const int len)414 direct_md5_sum( void *dst, const void *src, const int len )
415 {
416 u8 block[64];
417 u32 ABCD[4];
418 int i, j;
419
420 D_ASSERT( dst != NULL );
421 D_ASSERT( src != NULL );
422
423 ABCD[0] = 0x10325476;
424 ABCD[1] = 0x98badcfe;
425 ABCD[2] = 0xefcdab89;
426 ABCD[3] = 0x67452301;
427
428 for (i = 0, j = 0; i < len; i++) {
429 block[j++] = ((const u8*)src)[i];
430 if (j == 64) {
431 md5_hash( ABCD, (u32*)block );
432 j = 0;
433 }
434 }
435
436 block[j++] = 0x80;
437 memset( &block[j], 0, 64-j );
438
439 if (j > 56) {
440 md5_hash( ABCD, (u32*)block );
441 memset( block, 0, 64 );
442 }
443
444 for (i = 0; i < 8; i++)
445 block[56+i] = ((u64)len << 3) >> (i << 3);
446
447 md5_hash( ABCD, (u32*)block );
448
449 for (i = 0; i < 4; i++)
450 #ifdef WORDS_BIGENDIAN
451 ((u32*)dst)[i] = BSWAP32(ABCD[3-i]);
452 #else
453 ((u32*)dst)[i] = ABCD[3-i];
454 #endif
455 }
456