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