PageRenderTime 107ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/user/firefly/mt-daapd-svn/src/util.c

https://bitbucket.org/altlc/wive-rtnl-ralink-rt305x-routers-firmware-amod
C | 725 lines | 515 code | 125 blank | 85 comment | 123 complexity | fe59051f8b056a3babbcf80a101d7ff1 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, GPL-3.0, LGPL-3.0, 0BSD, AGPL-1.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. * simple utility functions
  3. */
  4. #ifdef HAVE_CONFIG_H
  5. # include "config.h"
  6. #endif
  7. #include <errno.h>
  8. #include <pthread.h>
  9. #ifdef HAVE_STDINT_H
  10. # include <stdint.h>
  11. #endif
  12. #include <stdio.h>
  13. #include <stdarg.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <sys/types.h>
  17. #ifdef HAVE_ICONV
  18. # include <iconv.h>
  19. #endif
  20. #include "daapd.h"
  21. #include "err.h"
  22. #include "util.h"
  23. /* Globals */
  24. pthread_mutex_t util_locks[(int)l_last];
  25. pthread_mutex_t util_mutex = PTHREAD_MUTEX_INITIALIZER;
  26. int _util_initialized=0;
  27. /* Forwards */
  28. void _util_mutex_init(void);
  29. /**
  30. * Simple hash generator
  31. */
  32. uint32_t util_djb_hash_block(unsigned char *data, uint32_t len) {
  33. uint32_t hash = 5381;
  34. unsigned char *pstr = data;
  35. while(len--) {
  36. hash = ((hash << 5) + hash) + *pstr;
  37. pstr++;
  38. }
  39. return hash;
  40. }
  41. /**
  42. * simple hash generator
  43. */
  44. uint32_t util_djb_hash_str(char *str) {
  45. uint32_t len;
  46. len = (uint32_t)strlen(str);
  47. return util_djb_hash_block((unsigned char *)str,len);
  48. }
  49. /**
  50. * Dumb utility function that should probably be somehwere else
  51. */
  52. int util_must_exit(void) {
  53. return config.stop;
  54. }
  55. #ifdef HAVE_ICONV
  56. int util_utf8toutf16(unsigned char *utf16, int dlen, unsigned char *utf8, int slen) {
  57. int result;
  58. DPRINTF(E_DBG,L_MISC,"Converting %s to utf-16le (slen=%d, dlen=%d)\n",utf8,slen,dlen);
  59. result=util_xtoy(utf16, dlen, utf8, slen, "UTF-8","UTF-16LE");
  60. DPRINTF(E_DBG,L_MISC,"Result: %d\n",result);
  61. // _util_hexdump(utf16,32);
  62. return result;
  63. }
  64. int util_utf16toutf8(unsigned char *utf8, int dlen, unsigned char *utf16, int slen) {
  65. int result;
  66. DPRINTF(E_DBG,L_MISC,"Converting *something* to utf-8 (slen=%d, dlen=%d)\n",slen,dlen);
  67. // _util_hexdump(utf16,32);
  68. result = util_xtoy(utf8, dlen, utf16, slen, "UTF-16LE","UTF-8");
  69. DPRINTF(E_DBG,L_MISC,"Converted to %s\n",utf8);
  70. return result;
  71. }
  72. int util_utf16_byte_len(unsigned char *utf16) {
  73. unsigned char *src = utf16;
  74. int len = 0;
  75. while(1) {
  76. if((src[0] == 0) && (src[1]==0))
  77. return len;
  78. len += 2;
  79. src += 2;
  80. }
  81. return len; /* ?? */
  82. }
  83. unsigned char *util_utf8toutf16_alloc(unsigned char *utf8) {
  84. unsigned char *utf16;
  85. utf16 = calloc(1,strlen((char*)utf8) * 4 + 1);
  86. if(util_xtoy(utf16,strlen((char*)utf8) * 4 + 1, utf8, strlen((char*)utf8),"UTF-8","UTF-16LE")) {
  87. return utf16;
  88. }
  89. free(utf16);
  90. return NULL;
  91. }
  92. unsigned char *util_utf16toutf8_alloc(unsigned char *utf16, int slen) {
  93. unsigned char *utf8;
  94. utf8=calloc(1, slen * 2 + 1);
  95. if(util_xtoy(utf8,slen * 2 + 1,utf16,slen,"UTF-16LE","UTF-8")) {
  96. return utf8;
  97. }
  98. free(utf8);
  99. return NULL;
  100. }
  101. unsigned char *util_xtoutf8_alloc(unsigned char *x, int slen, char *from) {
  102. unsigned char *utf8;
  103. utf8 = calloc(1, slen * 4 + 1);
  104. if(util_xtoy(utf8,slen * 4 + 1, x, slen, from, "UTF-8")) {
  105. return utf8;
  106. }
  107. free(utf8);
  108. return NULL;
  109. }
  110. int util_xtoy(unsigned char *dbuffer, int dlen, unsigned char *sbuffer, int slen, char *from, char *to) {
  111. iconv_t iv;
  112. size_t csize;
  113. /* type punning warnings */
  114. size_t st_dlen = (size_t)dlen;
  115. size_t st_slen = (size_t)slen;
  116. char *st_dbuffer = (char*)dbuffer;
  117. ICONV_CONST char *st_sbuffer = (char*)sbuffer;
  118. memset(dbuffer,0,dlen);
  119. iv=iconv_open(to,from);
  120. if(iv == (iconv_t)-1) {
  121. DPRINTF(E_LOG,L_MISC,"iconv error: iconv_open failed with %d\n",errno);
  122. }
  123. csize = iconv(iv,&st_sbuffer,&st_slen,
  124. &st_dbuffer,&st_dlen);
  125. if(csize == (size_t)-1) {
  126. switch(errno) {
  127. case EILSEQ:
  128. DPRINTF(E_LOG,L_MISC,"iconv error: Invalid multibyte sequence\n");
  129. break;
  130. case EINVAL:
  131. DPRINTF(E_LOG,L_MISC,"iconv error: Incomplete multibyte sequence\n");
  132. break;
  133. case E2BIG:
  134. DPRINTF(E_LOG,L_MISC,"iconv error: Insufficient buffer size\n");
  135. break;
  136. default:
  137. DPRINTF(E_LOG,L_MISC,"iconv error: unknown (%d)\n",errno);
  138. break;
  139. }
  140. }
  141. iconv_close(iv);
  142. return (csize != (size_t)-1);
  143. }
  144. #else
  145. /* homerolled conversions */
  146. int util_utf16_byte_len(unsigned char *utf16) {
  147. unsigned char *src = utf16;
  148. int len = 0;
  149. while(1) {
  150. if((src[0] == 0) && (src[1]==0))
  151. return len;
  152. len += 2;
  153. src += 2;
  154. }
  155. return len; /* ?? */
  156. }
  157. /**
  158. * calculate how long a utf16le string will be once converted
  159. */
  160. int util_utf16toutf8_len(unsigned char *utf16, int len) {
  161. unsigned char *src = utf16;
  162. int out_len = 0;
  163. uint32_t temp_dword;
  164. while(src+2 <= utf16 + len) {
  165. temp_dword = src[1] << 8 | src[0];
  166. if((temp_dword & 0xFC00) == 0xD800) {
  167. src += 2;
  168. if(src + 2 <= utf16 + len) {
  169. out_len += 4;
  170. } else {
  171. return -1;
  172. }
  173. } else {
  174. if(temp_dword <= 0x7F)
  175. out_len += 1;
  176. else if(temp_dword <= 0x7FF)
  177. out_len += 2;
  178. else if(temp_dword <= 0xFFFF)
  179. out_len += 3;
  180. }
  181. src += 2;
  182. }
  183. return out_len;
  184. }
  185. /**
  186. * convert utf16 string to utf8. This is a bit naive, but...
  187. * Since utf-8 can't expand past 4 bytes per code point, and
  188. * we're converting utf-16, we can't be more than 2n+1 bytes, so
  189. * we'll just allocate that much.
  190. *
  191. * Probably it could be more efficiently calculated, but this will
  192. * always work. Besides, these are small strings, and will be freed
  193. * after the db insert.
  194. *
  195. * We assume this is utf-16LE, as it comes from windows
  196. *
  197. * @param utf16 utf-16 to convert
  198. * @param len length of utf-16 string
  199. */
  200. int util_utf16toutf8(unsigned char *utf8, int dlen, unsigned char *utf16, int len) {
  201. unsigned char *src=utf16;
  202. unsigned char *dst;
  203. unsigned int w1, w2;
  204. int bytes;
  205. int new_len;
  206. if(!len)
  207. return FALSE;
  208. new_len = util_utf16toutf8_len(utf16,len);
  209. if((new_len == -1) || (dlen <= new_len)) {
  210. DPRINTF(E_LOG,L_MISC,"Cannot convert %s to utf8; E2BIG (%d vs %d)\n",utf8,new_len,dlen);
  211. return FALSE;
  212. }
  213. dst=utf8;
  214. while((src+2) <= utf16+len) {
  215. w1=src[1] << 8 | src[0];
  216. src += 2;
  217. if((w1 & 0xFC00) == 0xD800) { // could be surrogate pair
  218. if(src+2 > utf16+len) {
  219. DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
  220. return FALSE;
  221. }
  222. w2 = src[3] << 8 | src[2];
  223. if((w2 & 0xFC00) != 0xDC00) {
  224. DPRINTF(E_INF,L_SCAN,"Invalid utf-16 in file\n");
  225. return FALSE;
  226. }
  227. // get bottom 10 of each
  228. w1 = w1 & 0x03FF;
  229. w1 = w1 << 10;
  230. w1 = w1 | (w2 & 0x03FF);
  231. // add back the 0x10000
  232. w1 += 0x10000;
  233. }
  234. // now encode the original code point in utf-8
  235. if (w1 < 0x80) {
  236. *dst++ = w1;
  237. bytes=0;
  238. } else if (w1 < 0x800) {
  239. *dst++ = 0xC0 | (w1 >> 6);
  240. bytes=1;
  241. } else if (w1 < 0x10000) {
  242. *dst++ = 0xE0 | (w1 >> 12);
  243. bytes=2;
  244. } else {
  245. *dst++ = 0xF0 | (w1 >> 18);
  246. bytes=3;
  247. }
  248. while(bytes) {
  249. *dst++ = 0x80 | ((w1 >> (6*(bytes-1))) & 0x3f);
  250. bytes--;
  251. }
  252. }
  253. *dst = '\x0';
  254. return new_len;
  255. }
  256. /**
  257. * calculate how long a utf8 string will be once converted
  258. */
  259. int util_utf8toutf16_len(unsigned char *utf8) {
  260. int len,out_len,trailing_bytes;
  261. unsigned char *src = utf8;
  262. len=(int)strlen((char *)utf8);
  263. out_len = 0;
  264. while(src < utf8 + len) {
  265. trailing_bytes = 0;
  266. if((*src & 0xE0) == 0xC0) trailing_bytes = 1;
  267. else if((*src & 0xF0) == 0xE0) trailing_bytes = 2;
  268. else if((*src & 0xF8) == 0xF0) trailing_bytes = 3;
  269. if(src + trailing_bytes > utf8 + len)
  270. return -1;
  271. out_len += 2;
  272. if(trailing_bytes == 3) /* surrogate pair */
  273. out_len += 2;
  274. src += (1 + trailing_bytes);
  275. }
  276. out_len += 1;
  277. return out_len;
  278. }
  279. unsigned char *util_utf8toutf16_alloc(unsigned char *utf8) {
  280. unsigned char *out;
  281. int new_len;
  282. new_len = util_utf8toutf16_len(utf8);
  283. if(new_len == -1)
  284. return NULL;
  285. out = calloc(1,new_len + 2);
  286. if(!util_utf8toutf16(out,new_len + 2,utf8,(int)strlen((char*)utf8))) {
  287. free(out);
  288. return NULL;
  289. }
  290. return out;
  291. }
  292. unsigned char *util_utf16touft8_alloc(unsigned char *utf16, int len) {
  293. unsigned char *out;
  294. int new_len;
  295. new_len = util_utf16toutf8_len(utf16,len);
  296. if(new_len == -1)
  297. return NULL;
  298. out = calloc(1,new_len + 1);
  299. if(!util_utf16toutf8(out,new_len + 1,utf16,len)) {
  300. free(out);
  301. return NULL;
  302. }
  303. return out;
  304. }
  305. int util_utf8toutf16(unsigned char *utf16, int dlen, unsigned char *utf8, int len) {
  306. unsigned char *src=utf8;
  307. unsigned char *dst;
  308. int new_len;
  309. int trailing_bytes;
  310. uint32_t utf32;
  311. uint16_t temp_word;
  312. len=(int)strlen((char*)utf8); /* ignore passed length, might be wrong! */
  313. if(!len)
  314. return FALSE;
  315. new_len = util_utf8toutf16_len(utf8);
  316. if((new_len == -1) || (dlen <= (new_len+1))) {
  317. DPRINTF(E_LOG,L_MISC,"Cannot convert %s to utf16; E2BIG (%d vs %d)\n",utf8,new_len,dlen);
  318. return FALSE;
  319. }
  320. dst=utf16;
  321. while(src < utf8 + len) {
  322. utf32=0;
  323. trailing_bytes=0;
  324. if((*src & 0xE0) == 0xC0) trailing_bytes = 1;
  325. else if((*src & 0xF0) == 0xE0) trailing_bytes = 2;
  326. else if((*src & 0xF8) == 0xF0) trailing_bytes = 3;
  327. if(src + trailing_bytes > utf8 + len) {
  328. DPRINTF(E_LOG,L_SCAN,"Invalid UTF8 string\n");
  329. return FALSE;
  330. }
  331. switch(trailing_bytes) {
  332. case 0:
  333. utf32 = *src;
  334. break;
  335. case 1:
  336. utf32 = ((src[0] & 0x1F) << 6) |
  337. (src[1] & 0x3F);
  338. break;
  339. case 2:
  340. utf32 = ((src[0] & 0x0F) << 12) |
  341. ((src[1] & 0x3F) << 6) |
  342. ((src[2] & 0x3F));
  343. break;
  344. case 3:
  345. utf32 = ((src[0] & 0x07) << 18) |
  346. ((src[1] & 0x3F) << 12) |
  347. ((src[2] & 0x3F) << 6) |
  348. ((src[3] & 0x3F));
  349. break;
  350. }
  351. if(utf32 <= 0xFFFF) {
  352. /* we are encoding LE style... */
  353. *dst++ = utf32 & 0xFF;
  354. *dst++ = (utf32 & 0xFF00) >> 8;
  355. } else {
  356. /* Encode with surrogates */
  357. temp_word = 0xD800 | ((utf32 & 0x0FFC00) >> 10);
  358. *dst++ = temp_word & 0xFF;
  359. *dst++ = (temp_word & 0xFF00) >> 8;
  360. temp_word = 0xDC00 | (utf32 & 0x3FF);
  361. *dst++ = temp_word & 0xFF;
  362. *dst++ = (temp_word & 0xFF00) >> 8;
  363. }
  364. src += (trailing_bytes + 1);
  365. }
  366. *dst++ = '\x0';
  367. *dst = '\x0';
  368. return new_len;
  369. }
  370. #endif
  371. void util_hexdump(unsigned char *block, int len) {
  372. char charmap[256];
  373. int index;
  374. int row, offset;
  375. char output[80];
  376. char tmp[20];
  377. memset(charmap,'.',sizeof(charmap));
  378. for(index=' ';index<'~';index++) charmap[index]=index;
  379. for(row=0;row<(len+15)/16;row++) {
  380. sprintf(output,"%04X: ",row*16);
  381. for(offset=0; offset < 16; offset++) {
  382. if(row * 16 + offset < len) {
  383. sprintf(tmp,"%02X ",block[row*16 + offset]);
  384. } else {
  385. sprintf(tmp," ");
  386. }
  387. strcat(output,tmp);
  388. }
  389. for(offset=0; offset < 16; offset++) {
  390. if(row * 16 + offset < len) {
  391. sprintf(tmp,"%c",charmap[block[row*16 + offset]]);
  392. } else {
  393. sprintf(tmp," ");
  394. }
  395. strcat(output,tmp);
  396. }
  397. DPRINTF(E_LOG,L_MISC,"%s\n",output);
  398. }
  399. }
  400. /**
  401. * simple mutex wrapper for better debugging
  402. */
  403. void util_mutex_lock(ff_lock_t which) {
  404. if(!_util_initialized)
  405. _util_mutex_init();
  406. if(pthread_mutex_lock(&util_locks[(int)which])) {
  407. fprintf(stderr,"Cannot lock mutex\n");
  408. exit(-1);
  409. }
  410. }
  411. /**
  412. * simple mutex wrapper for better debugging
  413. */
  414. void util_mutex_unlock(ff_lock_t which) {
  415. if(pthread_mutex_unlock(&util_locks[(int)which])) {
  416. fprintf(stderr,"Cannot unlock mutex\n");
  417. exit(-1);
  418. }
  419. }
  420. /**
  421. * mutex initializer. This might should be done from the
  422. * main thread.
  423. */
  424. void _util_mutex_init(void) {
  425. int err;
  426. ff_lock_t lock;
  427. if((err = pthread_mutex_lock(&util_mutex))) {
  428. fprintf(stderr,"Error locking mutex\n");
  429. exit(-1);
  430. }
  431. if(!_util_initialized) {
  432. /* now, walk through and manually initialize the mutexes */
  433. for(lock=(ff_lock_t)0; lock < l_last; lock++) {
  434. if((err = pthread_mutex_init(&util_locks[(int)lock],NULL))) {
  435. fprintf(stderr,"Error initializing mutex\n");
  436. exit(-1);
  437. }
  438. }
  439. _util_initialized=1;
  440. }
  441. pthread_mutex_unlock(&util_mutex);
  442. }
  443. /**
  444. * split a string on delimiter boundaries, filling
  445. * a string-pointer array.
  446. *
  447. * The user must free both the first element in the array,
  448. * and the array itself.
  449. *
  450. * @param s string to split
  451. * @param delimiters boundaries to split on
  452. * @param argvp an argv array to be filled
  453. * @returns number of tokens
  454. */
  455. int util_split(char *s, char *delimiters, char ***argvp) {
  456. int i;
  457. int numtokens;
  458. const char *snew;
  459. char *t;
  460. char *tokptr;
  461. char *tmp;
  462. char *fix_src, *fix_dst;
  463. if ((s == NULL) || (delimiters == NULL) || (argvp == NULL))
  464. return -1;
  465. *argvp = NULL;
  466. snew = s + strspn(s, delimiters);
  467. if ((t = malloc(strlen(snew) + 1)) == NULL)
  468. return -1;
  469. strcpy(t, snew);
  470. numtokens = 1;
  471. tokptr = NULL;
  472. tmp = t;
  473. tmp = s;
  474. while(*tmp) {
  475. if(strchr(delimiters,*tmp) && (*(tmp+1) == *tmp)) {
  476. tmp += 2;
  477. } else if(strchr(delimiters,*tmp)) {
  478. numtokens++;
  479. tmp++;
  480. } else {
  481. tmp++;
  482. }
  483. }
  484. DPRINTF(E_DBG,L_CONF,"Found %d tokens in %s\n",numtokens,s);
  485. if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) {
  486. free(t);
  487. return -1;
  488. }
  489. if (numtokens == 0)
  490. free(t);
  491. else {
  492. tokptr = t;
  493. tmp = t;
  494. for (i = 0; i < numtokens; i++) {
  495. while(*tmp) {
  496. if(strchr(delimiters,*tmp) && (*(tmp+1) != *tmp))
  497. break;
  498. if(strchr(delimiters,*tmp)) {
  499. tmp += 2;
  500. } else {
  501. tmp++;
  502. }
  503. }
  504. *tmp = '\0';
  505. tmp++;
  506. (*argvp)[i] = tokptr;
  507. fix_src = fix_dst = tokptr;
  508. while(*fix_src) {
  509. if(strchr(delimiters,*fix_src) && (*(fix_src+1) == *fix_src)) {
  510. fix_src++;
  511. }
  512. *fix_dst++ = *fix_src++;
  513. }
  514. *fix_dst = '\0';
  515. tokptr = tmp;
  516. DPRINTF(E_DBG,L_CONF,"Token %d: %s\n",i+1,(*argvp)[i]);
  517. }
  518. }
  519. *((*argvp) + numtokens) = NULL;
  520. return numtokens;
  521. }
  522. /**
  523. * dispose of the argv set that was created in util_split
  524. *
  525. * @param argv string array to delete
  526. */
  527. void util_dispose_split(char **argv) {
  528. if(!argv)
  529. return;
  530. if(argv[0])
  531. free(argv[0]);
  532. free(argv);
  533. }
  534. /**
  535. * Write a formatted string to an allocated string. Leverage
  536. * the existing util_vasprintf to do so
  537. */
  538. char *util_asprintf(char *fmt, ...) {
  539. char *outbuf;
  540. va_list ap;
  541. ASSERT(fmt);
  542. if(!fmt)
  543. return NULL;
  544. va_start(ap,fmt);
  545. outbuf = util_vasprintf(fmt, ap);
  546. va_end(ap);
  547. return outbuf;
  548. }
  549. /**
  550. * Write a formatted string to an allocated string. This deals with
  551. * versions of vsnprintf that return either the C99 way, or the pre-C99
  552. * way, by increasing the buffer until it works.
  553. *
  554. * @param
  555. * @param fmt format string of print (compatible with printf(2))
  556. * @returns TRUE on success
  557. */
  558. #ifdef HAVE_VA_COPY
  559. # define VA_COPY(a,b) va_copy((a),(b))
  560. #else
  561. # ifdef HAVE___VA_COPY
  562. # define VA_COPY(a,b) __va_copy((a),(b))
  563. # else
  564. # define VA_COPY(a,b) memcpy((&a),(&b),sizeof(b))
  565. # endif
  566. #endif
  567. char *util_vasprintf(char *fmt, va_list ap) {
  568. char *outbuf;
  569. char *newbuf;
  570. va_list ap2;
  571. int size=200;
  572. int new_size;
  573. outbuf = (char*)malloc(size);
  574. if(!outbuf)
  575. DPRINTF(E_FATAL,L_MISC,"Could not allocate buffer in vasprintf\n");
  576. VA_COPY(ap2,ap);
  577. while(1) {
  578. new_size=vsnprintf(outbuf,size,fmt,ap);
  579. if(new_size > -1 && new_size < size)
  580. break;
  581. if(new_size > -1)
  582. size = new_size + 1;
  583. else
  584. size *= 2;
  585. if((newbuf = realloc(outbuf,size)) == NULL) {
  586. free(outbuf);
  587. DPRINTF(E_FATAL,L_MISC,"malloc error in vasprintf\n");
  588. exit(1);
  589. }
  590. outbuf = newbuf;
  591. VA_COPY(ap,ap2);
  592. }
  593. return outbuf;
  594. }
  595. #ifdef DEBUG_MEM
  596. void *util_malloc(char *file, char *line, size_t size);
  597. void *util_calloc(char *file, char *line, size_t count, size_t size);
  598. void *util_realloc(char *file, char *line, void *ptr, size_t size);
  599. void util_free(void *ptr);
  600. #endif