1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7 
8 #define _GNU_SOURCE
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #ifdef _WIN32
16   #include <windows.h>
17   #include <io.h>
18 #else
19   #include <sys/time.h>
20 #endif
21 
22 #include "util.h"
23 
24 void
solv_oom(size_t num,size_t len)25 solv_oom(size_t num, size_t len)
26 {
27   if (num)
28     fprintf(stderr, "Out of memory allocating %zu*%zu bytes!\n", num, len);
29   else
30     fprintf(stderr, "Out of memory allocating %zu bytes!\n", len);
31   abort();
32   exit(1);
33 }
34 
35 void *
solv_malloc(size_t len)36 solv_malloc(size_t len)
37 {
38   void *r = malloc(len ? len : 1);
39   if (!r)
40     solv_oom(0, len);
41   return r;
42 }
43 
44 void *
solv_malloc2(size_t num,size_t len)45 solv_malloc2(size_t num, size_t len)
46 {
47   if (len && (num * len) / len != num)
48     solv_oom(num, len);
49   return solv_malloc(num * len);
50 }
51 
52 void *
solv_realloc(void * old,size_t len)53 solv_realloc(void *old, size_t len)
54 {
55   if (old == 0)
56     old = malloc(len ? len : 1);
57   else
58     old = realloc(old, len ? len : 1);
59   if (!old)
60     solv_oom(0, len);
61   return old;
62 }
63 
64 void *
solv_realloc2(void * old,size_t num,size_t len)65 solv_realloc2(void *old, size_t num, size_t len)
66 {
67   if (len && (num * len) / len != num)
68     solv_oom(num, len);
69   return solv_realloc(old, num * len);
70 }
71 
72 void *
solv_calloc(size_t num,size_t len)73 solv_calloc(size_t num, size_t len)
74 {
75   void *r;
76   if (num == 0 || len == 0)
77     r = malloc(1);
78   else
79     r = calloc(num, len);
80   if (!r)
81     solv_oom(num, len);
82   return r;
83 }
84 
85 /* this was solv_realloc2(old, len, size), but we now overshoot
86  * for huge len sizes */
87 void *
solv_extend_realloc(void * old,size_t len,size_t size,size_t block)88 solv_extend_realloc(void *old, size_t len, size_t size, size_t block)
89 {
90   size_t xblock = (block + 1) << 5;
91   len = (len + block) & ~block;
92   if (len >= xblock && xblock)
93     {
94       xblock <<= 1;
95       while (len >= xblock && xblock)
96 	xblock <<= 1;
97       if (xblock)
98 	{
99 	  size_t nlen;
100           xblock = (xblock >> 5) - 1;
101 	  nlen = (len + xblock) & ~xblock;
102 	  if (nlen > len)
103 	    len = nlen;
104 	}
105     }
106   return solv_realloc2(old, len, size);
107 }
108 
109 void *
solv_free(void * mem)110 solv_free(void *mem)
111 {
112   if (mem)
113     free(mem);
114   return 0;
115 }
116 
117 char *
solv_strdup(const char * s)118 solv_strdup(const char *s)
119 {
120   char *r;
121   if (!s)
122     return 0;
123   r = strdup(s);
124   if (!r)
125     solv_oom(0, strlen(s));
126   return r;
127 }
128 
129 unsigned int
solv_timems(unsigned int subtract)130 solv_timems(unsigned int subtract)
131 {
132 #ifdef _WIN32
133   return GetTickCount() - subtract;
134 #else
135   struct timeval tv;
136   unsigned int r;
137 
138   if (gettimeofday(&tv, 0))
139     return 0;
140   r = (((unsigned int)tv.tv_sec >> 16) * 1000) << 16;
141   r += ((unsigned int)tv.tv_sec & 0xffff) * 1000;
142   r += (unsigned int)tv.tv_usec / 1000;
143   return r - subtract;
144 #endif
145 }
146 
147 int
solv_setcloexec(int fd,int state)148 solv_setcloexec(int fd, int state)
149 {
150   #ifdef _WIN32
151     return SetHandleInformation((HANDLE) _get_osfhandle(fd), HANDLE_FLAG_INHERIT, state ? 0 : HANDLE_FLAG_INHERIT);
152   #else
153     return fcntl(fd, F_SETFD, state ? FD_CLOEXEC : 0) == 0;
154   #endif
155 }
156 
157 /* bsd's qsort_r has different arguments, so we define our
158    own version in case we need to do some clever mapping
159 
160    see also: http://sources.redhat.com/ml/libc-alpha/2008-12/msg00003.html
161  */
162 #if (defined(__GLIBC__) || defined(__NEWLIB__)) && (defined(HAVE_QSORT_R) || defined(HAVE___QSORT_R))
163 
164 void
solv_sort(void * base,size_t nmemb,size_t size,int (* compar)(const void *,const void *,void *),void * compard)165 solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
166 {
167 # if defined(HAVE_QSORT_R)
168   qsort_r(base, nmemb, size, compar, compard);
169 # else
170   /* backported for SLE10-SP2 */
171   __qsort_r(base, nmemb, size, compar, compard);
172 # endif
173 
174 }
175 
176 #elif defined(HAVE_QSORT_R) /* not glibc, but has qsort_r() */
177 
178 struct solv_sort_data {
179   int (*compar)(const void *, const void *, void *);
180   void *compard;
181 };
182 
183 static int
solv_sort_helper(void * compard,const void * a,const void * b)184 solv_sort_helper(void *compard, const void *a, const void *b)
185 {
186   struct solv_sort_data *d = compard;
187   return (*d->compar)(a, b, d->compard);
188 }
189 
190 void
solv_sort(void * base,size_t nmemb,size_t size,int (* compar)(const void *,const void *,void *),void * compard)191 solv_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *compard)
192 {
193   struct solv_sort_data d;
194   d.compar = compar;
195   d.compard = compard;
196   qsort_r(base, nmemb, size, &d, solv_sort_helper);
197 }
198 
199 #else /* not glibc and no qsort_r() */
200 /* use own version of qsort if none available */
201 #include "qsort_r.c"
202 #endif
203 
204 char *
solv_dupjoin(const char * str1,const char * str2,const char * str3)205 solv_dupjoin(const char *str1, const char *str2, const char *str3)
206 {
207   int l1, l2, l3;
208   char *s, *str;
209   l1 = str1 ? strlen(str1) : 0;
210   l2 = str2 ? strlen(str2) : 0;
211   l3 = str3 ? strlen(str3) : 0;
212   s = str = solv_malloc(l1 + l2 + l3 + 1);
213   if (l1)
214     {
215       strcpy(s, str1);
216       s += l1;
217     }
218   if (l2)
219     {
220       strcpy(s, str2);
221       s += l2;
222     }
223   if (l3)
224     {
225       strcpy(s, str3);
226       s += l3;
227     }
228   *s = 0;
229   return str;
230 }
231 
232 char *
solv_dupappend(const char * str1,const char * str2,const char * str3)233 solv_dupappend(const char *str1, const char *str2, const char *str3)
234 {
235   char *str = solv_dupjoin(str1, str2, str3);
236   solv_free((void *)str1);
237   return str;
238 }
239 
240 int
solv_hex2bin(const char ** strp,unsigned char * buf,int bufl)241 solv_hex2bin(const char **strp, unsigned char *buf, int bufl)
242 {
243   const char *str = *strp;
244   int i;
245 
246   for (i = 0; i < bufl; i++)
247     {
248       int c = *str;
249       int d;
250       if (c >= '0' && c <= '9')
251         d = c - '0';
252       else if (c >= 'a' && c <= 'f')
253         d = c - ('a' - 10);
254       else if (c >= 'A' && c <= 'F')
255         d = c - ('A' - 10);
256       else
257 	break;
258       c = str[1];
259       d <<= 4;
260       if (c >= '0' && c <= '9')
261         d |= c - '0';
262       else if (c >= 'a' && c <= 'f')
263         d |= c - ('a' - 10);
264       else if (c >= 'A' && c <= 'F')
265         d |= c - ('A' - 10);
266       else
267 	break;
268       buf[i] = d;
269       str += 2;
270     }
271   *strp = str;
272   return i;
273 }
274 
275 char *
solv_bin2hex(const unsigned char * buf,int l,char * str)276 solv_bin2hex(const unsigned char *buf, int l, char *str)
277 {
278   int i;
279   for (i = 0; i < l; i++, buf++)
280     {
281       int c = *buf >> 4;
282       *str++ = c < 10 ? c + '0' : c + ('a' - 10);
283       c = *buf & 15;
284       *str++ = c < 10 ? c + '0' : c + ('a' - 10);
285     }
286   *str = 0;
287   return str;
288 }
289 
290 size_t
solv_validutf8(const char * buf)291 solv_validutf8(const char *buf)
292 {
293   const unsigned char *p;
294   int x;
295 
296   for (p = (const unsigned char *)buf; (x = *p) != 0; p++)
297     {
298       if (x < 0x80)
299 	continue;
300       if (x < 0xc0)
301 	break;
302       if (x < 0xe0)
303 	{
304 	  /* one byte to follow */
305 	  if ((p[1] & 0xc0) != 0x80)
306 	    break;
307 	  if ((x & 0x1e) == 0)
308 	    break;	/* not minimal */
309 	  p += 1;
310 	  continue;
311 	}
312       if (x < 0xf0)
313 	{
314 	  /* two bytes to follow */
315 	  if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80)
316 	    break;
317 	  if ((x & 0x0f) == 0 && (p[1] & 0x20) == 0)
318 	    break;	/* not minimal */
319 	  if (x == 0xed && (p[1] & 0x20) != 0)
320 	    break;	/* d800-dfff surrogate */
321 	  if (x == 0xef && p[1] == 0xbf && (p[2] == 0xbe || p[2] == 0xbf))
322 	    break;	/* fffe or ffff */
323 	  p += 2;
324 	  continue;
325 	}
326       if (x < 0xf8)
327 	{
328 	  /* three bytes to follow */
329 	  if ((p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80)
330 	    break;
331 	  if ((x & 0x07) == 0 && (p[1] & 0x30) == 0)
332 	    break;	/* not minimal */
333 	  if ((x & 0x07) > 4 || ((x & 0x07) == 4 && (p[1] & 0x30) != 0))
334 	    break;	/* above 0x10ffff */
335 	  p += 3;
336 	  continue;
337 	}
338       break;	/* maybe valid utf8, but above 0x10ffff */
339     }
340   return (const char *)p - buf;
341 }
342 
343 char *
solv_latin1toutf8(const char * buf)344 solv_latin1toutf8(const char *buf)
345 {
346   int l = 1;
347   const char *p;
348   char *r, *rp;
349 
350   for (p = buf; *p; p++)
351     if ((*(const unsigned char *)p & 128) != 0)
352       l++;
353   r = rp = solv_malloc(p - buf + l);
354   for (p = buf; *p; p++)
355     {
356       if ((*(const unsigned char *)p & 128) != 0)
357 	{
358 	  *rp++ = *(const unsigned char *)p & 64 ? 0xc3 : 0xc2;
359 	  *rp++ = *p & 0xbf;
360 	}
361       else
362         *rp++ = *p;
363     }
364   *rp = 0;
365   return r;
366 }
367 
368 char *
solv_replacebadutf8(const char * buf,int replchar)369 solv_replacebadutf8(const char *buf, int replchar)
370 {
371   size_t l, nl;
372   const char *p;
373   char *r = 0, *rp = 0;
374   int repllen, replin;
375 
376   if (replchar < 0 || replchar > 0x10ffff)
377     replchar = 0xfffd;
378   if (!replchar)
379     repllen = replin = 0;
380   else if (replchar < 0x80)
381     {
382       repllen = 1;
383       replin = (replchar & 0x40) | 0x80;
384     }
385   else if (replchar < 0x800)
386     {
387       repllen = 2;
388       replin = 0x40;
389     }
390   else if (replchar < 0x10000)
391     {
392       repllen = 3;
393       replin = 0x60;
394     }
395   else
396     {
397       repllen = 4;
398       replin = 0x70;
399     }
400   for (;;)
401     {
402       for (p = buf, nl = 0; *p; )
403 	{
404 	  l = solv_validutf8(p);
405 	  if (rp && l)
406 	    {
407 	      memcpy(rp, p, l);
408 	      rp += l;
409 	    }
410 	  nl += l;
411 	  p += l;
412 	  if (!*p)
413 	    break;
414 	  /* found a bad char, replace with replchar */
415 	  if (rp && replchar)
416 	    {
417 	      switch (repllen)
418 		{
419 		case 4:
420 		  *rp++ = (replchar >> 18 & 0x3f) | 0x80;
421 		case 3:
422 		  *rp++ = (replchar >> 12 & 0x3f) | 0x80;
423 		case 2:
424 		  *rp++ = (replchar >> 6  & 0x3f) | 0x80;
425 		default:
426 		  *rp++ = (replchar       & 0x3f) | 0x80;
427 		}
428 	      rp[-repllen] ^= replin;
429 	    }
430 	  nl += repllen;
431 	  p++;
432 	  while ((*(const unsigned char *)p & 0xc0) == 0x80)
433 	    p++;
434 	}
435       if (rp)
436 	break;
437       r = rp = solv_malloc(nl + 1);
438     }
439   *rp = 0;
440   return r;
441 }
442 
443