1 /*
2  * This file Copyright (C) 2009-2017 Mnemosyne LLC
3  *
4  * It may be used under the GNU GPL versions 2 or 3
5  * or any future license endorsed by Mnemosyne LLC.
6  *
7  */
8 
9 #ifdef HAVE_MEMMEM
10 #define _GNU_SOURCE /* glibc's string.h needs this to pick up memmem */
11 #endif
12 
13 #if defined(XCODE_BUILD)
14 #define HAVE_GETPAGESIZE
15 #define HAVE_VALLOC
16 #endif
17 
18 #include <ctype.h> /* isdigit(), tolower() */
19 #include <errno.h>
20 #include <float.h> /* DBL_DIG */
21 #include <locale.h> /* localeconv() */
22 #include <math.h> /* fabs(), floor() */
23 #include <stdio.h>
24 #include <stdlib.h> /* getenv() */
25 #include <string.h> /* strerror(), memset(), memmem() */
26 #include <time.h> /* nanosleep() */
27 
28 #ifdef _WIN32
29 #include <ws2tcpip.h> /* WSAStartup() */
30 #include <windows.h> /* Sleep(), GetSystemTimeAsFileTime(), GetEnvironmentVariable() */
31 #include <shellapi.h> /* CommandLineToArgv() */
32 #include <shlwapi.h> /* StrStrIA() */
33 #else
34 #include <sys/time.h>
35 #include <unistd.h> /* getpagesize() */
36 #endif
37 
38 #ifdef HAVE_ICONV
39 #include <iconv.h>
40 #endif
41 
42 #include <event2/buffer.h>
43 #include <event2/event.h>
44 
45 #include "transmission.h"
46 #include "error.h"
47 #include "error-types.h"
48 #include "file.h"
49 #include "ConvertUTF.h"
50 #include "list.h"
51 #include "log.h"
52 #include "net.h"
53 #include "platform.h" /* tr_lockLock() */
54 #include "platform-quota.h" /* tr_device_info_create(), tr_device_info_get_free_space(), tr_device_info_free() */
55 #include "tr-assert.h"
56 #include "utils.h"
57 #include "variant.h"
58 #include "version.h"
59 
60 time_t __tr_current_time = 0;
61 
62 /***
63 ****
64 ***/
65 
tr_localtime_r(time_t const * _clock,struct tm * _result)66 struct tm* tr_localtime_r(time_t const* _clock, struct tm* _result)
67 {
68 #ifdef HAVE_LOCALTIME_R
69 
70     return localtime_r(_clock, _result);
71 
72 #else
73 
74     struct tm* p = localtime(_clock);
75 
76     if (p != NULL)
77     {
78         *(_result) = *p;
79     }
80 
81     return p;
82 
83 #endif
84 }
85 
tr_gettimeofday(struct timeval * tv)86 int tr_gettimeofday(struct timeval* tv)
87 {
88 #ifdef _WIN32
89 
90 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
91 
92     FILETIME ft;
93     uint64_t tmp = 0;
94 
95     if (tv == NULL)
96     {
97         errno = EINVAL;
98         return -1;
99     }
100 
101     GetSystemTimeAsFileTime(&ft);
102     tmp |= ft.dwHighDateTime;
103     tmp <<= 32;
104     tmp |= ft.dwLowDateTime;
105     tmp /= 10; /* to microseconds */
106     tmp -= DELTA_EPOCH_IN_MICROSECS;
107 
108     tv->tv_sec = tmp / 1000000UL;
109     tv->tv_usec = tmp % 1000000UL;
110 
111     return 0;
112 
113 #undef DELTA_EPOCH_IN_MICROSECS
114 
115 #else
116 
117     return gettimeofday(tv, NULL);
118 
119 #endif
120 }
121 
122 /***
123 ****
124 ***/
125 
tr_malloc(size_t size)126 void* tr_malloc(size_t size)
127 {
128     return size != 0 ? malloc(size) : NULL;
129 }
130 
tr_malloc0(size_t size)131 void* tr_malloc0(size_t size)
132 {
133     return size != 0 ? calloc(1, size) : NULL;
134 }
135 
tr_realloc(void * p,size_t size)136 void* tr_realloc(void* p, size_t size)
137 {
138     void* result = size != 0 ? realloc(p, size) : NULL;
139 
140     if (result == NULL)
141     {
142         tr_free(p);
143     }
144 
145     return result;
146 }
147 
tr_free(void * p)148 void tr_free(void* p)
149 {
150     if (p != NULL)
151     {
152         free(p);
153     }
154 }
155 
tr_free_ptrv(void * const * p)156 void tr_free_ptrv(void* const* p)
157 {
158     if (p == NULL)
159     {
160         return;
161     }
162 
163     while (*p != NULL)
164     {
165         tr_free(*p);
166         ++p;
167     }
168 }
169 
tr_memdup(void const * src,size_t byteCount)170 void* tr_memdup(void const* src, size_t byteCount)
171 {
172     return memcpy(tr_malloc(byteCount), src, byteCount);
173 }
174 
175 /***
176 ****
177 ***/
178 
tr_strip_positional_args(char const * str)179 char const* tr_strip_positional_args(char const* str)
180 {
181     char* out;
182     static size_t bufsize = 0;
183     static char* buf = NULL;
184     char const* in = str;
185     size_t const len = str != NULL ? strlen(str) : 0;
186 
187     if (buf == NULL || bufsize < len)
188     {
189         bufsize = len * 2 + 1;
190         buf = tr_renew(char, buf, bufsize);
191     }
192 
193     out = buf;
194 
195     for (; !tr_str_is_empty(str); ++str)
196     {
197         *out++ = *str;
198 
199         if (*str == '%' && isdigit(str[1]))
200         {
201             char const* tmp = str + 1;
202 
203             while (isdigit(*tmp))
204             {
205                 ++tmp;
206             }
207 
208             if (*tmp == '$')
209             {
210                 str = tmp[1] == '\'' ? tmp + 1 : tmp;
211             }
212         }
213 
214         if (*str == '%' && str[1] == '\'')
215         {
216             str = str + 1;
217         }
218     }
219 
220     *out = '\0';
221     return (in == NULL || strcmp(buf, in) != 0) ? buf : in;
222 }
223 
224 /**
225 ***
226 **/
227 
tr_timerAdd(struct event * timer,int seconds,int microseconds)228 void tr_timerAdd(struct event* timer, int seconds, int microseconds)
229 {
230     struct timeval tv;
231     tv.tv_sec = seconds;
232     tv.tv_usec = microseconds;
233 
234     TR_ASSERT(tv.tv_sec >= 0);
235     TR_ASSERT(tv.tv_usec >= 0);
236     TR_ASSERT(tv.tv_usec < 1000000);
237 
238     evtimer_add(timer, &tv);
239 }
240 
tr_timerAddMsec(struct event * timer,int msec)241 void tr_timerAddMsec(struct event* timer, int msec)
242 {
243     int const seconds = msec / 1000;
244     int const usec = (msec % 1000) * 1000;
245     tr_timerAdd(timer, seconds, usec);
246 }
247 
248 /**
249 ***
250 **/
251 
tr_loadFile(char const * path,size_t * size,tr_error ** error)252 uint8_t* tr_loadFile(char const* path, size_t* size, tr_error** error)
253 {
254     uint8_t* buf;
255     tr_sys_path_info info;
256     tr_sys_file_t fd;
257     tr_error* my_error = NULL;
258     char const* const err_fmt = _("Couldn't read \"%1$s\": %2$s");
259 
260     /* try to stat the file */
261     if (!tr_sys_path_get_info(path, 0, &info, &my_error))
262     {
263         tr_logAddDebug(err_fmt, path, my_error->message);
264         tr_error_propagate(error, &my_error);
265         return NULL;
266     }
267 
268     if (info.type != TR_SYS_PATH_IS_FILE)
269     {
270         tr_logAddError(err_fmt, path, _("Not a regular file"));
271         tr_error_set_literal(error, TR_ERROR_EISDIR, _("Not a regular file"));
272         return NULL;
273     }
274 
275     /* file size should be able to fit into size_t */
276     if (sizeof(info.size) > sizeof(*size))
277     {
278         TR_ASSERT(info.size <= SIZE_MAX);
279     }
280 
281     /* Load the torrent file into our buffer */
282     fd = tr_sys_file_open(path, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &my_error);
283 
284     if (fd == TR_BAD_SYS_FILE)
285     {
286         tr_logAddError(err_fmt, path, my_error->message);
287         tr_error_propagate(error, &my_error);
288         return NULL;
289     }
290 
291     buf = tr_malloc(info.size + 1);
292 
293     if (!tr_sys_file_read(fd, buf, info.size, NULL, &my_error))
294     {
295         tr_logAddError(err_fmt, path, my_error->message);
296         tr_sys_file_close(fd, NULL);
297         free(buf);
298         tr_error_propagate(error, &my_error);
299         return NULL;
300     }
301 
302     tr_sys_file_close(fd, NULL);
303     buf[info.size] = '\0';
304     *size = info.size;
305     return buf;
306 }
307 
tr_buildPath(char const * first_element,...)308 char* tr_buildPath(char const* first_element, ...)
309 {
310     char const* element;
311     char* buf;
312     char* pch;
313     va_list vl;
314     size_t bufLen = 0;
315 
316     /* pass 1: allocate enough space for the string */
317     va_start(vl, first_element);
318     element = first_element;
319 
320     while (element != NULL)
321     {
322         bufLen += strlen(element) + 1;
323         element = va_arg(vl, char const*);
324     }
325 
326     pch = buf = tr_new(char, bufLen);
327     va_end(vl);
328 
329     if (buf == NULL)
330     {
331         return NULL;
332     }
333 
334     /* pass 2: build the string piece by piece */
335     va_start(vl, first_element);
336     element = first_element;
337 
338     while (element != NULL)
339     {
340         size_t const elementLen = strlen(element);
341         memcpy(pch, element, elementLen);
342         pch += elementLen;
343         *pch++ = TR_PATH_DELIMITER;
344         element = va_arg(vl, char const*);
345     }
346 
347     va_end(vl);
348 
349     /* terminate the string. if nonempty, eat the unwanted trailing slash */
350     if (pch != buf)
351     {
352         --pch;
353     }
354 
355     *pch++ = '\0';
356 
357     /* sanity checks & return */
358     TR_ASSERT(pch - buf == (ptrdiff_t)bufLen);
359     return buf;
360 }
361 
tr_getDirFreeSpace(char const * dir)362 int64_t tr_getDirFreeSpace(char const* dir)
363 {
364     int64_t free_space;
365 
366     if (tr_str_is_empty(dir))
367     {
368         errno = EINVAL;
369         free_space = -1;
370     }
371     else
372     {
373         struct tr_device_info* info;
374         info = tr_device_info_create(dir);
375         free_space = tr_device_info_get_free_space(info);
376         tr_device_info_free(info);
377     }
378 
379     return free_space;
380 }
381 
382 /****
383 *****
384 ****/
385 
evbuffer_free_to_str(struct evbuffer * buf,size_t * result_len)386 char* evbuffer_free_to_str(struct evbuffer* buf, size_t* result_len)
387 {
388     size_t const n = evbuffer_get_length(buf);
389     char* ret = tr_new(char, n + 1);
390     evbuffer_copyout(buf, ret, n);
391     evbuffer_free(buf);
392     ret[n] = '\0';
393 
394     if (result_len != NULL)
395     {
396         *result_len = n;
397     }
398 
399     return ret;
400 }
401 
tr_strdup(void const * in)402 char* tr_strdup(void const* in)
403 {
404     return tr_strndup(in, in != NULL ? strlen(in) : 0);
405 }
406 
tr_strndup(void const * in,size_t len)407 char* tr_strndup(void const* in, size_t len)
408 {
409     char* out = NULL;
410 
411     if (len == TR_BAD_SIZE)
412     {
413         out = tr_strdup(in);
414     }
415     else if (in != NULL)
416     {
417         out = tr_malloc(len + 1);
418 
419         if (out != NULL)
420         {
421             memcpy(out, in, len);
422             out[len] = '\0';
423         }
424     }
425 
426     return out;
427 }
428 
tr_memmem(char const * haystack,size_t haystacklen,char const * needle,size_t needlelen)429 char const* tr_memmem(char const* haystack, size_t haystacklen, char const* needle, size_t needlelen)
430 {
431 #ifdef HAVE_MEMMEM
432 
433     return memmem(haystack, haystacklen, needle, needlelen);
434 
435 #else
436 
437     if (needlelen == 0)
438     {
439         return haystack;
440     }
441 
442     if (needlelen > haystacklen || haystack == NULL || needle == NULL)
443     {
444         return NULL;
445     }
446 
447     for (size_t i = 0; i <= haystacklen - needlelen; ++i)
448     {
449         if (memcmp(haystack + i, needle, needlelen) == 0)
450         {
451             return haystack + i;
452         }
453     }
454 
455     return NULL;
456 
457 #endif
458 }
459 
tr_strcasestr(char const * haystack,char const * needle)460 char const* tr_strcasestr(char const* haystack, char const* needle)
461 {
462 #ifdef HAVE_STRCASESTR
463 
464     return strcasestr(haystack, needle);
465 
466 #elif defined(_WIN32)
467 
468     return StrStrIA(haystack, needle);
469 
470 #else
471 
472 #error please open a PR to implement tr_strcasestr() for your platform
473 
474 #endif
475 }
476 
tr_strdup_printf(char const * fmt,...)477 char* tr_strdup_printf(char const* fmt, ...)
478 {
479     va_list ap;
480     char* ret;
481 
482     va_start(ap, fmt);
483     ret = tr_strdup_vprintf(fmt, ap);
484     va_end(ap);
485 
486     return ret;
487 }
488 
tr_strdup_vprintf(char const * fmt,va_list args)489 char* tr_strdup_vprintf(char const* fmt, va_list args)
490 {
491     struct evbuffer* buf = evbuffer_new();
492     evbuffer_add_vprintf(buf, fmt, args);
493     return evbuffer_free_to_str(buf, NULL);
494 }
495 
tr_strerror(int i)496 char const* tr_strerror(int i)
497 {
498     char const* ret = strerror(i);
499 
500     if (ret == NULL)
501     {
502         ret = "Unknown Error";
503     }
504 
505     return ret;
506 }
507 
tr_strcmp0(char const * str1,char const * str2)508 int tr_strcmp0(char const* str1, char const* str2)
509 {
510     if (str1 != NULL && str2 != NULL)
511     {
512         return strcmp(str1, str2);
513     }
514 
515     if (str1 != NULL)
516     {
517         return 1;
518     }
519 
520     if (str2 != NULL)
521     {
522         return -1;
523     }
524 
525     return 0;
526 }
527 
tr_memcmp0(void const * lhs,void const * rhs,size_t size)528 int tr_memcmp0(void const* lhs, void const* rhs, size_t size)
529 {
530     if (lhs != NULL && rhs != NULL)
531     {
532         return memcmp(lhs, rhs, size);
533     }
534 
535     if (lhs != NULL)
536     {
537         return 1;
538     }
539 
540     if (rhs != NULL)
541     {
542         return -1;
543     }
544 
545     return 0;
546 }
547 
548 /****
549 *****
550 ****/
551 
552 /* https://bugs.launchpad.net/percona-patches/+bug/526863/+attachment/1160199/+files/solaris_10_fix.patch */
tr_strsep(char ** str,char const * delims)553 char* tr_strsep(char** str, char const* delims)
554 {
555 #ifdef HAVE_STRSEP
556 
557     return strsep(str, delims);
558 
559 #else
560 
561     char* token;
562 
563     if (*str == NULL) /* no more tokens */
564     {
565         return NULL;
566     }
567 
568     token = *str;
569 
570     while (**str != '\0')
571     {
572         if (strchr(delims, **str) != NULL)
573         {
574             **str = '\0';
575             (*str)++;
576             return token;
577         }
578 
579         (*str)++;
580     }
581 
582     /* there is not another token */
583     *str = NULL;
584 
585     return token;
586 
587 #endif
588 }
589 
tr_strjoin(char const * const * arr,size_t len,char const * delim)590 char* tr_strjoin(char const* const* arr, size_t len, char const* delim)
591 {
592     size_t total_len = 1;
593     size_t delim_len = strlen(delim);
594     for (size_t i = 0; i < len; ++i)
595     {
596         total_len += strlen(arr[i]);
597     }
598 
599     total_len += len > 0 ? (len - 1) * delim_len : 0;
600 
601     char* const ret = tr_new(char, total_len);
602     char* p = ret;
603 
604     for (size_t i = 0; i < len; ++i)
605     {
606         if (i > 0)
607         {
608             memcpy(p, delim, delim_len);
609             p += delim_len;
610         }
611 
612         size_t const part_len = strlen(arr[i]);
613         memcpy(p, arr[i], part_len);
614         p += part_len;
615     }
616 
617     *p = '\0';
618     return ret;
619 }
620 
tr_strstrip(char * str)621 char* tr_strstrip(char* str)
622 {
623     if (str != NULL)
624     {
625         size_t len = strlen(str);
626 
627         while (len != 0 && isspace(str[len - 1]))
628         {
629             --len;
630         }
631 
632         size_t pos = 0;
633 
634         while (pos < len && isspace(str[pos]))
635         {
636             ++pos;
637         }
638 
639         len -= pos;
640         memmove(str, str + pos, len);
641         str[len] = '\0';
642     }
643 
644     return str;
645 }
646 
tr_str_has_suffix(char const * str,char const * suffix)647 bool tr_str_has_suffix(char const* str, char const* suffix)
648 {
649     size_t str_len;
650     size_t suffix_len;
651 
652     if (str == NULL)
653     {
654         return false;
655     }
656 
657     if (suffix == NULL)
658     {
659         return true;
660     }
661 
662     str_len = strlen(str);
663     suffix_len = strlen(suffix);
664 
665     if (str_len < suffix_len)
666     {
667         return false;
668     }
669 
670     return evutil_ascii_strncasecmp(str + str_len - suffix_len, suffix, suffix_len) == 0;
671 }
672 
673 /****
674 *****
675 ****/
676 
tr_time_msec(void)677 uint64_t tr_time_msec(void)
678 {
679     struct timeval tv;
680 
681     tr_gettimeofday(&tv);
682     return (uint64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
683 }
684 
tr_wait_msec(long int msec)685 void tr_wait_msec(long int msec)
686 {
687 #ifdef _WIN32
688 
689     Sleep((DWORD)msec);
690 
691 #else
692 
693     struct timespec ts;
694     ts.tv_sec = msec / 1000;
695     ts.tv_nsec = (msec % 1000) * 1000000;
696     nanosleep(&ts, NULL);
697 
698 #endif
699 }
700 
701 /***
702 ****
703 ***/
704 
tr_snprintf(char * buf,size_t buflen,char const * fmt,...)705 int tr_snprintf(char* buf, size_t buflen, char const* fmt, ...)
706 {
707     int len;
708     va_list args;
709 
710     va_start(args, fmt);
711     len = evutil_vsnprintf(buf, buflen, fmt, args);
712     va_end(args);
713     return len;
714 }
715 
716 /*
717  * Copy src to string dst of size siz. At most siz-1 characters
718  * will be copied. Always NUL terminates (unless siz == 0).
719  * Returns strlen (src); if retval >= siz, truncation occurred.
720  */
tr_strlcpy(char * dst,void const * src,size_t siz)721 size_t tr_strlcpy(char* dst, void const* src, size_t siz)
722 {
723     TR_ASSERT(dst != NULL);
724     TR_ASSERT(src != NULL);
725 
726 #ifdef HAVE_STRLCPY
727 
728     return strlcpy(dst, src, siz);
729 
730 #else
731 
732     char* d = dst;
733     char const* s = src;
734     size_t n = siz;
735 
736     /* Copy as many bytes as will fit */
737     if (n != 0)
738     {
739         while (--n != 0)
740         {
741             if ((*d++ = *s++) == '\0')
742             {
743                 break;
744             }
745         }
746     }
747 
748     /* Not enough room in dst, add NUL and traverse rest of src */
749     if (n == 0)
750     {
751         if (siz != 0)
752         {
753             *d = '\0'; /* NUL-terminate dst */
754         }
755 
756         while (*s++ != '\0')
757         {
758         }
759     }
760 
761     return s - (char const*)src - 1; /* count does not include NUL */
762 
763 #endif
764 }
765 
766 /***
767 ****
768 ***/
769 
tr_getRatio(uint64_t numerator,uint64_t denominator)770 double tr_getRatio(uint64_t numerator, uint64_t denominator)
771 {
772     double ratio;
773 
774     if (denominator > 0)
775     {
776         ratio = numerator / (double)denominator;
777     }
778     else if (numerator > 0)
779     {
780         ratio = TR_RATIO_INF;
781     }
782     else
783     {
784         ratio = TR_RATIO_NA;
785     }
786 
787     return ratio;
788 }
789 
tr_binary_to_hex(void const * input,char * output,size_t byte_length)790 void tr_binary_to_hex(void const* input, char* output, size_t byte_length)
791 {
792     static char const hex[] = "0123456789abcdef";
793     uint8_t const* input_octets = input;
794 
795     /* go from back to front to allow for in-place conversion */
796     input_octets += byte_length;
797     output += byte_length * 2;
798 
799     *output = '\0';
800 
801     while (byte_length-- > 0)
802     {
803         unsigned int const val = *(--input_octets);
804         *(--output) = hex[val & 0xf];
805         *(--output) = hex[val >> 4];
806     }
807 }
808 
tr_hex_to_binary(char const * input,void * output,size_t byte_length)809 void tr_hex_to_binary(char const* input, void* output, size_t byte_length)
810 {
811     static char const hex[] = "0123456789abcdef";
812     uint8_t* output_octets = output;
813 
814     for (size_t i = 0; i < byte_length; ++i)
815     {
816         int const hi = strchr(hex, tolower(*input++)) - hex;
817         int const lo = strchr(hex, tolower(*input++)) - hex;
818         *output_octets++ = (uint8_t)((hi << 4) | lo);
819     }
820 }
821 
822 /***
823 ****
824 ***/
825 
isValidURLChars(char const * url,size_t url_len)826 static bool isValidURLChars(char const* url, size_t url_len)
827 {
828     static char const rfc2396_valid_chars[] =
829         "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
830         "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
831         "0123456789" /* digit */
832         "-_.!~*'()" /* mark */
833         ";/?:@&=+$," /* reserved */
834         "<>#%<\"" /* delims */
835         "{}|\\^[]`"; /* unwise */
836 
837     if (url == NULL)
838     {
839         return false;
840     }
841 
842     for (char const* c = url, * end = url + url_len; c < end && *c != '\0'; ++c)
843     {
844         if (memchr(rfc2396_valid_chars, *c, sizeof(rfc2396_valid_chars) - 1) == NULL)
845         {
846             return false;
847         }
848     }
849 
850     return true;
851 }
852 
tr_urlIsValidTracker(char const * url)853 bool tr_urlIsValidTracker(char const* url)
854 {
855     if (url == NULL)
856     {
857         return false;
858     }
859 
860     size_t const url_len = strlen(url);
861 
862     return isValidURLChars(url, url_len) && tr_urlParse(url, url_len, NULL, NULL, NULL, NULL) &&
863         (memcmp(url, "http://", 7) == 0 || memcmp(url, "https://", 8) == 0 || memcmp(url, "udp://", 6) == 0);
864 }
865 
tr_urlIsValid(char const * url,size_t url_len)866 bool tr_urlIsValid(char const* url, size_t url_len)
867 {
868     if (url == NULL)
869     {
870         return false;
871     }
872 
873     if (url_len == TR_BAD_SIZE)
874     {
875         url_len = strlen(url);
876     }
877 
878     return isValidURLChars(url, url_len) && tr_urlParse(url, url_len, NULL, NULL, NULL, NULL) &&
879         (memcmp(url, "http://", 7) == 0 || memcmp(url, "https://", 8) == 0 || memcmp(url, "ftp://", 6) == 0 ||
880             memcmp(url, "sftp://", 7) == 0);
881 }
882 
tr_addressIsIP(char const * str)883 bool tr_addressIsIP(char const* str)
884 {
885     tr_address tmp;
886     return tr_address_from_string(&tmp, str);
887 }
888 
parse_port(char const * port,size_t port_len)889 static int parse_port(char const* port, size_t port_len)
890 {
891     char* tmp = tr_strndup(port, port_len);
892     char* end;
893 
894     long port_num = strtol(tmp, &end, 10);
895 
896     if (*end != '\0' || port_num <= 0 || port_num >= 65536)
897     {
898         port_num = -1;
899     }
900 
901     tr_free(tmp);
902 
903     return (int)port_num;
904 }
905 
get_port_for_scheme(char const * scheme,size_t scheme_len)906 static int get_port_for_scheme(char const* scheme, size_t scheme_len)
907 {
908     struct known_scheme
909     {
910         char const* name;
911         int port;
912     };
913 
914     static struct known_scheme const known_schemes[] =
915     {
916         { "udp", 80 },
917         { "ftp", 21 },
918         { "sftp", 22 },
919         { "http", 80 },
920         { "https", 443 },
921         { NULL, 0 }
922     };
923 
924     for (struct known_scheme const* s = known_schemes; s->name != NULL; ++s)
925     {
926         if (scheme_len == strlen(s->name) && memcmp(scheme, s->name, scheme_len) == 0)
927         {
928             return s->port;
929         }
930     }
931 
932     return -1;
933 }
934 
tr_urlParse(char const * url,size_t url_len,char ** setme_scheme,char ** setme_host,int * setme_port,char ** setme_path)935 bool tr_urlParse(char const* url, size_t url_len, char** setme_scheme, char** setme_host, int* setme_port, char** setme_path)
936 {
937     if (url_len == TR_BAD_SIZE)
938     {
939         url_len = strlen(url);
940     }
941 
942     char const* scheme = url;
943     char const* scheme_end = tr_memmem(scheme, url_len, "://", 3);
944 
945     if (scheme_end == NULL)
946     {
947         return false;
948     }
949 
950     size_t const scheme_len = scheme_end - scheme;
951 
952     if (scheme_len == 0)
953     {
954         return false;
955     }
956 
957     url += scheme_len + 3;
958     url_len -= scheme_len + 3;
959 
960     char const* authority = url;
961     char const* authority_end = memchr(authority, '/', url_len);
962 
963     if (authority_end == NULL)
964     {
965         authority_end = authority + url_len;
966     }
967 
968     size_t const authority_len = authority_end - authority;
969 
970     if (authority_len == 0)
971     {
972         return false;
973     }
974 
975     url += authority_len;
976     url_len -= authority_len;
977 
978     char const* host_end = memchr(authority, ':', authority_len);
979 
980     size_t const host_len = host_end != NULL ? (size_t)(host_end - authority) : authority_len;
981 
982     if (host_len == 0)
983     {
984         return false;
985     }
986 
987     size_t const port_len = host_end != NULL ? authority_end - host_end - 1 : 0;
988 
989     if (setme_scheme != NULL)
990     {
991         *setme_scheme = tr_strndup(scheme, scheme_len);
992     }
993 
994     if (setme_host != NULL)
995     {
996         *setme_host = tr_strndup(authority, host_len);
997     }
998 
999     if (setme_port != NULL)
1000     {
1001         *setme_port = port_len > 0 ? parse_port(host_end + 1, port_len) : get_port_for_scheme(scheme, scheme_len);
1002     }
1003 
1004     if (setme_path != NULL)
1005     {
1006         if (url[0] == '\0')
1007         {
1008             *setme_path = tr_strdup("/");
1009         }
1010         else
1011         {
1012             *setme_path = tr_strndup(url, url_len);
1013         }
1014     }
1015 
1016     return true;
1017 }
1018 
1019 /***
1020 ****
1021 ***/
1022 
tr_removeElementFromArray(void * array,unsigned int index_to_remove,size_t sizeof_element,size_t nmemb)1023 void tr_removeElementFromArray(void* array, unsigned int index_to_remove, size_t sizeof_element, size_t nmemb)
1024 {
1025     char* a = array;
1026 
1027     memmove(a + sizeof_element * index_to_remove, a + sizeof_element * (index_to_remove + 1),
1028         sizeof_element * (--nmemb - index_to_remove));
1029 }
1030 
tr_lowerBound(void const * key,void const * base,size_t nmemb,size_t size,tr_voidptr_compare_func compar,bool * exact_match)1031 int tr_lowerBound(void const* key, void const* base, size_t nmemb, size_t size, tr_voidptr_compare_func compar,
1032     bool* exact_match)
1033 {
1034     size_t first = 0;
1035     char const* cbase = base;
1036     bool exact = false;
1037 
1038     while (nmemb != 0)
1039     {
1040         size_t const half = nmemb / 2;
1041         size_t const middle = first + half;
1042         int const c = (*compar)(key, cbase + size * middle);
1043 
1044         if (c <= 0)
1045         {
1046             if (c == 0)
1047             {
1048                 exact = true;
1049             }
1050 
1051             nmemb = half;
1052         }
1053         else
1054         {
1055             first = middle + 1;
1056             nmemb = nmemb - half - 1;
1057         }
1058     }
1059 
1060     *exact_match = exact;
1061     return first;
1062 }
1063 
1064 /***
1065 ****
1066 ****
1067 ***/
1068 
1069 /* Byte-wise swap two items of size SIZE.
1070    From glibc, written by Douglas C. Schmidt, LGPL 2.1 or higher */
1071 #define SWAP(a, b, size) \
1072     do \
1073     { \
1074         register size_t __size = (size); \
1075         register char* __a = (a); \
1076         register char* __b = (b); \
1077         if (__a != __b) \
1078         { \
1079             do \
1080             { \
1081                 char __tmp = *__a; \
1082                 *__a++ = *__b; \
1083                 *__b++ = __tmp; \
1084             } \
1085             while (--__size > 0); \
1086         } \
1087     } \
1088     while (0)
1089 
quickfindPartition(char * base,size_t left,size_t right,size_t size,tr_voidptr_compare_func compar,size_t pivotIndex)1090 static size_t quickfindPartition(char* base, size_t left, size_t right, size_t size, tr_voidptr_compare_func compar,
1091     size_t pivotIndex)
1092 {
1093     size_t storeIndex;
1094 
1095     /* move pivot to the end */
1096     SWAP(base + (size * pivotIndex), base + (size * right), size);
1097 
1098     storeIndex = left;
1099 
1100     for (size_t i = left; i < right; ++i)
1101     {
1102         if ((*compar)(base + (size * i), base + (size * right)) <= 0)
1103         {
1104             SWAP(base + (size * storeIndex), base + (size * i), size);
1105             ++storeIndex;
1106         }
1107     }
1108 
1109     /* move pivot to its final place */
1110     SWAP(base + (size * right), base + (size * storeIndex), size);
1111 
1112     /* sanity check the partition */
1113 #ifdef TR_ENABLE_ASSERTS
1114 
1115     TR_ASSERT(storeIndex >= left);
1116     TR_ASSERT(storeIndex <= right);
1117 
1118     for (size_t i = left; i < storeIndex; ++i)
1119     {
1120         TR_ASSERT((*compar)(base + (size * i), base + (size * storeIndex)) <= 0);
1121     }
1122 
1123     for (size_t i = storeIndex + 1; i <= right; ++i)
1124     {
1125         TR_ASSERT((*compar)(base + (size * i), base + (size * storeIndex)) >= 0);
1126     }
1127 
1128 #endif
1129 
1130     return storeIndex;
1131 }
1132 
quickfindFirstK(char * base,size_t left,size_t right,size_t size,tr_voidptr_compare_func compar,size_t k)1133 static void quickfindFirstK(char* base, size_t left, size_t right, size_t size, tr_voidptr_compare_func compar, size_t k)
1134 {
1135     if (right > left)
1136     {
1137         size_t const pivotIndex = left + (right - left) / 2U;
1138 
1139         size_t const pivotNewIndex = quickfindPartition(base, left, right, size, compar, pivotIndex);
1140 
1141         if (pivotNewIndex > left + k) /* new condition */
1142         {
1143             quickfindFirstK(base, left, pivotNewIndex - 1, size, compar, k);
1144         }
1145         else if (pivotNewIndex < left + k)
1146         {
1147             quickfindFirstK(base, pivotNewIndex + 1, right, size, compar, k + left - pivotNewIndex - 1);
1148         }
1149     }
1150 }
1151 
1152 #ifdef TR_ENABLE_ASSERTS
1153 
checkBestScoresComeFirst(char * base,size_t nmemb,size_t size,tr_voidptr_compare_func compar,size_t k)1154 static void checkBestScoresComeFirst(char* base, size_t nmemb, size_t size, tr_voidptr_compare_func compar, size_t k)
1155 {
1156     size_t worstFirstPos = 0;
1157 
1158     for (size_t i = 1; i < k; ++i)
1159     {
1160         if ((*compar)(base + (size * worstFirstPos), base + (size * i)) < 0)
1161         {
1162             worstFirstPos = i;
1163         }
1164     }
1165 
1166     for (size_t i = 0; i < k; ++i)
1167     {
1168         TR_ASSERT((*compar)(base + (size * i), base + (size * worstFirstPos)) <= 0);
1169     }
1170 
1171     for (size_t i = k; i < nmemb; ++i)
1172     {
1173         TR_ASSERT((*compar)(base + (size * i), base + (size * worstFirstPos)) >= 0);
1174     }
1175 }
1176 
1177 #endif
1178 
tr_quickfindFirstK(void * base,size_t nmemb,size_t size,tr_voidptr_compare_func compar,size_t k)1179 void tr_quickfindFirstK(void* base, size_t nmemb, size_t size, tr_voidptr_compare_func compar, size_t k)
1180 {
1181     if (k < nmemb)
1182     {
1183         quickfindFirstK(base, 0, nmemb - 1, size, compar, k);
1184 
1185 #ifdef TR_ENABLE_ASSERTS
1186         checkBestScoresComeFirst(base, nmemb, size, compar, k);
1187 #endif
1188     }
1189 }
1190 
1191 /***
1192 ****
1193 ***/
1194 
strip_non_utf8(char const * in,size_t inlen)1195 static char* strip_non_utf8(char const* in, size_t inlen)
1196 {
1197     char const* end;
1198     struct evbuffer* buf = evbuffer_new();
1199 
1200     while (!tr_utf8_validate(in, inlen, &end))
1201     {
1202         int const good_len = end - in;
1203 
1204         evbuffer_add(buf, in, good_len);
1205         inlen -= (good_len + 1);
1206         in += (good_len + 1);
1207         evbuffer_add(buf, "?", 1);
1208     }
1209 
1210     evbuffer_add(buf, in, inlen);
1211     return evbuffer_free_to_str(buf, NULL);
1212 }
1213 
to_utf8(char const * in,size_t inlen)1214 static char* to_utf8(char const* in, size_t inlen)
1215 {
1216     char* ret = NULL;
1217 
1218 #ifdef HAVE_ICONV
1219 
1220     char const* encodings[] = { "CURRENT", "ISO-8859-15" };
1221     size_t const buflen = inlen * 4 + 10;
1222     char* out = tr_new(char, buflen);
1223 
1224     for (size_t i = 0; ret == NULL && i < TR_N_ELEMENTS(encodings); ++i)
1225     {
1226 #ifdef ICONV_SECOND_ARGUMENT_IS_CONST
1227         char const* inbuf = in;
1228 #else
1229         char* inbuf = (char*)in;
1230 #endif
1231         char* outbuf = out;
1232         size_t inbytesleft = inlen;
1233         size_t outbytesleft = buflen;
1234         char const* test_encoding = encodings[i];
1235 
1236         iconv_t cd = iconv_open("UTF-8", test_encoding);
1237 
1238         if (cd != (iconv_t)-1)
1239         {
1240             if (iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft) != (size_t)-1)
1241             {
1242                 ret = tr_strndup(out, buflen - outbytesleft);
1243             }
1244 
1245             iconv_close(cd);
1246         }
1247     }
1248 
1249     tr_free(out);
1250 
1251 #endif
1252 
1253     if (ret == NULL)
1254     {
1255         ret = strip_non_utf8(in, inlen);
1256     }
1257 
1258     return ret;
1259 }
1260 
tr_utf8clean(char const * str,size_t max_len)1261 char* tr_utf8clean(char const* str, size_t max_len)
1262 {
1263     char* ret;
1264     char const* end;
1265 
1266     if (max_len == TR_BAD_SIZE)
1267     {
1268         max_len = strlen(str);
1269     }
1270 
1271     if (tr_utf8_validate(str, max_len, &end))
1272     {
1273         ret = tr_strndup(str, max_len);
1274     }
1275     else
1276     {
1277         ret = to_utf8(str, max_len);
1278     }
1279 
1280     TR_ASSERT(tr_utf8_validate(ret, TR_BAD_SIZE, NULL));
1281     return ret;
1282 }
1283 
1284 #ifdef _WIN32
1285 
tr_win32_native_to_utf8(wchar_t const * text,int text_size)1286 char* tr_win32_native_to_utf8(wchar_t const* text, int text_size)
1287 {
1288     return tr_win32_native_to_utf8_ex(text, text_size, 0, 0, NULL);
1289 }
1290 
tr_win32_native_to_utf8_ex(wchar_t const * text,int text_size,int extra_chars_before,int extra_chars_after,int * real_result_size)1291 char* tr_win32_native_to_utf8_ex(wchar_t const* text, int text_size, int extra_chars_before, int extra_chars_after,
1292     int* real_result_size)
1293 {
1294     char* ret = NULL;
1295     int size;
1296 
1297     if (text_size == -1)
1298     {
1299         text_size = wcslen(text);
1300     }
1301 
1302     size = WideCharToMultiByte(CP_UTF8, 0, text, text_size, NULL, 0, NULL, NULL);
1303 
1304     if (size == 0)
1305     {
1306         goto fail;
1307     }
1308 
1309     ret = tr_new(char, size + extra_chars_before + extra_chars_after + 1);
1310     size = WideCharToMultiByte(CP_UTF8, 0, text, text_size, ret + extra_chars_before, size, NULL, NULL);
1311 
1312     if (size == 0)
1313     {
1314         goto fail;
1315     }
1316 
1317     ret[size + extra_chars_before + extra_chars_after] = '\0';
1318 
1319     if (real_result_size != NULL)
1320     {
1321         *real_result_size = size;
1322     }
1323 
1324     return ret;
1325 
1326 fail:
1327     tr_free(ret);
1328 
1329     return NULL;
1330 }
1331 
tr_win32_utf8_to_native(char const * text,int text_size)1332 wchar_t* tr_win32_utf8_to_native(char const* text, int text_size)
1333 {
1334     return tr_win32_utf8_to_native_ex(text, text_size, 0, 0, NULL);
1335 }
1336 
tr_win32_utf8_to_native_ex(char const * text,int text_size,int extra_chars_before,int extra_chars_after,int * real_result_size)1337 wchar_t* tr_win32_utf8_to_native_ex(char const* text, int text_size, int extra_chars_before, int extra_chars_after,
1338     int* real_result_size)
1339 {
1340     wchar_t* ret = NULL;
1341     int size;
1342 
1343     if (text_size == -1)
1344     {
1345         text_size = strlen(text);
1346     }
1347 
1348     size = MultiByteToWideChar(CP_UTF8, 0, text, text_size, NULL, 0);
1349 
1350     if (size == 0)
1351     {
1352         goto fail;
1353     }
1354 
1355     ret = tr_new(wchar_t, size + extra_chars_before + extra_chars_after + 1);
1356     size = MultiByteToWideChar(CP_UTF8, 0, text, text_size, ret + extra_chars_before, size);
1357 
1358     if (size == 0)
1359     {
1360         goto fail;
1361     }
1362 
1363     ret[size + extra_chars_before + extra_chars_after] = L'\0';
1364 
1365     if (real_result_size != NULL)
1366     {
1367         *real_result_size = size;
1368     }
1369 
1370     return ret;
1371 
1372 fail:
1373     tr_free(ret);
1374 
1375     return NULL;
1376 }
1377 
tr_win32_format_message(uint32_t code)1378 char* tr_win32_format_message(uint32_t code)
1379 {
1380     wchar_t* wide_text = NULL;
1381     DWORD wide_size;
1382     char* text = NULL;
1383     size_t text_size;
1384 
1385     wide_size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1386         NULL, code, 0, (LPWSTR)&wide_text, 0, NULL);
1387 
1388     if (wide_size == 0)
1389     {
1390         return tr_strdup_printf("Unknown error (0x%08x)", code);
1391     }
1392 
1393     if (wide_size != 0 && wide_text != NULL)
1394     {
1395         text = tr_win32_native_to_utf8(wide_text, wide_size);
1396     }
1397 
1398     LocalFree(wide_text);
1399 
1400     if (text != NULL)
1401     {
1402         /* Most (all?) messages contain "\r\n" in the end, chop it */
1403         text_size = strlen(text);
1404 
1405         while (text_size > 0 && isspace((uint8_t)text[text_size - 1]))
1406         {
1407             text[--text_size] = '\0';
1408         }
1409     }
1410 
1411     return text;
1412 }
1413 
tr_win32_make_args_utf8(int * argc,char *** argv)1414 void tr_win32_make_args_utf8(int* argc, char*** argv)
1415 {
1416     int my_argc;
1417     wchar_t** my_wide_argv;
1418 
1419     my_wide_argv = CommandLineToArgvW(GetCommandLineW(), &my_argc);
1420 
1421     if (my_wide_argv == NULL)
1422     {
1423         return;
1424     }
1425 
1426     TR_ASSERT(*argc == my_argc);
1427 
1428     char** my_argv = tr_new(char*, my_argc + 1);
1429     int processed_argc = 0;
1430 
1431     for (int i = 0; i < my_argc; ++i, ++processed_argc)
1432     {
1433         my_argv[i] = tr_win32_native_to_utf8(my_wide_argv[i], -1);
1434 
1435         if (my_argv[i] == NULL)
1436         {
1437             break;
1438         }
1439     }
1440 
1441     if (processed_argc < my_argc)
1442     {
1443         for (int i = 0; i < processed_argc; ++i)
1444         {
1445             tr_free(my_argv[i]);
1446         }
1447 
1448         tr_free(my_argv);
1449     }
1450     else
1451     {
1452         my_argv[my_argc] = NULL;
1453 
1454         *argc = my_argc;
1455         *argv = my_argv;
1456 
1457         /* TODO: Add atexit handler to cleanup? */
1458     }
1459 
1460     LocalFree(my_wide_argv);
1461 }
1462 
tr_main_win32(int argc,char ** argv,int (* real_main)(int,char **))1463 int tr_main_win32(int argc, char** argv, int (* real_main)(int, char**))
1464 {
1465     tr_win32_make_args_utf8(&argc, &argv);
1466     SetConsoleCP(CP_UTF8);
1467     SetConsoleOutputCP(CP_UTF8);
1468     return (*real_main)(argc, argv);
1469 }
1470 
1471 #endif
1472 
1473 /***
1474 ****
1475 ***/
1476 
1477 struct number_range
1478 {
1479     int low;
1480     int high;
1481 };
1482 
1483 /**
1484  * This should be a single number (ex. "6") or a range (ex. "6-9").
1485  * Anything else is an error and will return failure.
1486  */
parseNumberSection(char const * str,size_t len,struct number_range * setme)1487 static bool parseNumberSection(char const* str, size_t len, struct number_range* setme)
1488 {
1489     long a;
1490     long b;
1491     bool success;
1492     char* end;
1493     int const error = errno;
1494     char* tmp = tr_strndup(str, len);
1495 
1496     errno = 0;
1497     a = b = strtol(tmp, &end, 10);
1498 
1499     if (errno != 0 || end == tmp)
1500     {
1501         success = false;
1502     }
1503     else if (*end != '-')
1504     {
1505         success = true;
1506     }
1507     else
1508     {
1509         char const* pch = end + 1;
1510         b = strtol(pch, &end, 10);
1511 
1512         if (errno != 0 || pch == end)
1513         {
1514             success = false;
1515         }
1516         else if (*end != '\0') /* trailing data */
1517         {
1518             success = false;
1519         }
1520         else
1521         {
1522             success = true;
1523         }
1524     }
1525 
1526     tr_free(tmp);
1527 
1528     setme->low = MIN(a, b);
1529     setme->high = MAX(a, b);
1530 
1531     errno = error;
1532     return success;
1533 }
1534 
compareInt(void const * va,void const * vb)1535 int compareInt(void const* va, void const* vb)
1536 {
1537     int const a = *(int const*)va;
1538     int const b = *(int const*)vb;
1539     return a - b;
1540 }
1541 
1542 /**
1543  * Given a string like "1-4" or "1-4,6,9,14-51", this allocates and returns an
1544  * array of setmeCount ints of all the values in the array.
1545  * For example, "5-8" will return [ 5, 6, 7, 8 ] and setmeCount will be 4.
1546  * It's the caller's responsibility to call tr_free () on the returned array.
1547  * If a fragment of the string can't be parsed, NULL is returned.
1548  */
tr_parseNumberRange(char const * str_in,size_t len,int * setmeCount)1549 int* tr_parseNumberRange(char const* str_in, size_t len, int* setmeCount)
1550 {
1551     int n = 0;
1552     int* uniq = NULL;
1553     char* str = tr_strndup(str_in, len);
1554     char const* walk;
1555     tr_list* ranges = NULL;
1556     bool success = true;
1557 
1558     walk = str;
1559 
1560     while (!tr_str_is_empty(walk) && success)
1561     {
1562         struct number_range range;
1563         char const* pch = strchr(walk, ',');
1564 
1565         if (pch != NULL)
1566         {
1567             success = parseNumberSection(walk, (size_t)(pch - walk), &range);
1568             walk = pch + 1;
1569         }
1570         else
1571         {
1572             success = parseNumberSection(walk, strlen(walk), &range);
1573             walk += strlen(walk);
1574         }
1575 
1576         if (success)
1577         {
1578             tr_list_append(&ranges, tr_memdup(&range, sizeof(struct number_range)));
1579         }
1580     }
1581 
1582     if (!success)
1583     {
1584         *setmeCount = 0;
1585         uniq = NULL;
1586     }
1587     else
1588     {
1589         int n2;
1590         int* sorted = NULL;
1591 
1592         /* build a sorted number array */
1593         n = n2 = 0;
1594 
1595         for (tr_list* l = ranges; l != NULL; l = l->next)
1596         {
1597             struct number_range const* r = l->data;
1598             n += r->high + 1 - r->low;
1599         }
1600 
1601         sorted = tr_new(int, n);
1602 
1603         if (sorted == NULL)
1604         {
1605             n = 0;
1606             uniq = NULL;
1607         }
1608         else
1609         {
1610             for (tr_list* l = ranges; l != NULL; l = l->next)
1611             {
1612                 struct number_range const* r = l->data;
1613 
1614                 for (int i = r->low; i <= r->high; ++i)
1615                 {
1616                     sorted[n2++] = i;
1617                 }
1618             }
1619 
1620             qsort(sorted, n, sizeof(int), compareInt);
1621             TR_ASSERT(n == n2);
1622 
1623             /* remove duplicates */
1624             uniq = tr_new(int, n);
1625             n = 0;
1626 
1627             if (uniq != NULL)
1628             {
1629                 for (int i = 0; i < n2; ++i)
1630                 {
1631                     if (n == 0 || uniq[n - 1] != sorted[i])
1632                     {
1633                         uniq[n++] = sorted[i];
1634                     }
1635                 }
1636             }
1637 
1638             tr_free(sorted);
1639         }
1640     }
1641 
1642     /* cleanup */
1643     tr_list_free(&ranges, tr_free);
1644     tr_free(str);
1645 
1646     /* return the result */
1647     *setmeCount = n;
1648     return uniq;
1649 }
1650 
1651 /***
1652 ****
1653 ***/
1654 
tr_truncd(double x,int precision)1655 double tr_truncd(double x, int precision)
1656 {
1657     char* pt;
1658     char buf[128];
1659     tr_snprintf(buf, sizeof(buf), "%.*f", DBL_DIG, x);
1660 
1661     if ((pt = strstr(buf, localeconv()->decimal_point)) != NULL)
1662     {
1663         pt[precision != 0 ? precision + 1 : 0] = '\0';
1664     }
1665 
1666     return atof(buf);
1667 }
1668 
1669 /* return a truncated double as a string */
tr_strtruncd(char * buf,double x,int precision,size_t buflen)1670 static char* tr_strtruncd(char* buf, double x, int precision, size_t buflen)
1671 {
1672     tr_snprintf(buf, buflen, "%.*f", precision, tr_truncd(x, precision));
1673     return buf;
1674 }
1675 
tr_strpercent(char * buf,double x,size_t buflen)1676 char* tr_strpercent(char* buf, double x, size_t buflen)
1677 {
1678     if (x < 100.0)
1679     {
1680         tr_strtruncd(buf, x, 1, buflen);
1681     }
1682     else
1683     {
1684         tr_strtruncd(buf, x, 0, buflen);
1685     }
1686 
1687     return buf;
1688 }
1689 
tr_strratio(char * buf,size_t buflen,double ratio,char const * infinity)1690 char* tr_strratio(char* buf, size_t buflen, double ratio, char const* infinity)
1691 {
1692     if ((int)ratio == TR_RATIO_NA)
1693     {
1694         tr_strlcpy(buf, _("None"), buflen);
1695     }
1696     else if ((int)ratio == TR_RATIO_INF)
1697     {
1698         tr_strlcpy(buf, infinity, buflen);
1699     }
1700     else
1701     {
1702         tr_strpercent(buf, ratio, buflen);
1703     }
1704 
1705     return buf;
1706 }
1707 
1708 /***
1709 ****
1710 ***/
1711 
tr_moveFile(char const * oldpath,char const * newpath,tr_error ** error)1712 bool tr_moveFile(char const* oldpath, char const* newpath, tr_error** error)
1713 {
1714     tr_sys_file_t in;
1715     tr_sys_file_t out;
1716     char* buf = NULL;
1717     tr_sys_path_info info;
1718     uint64_t bytesLeft;
1719     size_t const buflen = 1024 * 1024; /* 1024 KiB buffer */
1720 
1721     /* make sure the old file exists */
1722     if (!tr_sys_path_get_info(oldpath, 0, &info, error))
1723     {
1724         tr_error_prefix(error, "Unable to get information on old file: ");
1725         return false;
1726     }
1727 
1728     if (info.type != TR_SYS_PATH_IS_FILE)
1729     {
1730         tr_error_set_literal(error, TR_ERROR_EINVAL, "Old path does not point to a file.");
1731         return false;
1732     }
1733 
1734     /* make sure the target directory exists */
1735     {
1736         char* newdir = tr_sys_path_dirname(newpath, error);
1737         bool const i = newdir != NULL && tr_sys_dir_create(newdir, TR_SYS_DIR_CREATE_PARENTS, 0777, error);
1738         tr_free(newdir);
1739 
1740         if (!i)
1741         {
1742             tr_error_prefix(error, "Unable to create directory for new file: ");
1743             return false;
1744         }
1745     }
1746 
1747     /* they might be on the same filesystem... */
1748     if (tr_sys_path_rename(oldpath, newpath, NULL))
1749     {
1750         return true;
1751     }
1752 
1753     /* copy the file */
1754     in = tr_sys_file_open(oldpath, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, error);
1755 
1756     if (in == TR_BAD_SYS_FILE)
1757     {
1758         tr_error_prefix(error, "Unable to open old file: ");
1759         return false;
1760     }
1761 
1762     out = tr_sys_file_open(newpath, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0666, error);
1763 
1764     if (out == TR_BAD_SYS_FILE)
1765     {
1766         tr_error_prefix(error, "Unable to open new file: ");
1767         tr_sys_file_close(in, NULL);
1768         return false;
1769     }
1770 
1771     buf = tr_valloc(buflen);
1772     bytesLeft = info.size;
1773 
1774     while (bytesLeft > 0)
1775     {
1776         uint64_t const bytesThisPass = MIN(bytesLeft, buflen);
1777         uint64_t numRead;
1778         uint64_t bytesWritten;
1779 
1780         if (!tr_sys_file_read(in, buf, bytesThisPass, &numRead, error))
1781         {
1782             break;
1783         }
1784 
1785         if (!tr_sys_file_write(out, buf, numRead, &bytesWritten, error))
1786         {
1787             break;
1788         }
1789 
1790         TR_ASSERT(numRead == bytesWritten);
1791         TR_ASSERT(bytesWritten <= bytesLeft);
1792         bytesLeft -= bytesWritten;
1793     }
1794 
1795     /* cleanup */
1796     tr_free(buf);
1797     tr_sys_file_close(out, NULL);
1798     tr_sys_file_close(in, NULL);
1799 
1800     if (bytesLeft != 0)
1801     {
1802         tr_error_prefix(error, "Unable to read/write: ");
1803         return false;
1804     }
1805 
1806     {
1807         tr_error* my_error = NULL;
1808 
1809         if (!tr_sys_path_remove(oldpath, &my_error))
1810         {
1811             tr_logAddError("Unable to remove file at old path: %s", my_error->message);
1812             tr_error_free(my_error);
1813         }
1814     }
1815 
1816     return true;
1817 }
1818 
1819 /***
1820 ****
1821 ***/
1822 
tr_valloc(size_t bufLen)1823 void* tr_valloc(size_t bufLen)
1824 {
1825     size_t allocLen;
1826     void* buf = NULL;
1827     static size_t pageSize = 0;
1828 
1829     if (pageSize == 0)
1830     {
1831 #if defined(HAVE_GETPAGESIZE) && !defined(_WIN32)
1832         pageSize = (size_t)getpagesize();
1833 #else /* guess */
1834         pageSize = 4096;
1835 #endif
1836     }
1837 
1838     allocLen = pageSize;
1839 
1840     while (allocLen < bufLen)
1841     {
1842         allocLen += pageSize;
1843     }
1844 
1845 #ifdef HAVE_POSIX_MEMALIGN
1846 
1847     if (buf == NULL)
1848     {
1849         if (posix_memalign(&buf, pageSize, allocLen) != 0)
1850         {
1851             buf = NULL; /* just retry with valloc/malloc */
1852         }
1853     }
1854 
1855 #endif
1856 
1857 #ifdef HAVE_VALLOC
1858 
1859     if (buf == NULL)
1860     {
1861         buf = valloc(allocLen);
1862     }
1863 
1864 #endif
1865 
1866     if (buf == NULL)
1867     {
1868         buf = tr_malloc(allocLen);
1869     }
1870 
1871     return buf;
1872 }
1873 
1874 /***
1875 ****
1876 ***/
1877 
tr_htonll(uint64_t x)1878 uint64_t tr_htonll(uint64_t x)
1879 {
1880 #ifdef HAVE_HTONLL
1881 
1882     return htonll(x);
1883 
1884 #else
1885 
1886     /* fallback code by bdonlan at http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c/875505#875505 */
1887     union
1888     {
1889         uint32_t lx[2];
1890         uint64_t llx;
1891     }
1892     u;
1893     u.lx[0] = htonl(x >> 32);
1894     u.lx[1] = htonl(x & 0xFFFFFFFFULL);
1895     return u.llx;
1896 
1897 #endif
1898 }
1899 
tr_ntohll(uint64_t x)1900 uint64_t tr_ntohll(uint64_t x)
1901 {
1902 #ifdef HAVE_NTOHLL
1903 
1904     return ntohll(x);
1905 
1906 #else
1907 
1908     /* fallback code by bdonlan at http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c/875505#875505 */
1909     union
1910     {
1911         uint32_t lx[2];
1912         uint64_t llx;
1913     }
1914     u;
1915     u.llx = x;
1916     return ((uint64_t)ntohl(u.lx[0]) << 32) | (uint64_t)ntohl(u.lx[1]);
1917 
1918 #endif
1919 }
1920 
1921 /***
1922 ****
1923 ****
1924 ****
1925 ***/
1926 
1927 struct formatter_unit
1928 {
1929     char* name;
1930     int64_t value;
1931 };
1932 
1933 struct formatter_units
1934 {
1935     struct formatter_unit units[4];
1936 };
1937 
1938 enum
1939 {
1940     TR_FMT_KB,
1941     TR_FMT_MB,
1942     TR_FMT_GB,
1943     TR_FMT_TB
1944 };
1945 
formatter_init(struct formatter_units * units,unsigned int kilo,char const * kb,char const * mb,char const * gb,char const * tb)1946 static void formatter_init(struct formatter_units* units, unsigned int kilo, char const* kb, char const* mb, char const* gb,
1947     char const* tb)
1948 {
1949     uint64_t value;
1950 
1951     value = kilo;
1952     units->units[TR_FMT_KB].name = tr_strdup(kb);
1953     units->units[TR_FMT_KB].value = value;
1954 
1955     value *= kilo;
1956     units->units[TR_FMT_MB].name = tr_strdup(mb);
1957     units->units[TR_FMT_MB].value = value;
1958 
1959     value *= kilo;
1960     units->units[TR_FMT_GB].name = tr_strdup(gb);
1961     units->units[TR_FMT_GB].value = value;
1962 
1963     value *= kilo;
1964     units->units[TR_FMT_TB].name = tr_strdup(tb);
1965     units->units[TR_FMT_TB].value = value;
1966 }
1967 
formatter_get_size_str(struct formatter_units const * u,char * buf,int64_t bytes,size_t buflen)1968 static char* formatter_get_size_str(struct formatter_units const* u, char* buf, int64_t bytes, size_t buflen)
1969 {
1970     int precision;
1971     double value;
1972     char const* units;
1973     struct formatter_unit const* unit;
1974 
1975     if (bytes < u->units[1].value)
1976     {
1977         unit = &u->units[0];
1978     }
1979     else if (bytes < u->units[2].value)
1980     {
1981         unit = &u->units[1];
1982     }
1983     else if (bytes < u->units[3].value)
1984     {
1985         unit = &u->units[2];
1986     }
1987     else
1988     {
1989         unit = &u->units[3];
1990     }
1991 
1992     value = (double)bytes / unit->value;
1993     units = unit->name;
1994 
1995     if (unit->value == 1)
1996     {
1997         precision = 0;
1998     }
1999     else if (value < 100)
2000     {
2001         precision = 2;
2002     }
2003     else
2004     {
2005         precision = 1;
2006     }
2007 
2008     tr_snprintf(buf, buflen, "%.*f %s", precision, value, units);
2009     return buf;
2010 }
2011 
2012 static struct formatter_units size_units;
2013 
tr_formatter_size_init(unsigned int kilo,char const * kb,char const * mb,char const * gb,char const * tb)2014 void tr_formatter_size_init(unsigned int kilo, char const* kb, char const* mb, char const* gb, char const* tb)
2015 {
2016     formatter_init(&size_units, kilo, kb, mb, gb, tb);
2017 }
2018 
tr_formatter_size_B(char * buf,int64_t bytes,size_t buflen)2019 char* tr_formatter_size_B(char* buf, int64_t bytes, size_t buflen)
2020 {
2021     return formatter_get_size_str(&size_units, buf, bytes, buflen);
2022 }
2023 
2024 static struct formatter_units speed_units;
2025 
2026 unsigned int tr_speed_K = 0U;
2027 
tr_formatter_speed_init(unsigned int kilo,char const * kb,char const * mb,char const * gb,char const * tb)2028 void tr_formatter_speed_init(unsigned int kilo, char const* kb, char const* mb, char const* gb, char const* tb)
2029 {
2030     tr_speed_K = kilo;
2031     formatter_init(&speed_units, kilo, kb, mb, gb, tb);
2032 }
2033 
tr_formatter_speed_KBps(char * buf,double KBps,size_t buflen)2034 char* tr_formatter_speed_KBps(char* buf, double KBps, size_t buflen)
2035 {
2036     double const K = speed_units.units[TR_FMT_KB].value;
2037     double speed = KBps;
2038 
2039     if (speed <= 999.95) /* 0.0 KB to 999.9 KB */
2040     {
2041         tr_snprintf(buf, buflen, "%d %s", (int)speed, speed_units.units[TR_FMT_KB].name);
2042     }
2043     else
2044     {
2045         speed /= K;
2046 
2047         if (speed <= 99.995) /* 0.98 MB to 99.99 MB */
2048         {
2049             tr_snprintf(buf, buflen, "%.2f %s", speed, speed_units.units[TR_FMT_MB].name);
2050         }
2051         else if (speed <= 999.95) /* 100.0 MB to 999.9 MB */
2052         {
2053             tr_snprintf(buf, buflen, "%.1f %s", speed, speed_units.units[TR_FMT_MB].name);
2054         }
2055         else
2056         {
2057             tr_snprintf(buf, buflen, "%.1f %s", speed / K, speed_units.units[TR_FMT_GB].name);
2058         }
2059     }
2060 
2061     return buf;
2062 }
2063 
2064 static struct formatter_units mem_units;
2065 
2066 unsigned int tr_mem_K = 0U;
2067 
tr_formatter_mem_init(unsigned int kilo,char const * kb,char const * mb,char const * gb,char const * tb)2068 void tr_formatter_mem_init(unsigned int kilo, char const* kb, char const* mb, char const* gb, char const* tb)
2069 {
2070     tr_mem_K = kilo;
2071     formatter_init(&mem_units, kilo, kb, mb, gb, tb);
2072 }
2073 
tr_formatter_mem_B(char * buf,int64_t bytes_per_second,size_t buflen)2074 char* tr_formatter_mem_B(char* buf, int64_t bytes_per_second, size_t buflen)
2075 {
2076     return formatter_get_size_str(&mem_units, buf, bytes_per_second, buflen);
2077 }
2078 
tr_formatter_get_units(void * vdict)2079 void tr_formatter_get_units(void* vdict)
2080 {
2081     tr_variant* l;
2082     tr_variant* dict = vdict;
2083 
2084     tr_variantDictReserve(dict, 6);
2085 
2086     tr_variantDictAddInt(dict, TR_KEY_memory_bytes, mem_units.units[TR_FMT_KB].value);
2087     l = tr_variantDictAddList(dict, TR_KEY_memory_units, 4);
2088 
2089     for (int i = 0; i < 4; i++)
2090     {
2091         tr_variantListAddStr(l, mem_units.units[i].name);
2092     }
2093 
2094     tr_variantDictAddInt(dict, TR_KEY_size_bytes, size_units.units[TR_FMT_KB].value);
2095     l = tr_variantDictAddList(dict, TR_KEY_size_units, 4);
2096 
2097     for (int i = 0; i < 4; i++)
2098     {
2099         tr_variantListAddStr(l, size_units.units[i].name);
2100     }
2101 
2102     tr_variantDictAddInt(dict, TR_KEY_speed_bytes, speed_units.units[TR_FMT_KB].value);
2103     l = tr_variantDictAddList(dict, TR_KEY_speed_units, 4);
2104 
2105     for (int i = 0; i < 4; i++)
2106     {
2107         tr_variantListAddStr(l, speed_units.units[i].name);
2108     }
2109 }
2110 
2111 /***
2112 ****  ENVIRONMENT
2113 ***/
2114 
tr_env_key_exists(char const * key)2115 bool tr_env_key_exists(char const* key)
2116 {
2117     TR_ASSERT(key != NULL);
2118 
2119 #ifdef _WIN32
2120     return GetEnvironmentVariableA(key, NULL, 0) != 0;
2121 #else
2122     return getenv(key) != NULL;
2123 #endif
2124 }
2125 
tr_env_get_int(char const * key,int default_value)2126 int tr_env_get_int(char const* key, int default_value)
2127 {
2128     TR_ASSERT(key != NULL);
2129 
2130 #ifdef _WIN32
2131 
2132     char value[16];
2133 
2134     if (GetEnvironmentVariableA(key, value, TR_N_ELEMENTS(value)) > 1)
2135     {
2136         return atoi(value);
2137     }
2138 
2139 #else
2140 
2141     char const* value = getenv(key);
2142 
2143     if (!tr_str_is_empty(value))
2144     {
2145         return atoi(value);
2146     }
2147 
2148 #endif
2149 
2150     return default_value;
2151 }
2152 
tr_env_get_string(char const * key,char const * default_value)2153 char* tr_env_get_string(char const* key, char const* default_value)
2154 {
2155     TR_ASSERT(key != NULL);
2156 
2157 #ifdef _WIN32
2158 
2159     wchar_t* wide_key = tr_win32_utf8_to_native(key, -1);
2160     char* value = NULL;
2161 
2162     if (wide_key != NULL)
2163     {
2164         DWORD const size = GetEnvironmentVariableW(wide_key, NULL, 0);
2165 
2166         if (size != 0)
2167         {
2168             wchar_t* const wide_value = tr_new(wchar_t, size);
2169 
2170             if (GetEnvironmentVariableW(wide_key, wide_value, size) == size - 1)
2171             {
2172                 value = tr_win32_native_to_utf8(wide_value, size);
2173             }
2174 
2175             tr_free(wide_value);
2176         }
2177 
2178         tr_free(wide_key);
2179     }
2180 
2181     if (value == NULL && default_value != NULL)
2182     {
2183         value = tr_strdup(default_value);
2184     }
2185 
2186     return value;
2187 
2188 #else
2189 
2190     char* value = getenv(key);
2191 
2192     if (value == NULL)
2193     {
2194         value = (char*)default_value;
2195     }
2196 
2197     if (value != NULL)
2198     {
2199         value = tr_strdup(value);
2200     }
2201 
2202     return value;
2203 
2204 #endif
2205 }
2206 
2207 /***
2208 ****
2209 ***/
2210 
tr_net_init(void)2211 void tr_net_init(void)
2212 {
2213     static bool initialized = false;
2214 
2215     if (!initialized)
2216     {
2217 #ifdef _WIN32
2218         WSADATA wsaData;
2219         WSAStartup(MAKEWORD(2, 2), &wsaData);
2220 #endif
2221 
2222         initialized = true;
2223     }
2224 }
2225