9c7f95e7c1a398c17443f98c7224da7011b77983
[oweals/gnunet.git] / src / util / strings.c
1 /*
2      This file is part of GNUnet.
3      (C) 2005, 2006 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file util/strings.c
23  * @brief string functions
24  * @author Nils Durner
25  * @author Christian Grothoff
26  */
27
28 #include "platform.h"
29 #if HAVE_ICONV
30 #include <iconv.h>
31 #endif
32 #include "gnunet_common.h"
33 #include "gnunet_strings_lib.h"
34 #include <unicase.h>
35 #include <unistr.h>
36
37 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
38
39 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
40
41
42 /**
43  * Fill a buffer of the given size with
44  * count 0-terminated strings (given as varargs).
45  * If "buffer" is NULL, only compute the amount of
46  * space required (sum of "strlen(arg)+1").
47  *
48  * Unlike using "snprintf" with "%s", this function
49  * will add 0-terminators after each string.  The
50  * "GNUNET_string_buffer_tokenize" function can be
51  * used to parse the buffer back into individual
52  * strings.
53  *
54  * @param buffer the buffer to fill with strings, can
55  *               be NULL in which case only the necessary
56  *               amount of space will be calculated
57  * @param size number of bytes available in buffer
58  * @param count number of strings that follow
59  * @param ... count 0-terminated strings to copy to buffer
60  * @return number of bytes written to the buffer
61  *         (or number of bytes that would have been written)
62  */
63 size_t
64 GNUNET_STRINGS_buffer_fill (char *buffer, size_t size, unsigned int count, ...)
65 {
66   size_t needed;
67   size_t slen;
68   const char *s;
69   va_list ap;
70
71   needed = 0;
72   va_start (ap, count);
73   while (count > 0)
74   {
75     s = va_arg (ap, const char *);
76
77     slen = strlen (s) + 1;
78     if (buffer != NULL)
79     {
80       GNUNET_assert (needed + slen <= size);
81       memcpy (&buffer[needed], s, slen);
82     }
83     needed += slen;
84     count--;
85   }
86   va_end (ap);
87   return needed;
88 }
89
90
91 /**
92  * Given a buffer of a given size, find "count"
93  * 0-terminated strings in the buffer and assign
94  * the count (varargs) of type "const char**" to the
95  * locations of the respective strings in the
96  * buffer.
97  *
98  * @param buffer the buffer to parse
99  * @param size size of the buffer
100  * @param count number of strings to locate
101  * @return offset of the character after the last 0-termination
102  *         in the buffer, or 0 on error.
103  */
104 unsigned int
105 GNUNET_STRINGS_buffer_tokenize (const char *buffer, size_t size,
106                                 unsigned int count, ...)
107 {
108   unsigned int start;
109   unsigned int needed;
110   const char **r;
111   va_list ap;
112
113   needed = 0;
114   va_start (ap, count);
115   while (count > 0)
116   {
117     r = va_arg (ap, const char **);
118
119     start = needed;
120     while ((needed < size) && (buffer[needed] != '\0'))
121       needed++;
122     if (needed == size)
123     {
124       va_end (ap);
125       return 0;                 /* error */
126     }
127     *r = &buffer[start];
128     needed++;                   /* skip 0-termination */
129     count--;
130   }
131   va_end (ap);
132   return needed;
133 }
134
135
136 /**
137  * Convert a given filesize into a fancy human-readable format.
138  *
139  * @param size number of bytes
140  * @return fancy representation of the size (possibly rounded) for humans
141  */
142 char *
143 GNUNET_STRINGS_byte_size_fancy (unsigned long long size)
144 {
145   const char *unit = _( /* size unit */ "b");
146   char *ret;
147
148   if (size > 5 * 1024)
149   {
150     size = size / 1024;
151     unit = "KiB";
152     if (size > 5 * 1024)
153     {
154       size = size / 1024;
155       unit = "MiB";
156       if (size > 5 * 1024)
157       {
158         size = size / 1024;
159         unit = "GiB";
160         if (size > 5 * 1024)
161         {
162           size = size / 1024;
163           unit = "TiB";
164         }
165       }
166     }
167   }
168   ret = GNUNET_malloc (32);
169   GNUNET_snprintf (ret, 32, "%llu %s", size, unit);
170   return ret;
171 }
172
173
174 /**
175  * Unit conversion table entry for 'convert_with_table'.
176  */
177 struct ConversionTable
178 {
179   /**
180    * Name of the unit (or NULL for end of table).
181    */
182   const char *name;
183
184   /**
185    * Factor to apply for this unit.
186    */
187   unsigned long long value;
188 };
189
190
191 /**
192  * Convert a string of the form "4 X 5 Y" into a numeric value
193  * by interpreting "X" and "Y" as units and then multiplying
194  * the numbers with the values associated with the respective
195  * unit from the conversion table.
196  *
197  * @param input input string to parse
198  * @param table table with the conversion of unit names to numbers
199  * @param output where to store the result
200  * @return GNUNET_OK on success, GNUNET_SYSERR on error
201  */
202 static int
203 convert_with_table (const char *input,
204                     const struct ConversionTable *table,
205                     unsigned long long *output)
206 {
207   unsigned long long ret;
208   char *in;
209   const char *tok;
210   unsigned long long last;
211   unsigned int i;
212
213   ret = 0;
214   last = 0;
215   in = GNUNET_strdup (input);
216   for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " "))
217   {
218     i = 0;
219     while ((table[i].name != NULL) && (0 != strcasecmp (table[i].name, tok)))
220       i++;
221     if (table[i].name != NULL)
222       last *= table[i].value;
223     else
224     {
225       ret += last;
226       last = 0;
227       if (1 != SSCANF (tok, "%llu", &last))
228       {
229         GNUNET_free (in);
230         return GNUNET_SYSERR;   /* expected number */
231       }
232     }
233   }
234   ret += last;
235   *output = ret;
236   GNUNET_free (in);
237   return GNUNET_OK;
238 }
239
240
241 /**
242  * Convert a given fancy human-readable size to bytes.
243  *
244  * @param fancy_size human readable string (i.e. 1 MB)
245  * @param size set to the size in bytes
246  * @return GNUNET_OK on success, GNUNET_SYSERR on error
247  */
248 int
249 GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size,
250                                     unsigned long long *size)
251 {
252   static const struct ConversionTable table[] =
253   {
254     { "B", 1},
255     { "KiB", 1024},
256     { "kB", 1000},
257     { "MiB", 1024 * 1024},
258     { "MB", 1000 * 1000},
259     { "GiB", 1024 * 1024 * 1024},
260     { "GB", 1000 * 1000 * 1000},
261     { "TiB", 1024LL * 1024LL * 1024LL * 1024LL},
262     { "TB", 1000LL * 1000LL * 1000LL * 1024LL},
263     { "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL},
264     { "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL},
265     { "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL},
266     { "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL},
267     { NULL, 0}
268   };
269
270   return convert_with_table (fancy_size,
271                              table,
272                              size);
273 }
274
275
276 /**
277  * Convert a given fancy human-readable time to our internal
278  * representation.
279  *
280  * @param fancy_time human readable string (i.e. 1 minute)
281  * @param rtime set to the relative time
282  * @return GNUNET_OK on success, GNUNET_SYSERR on error
283  */
284 int
285 GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time,
286                                        struct GNUNET_TIME_Relative *rtime)
287 {
288   static const struct ConversionTable table[] =
289   {
290     { "ms", 1},
291     { "s", 1000},
292     { "\"", 1000},
293     { "min", 60 * 1000},
294     { "minutes", 60 * 1000},
295     { "'", 60 * 1000},
296     { "h", 60 * 60 * 1000},
297     { "d", 24 * 60 * 60 * 1000},
298     { "a", 31536000000LL /* year */ },
299     { NULL, 0}
300   };
301   int ret;
302   unsigned long long val;
303
304   ret = convert_with_table (fancy_time,
305                             table,
306                             &val);
307   rtime->rel_value = (uint64_t) val;
308   return ret;
309 }
310
311
312 /**
313  * Convert a given fancy human-readable time to our internal
314  * representation.
315  *
316  * @param fancy_time human readable string (i.e. %Y-%m-%d %H:%M:%S)
317  * @param atime set to the absolute time
318  * @return GNUNET_OK on success, GNUNET_SYSERR on error
319  */
320 int
321 GNUNET_STRINGS_fancy_time_to_absolute (const char *fancy_time,
322                                        struct GNUNET_TIME_Absolute *atime)
323 {
324   struct tm tv;
325   time_t t;
326
327   if ( (NULL == strptime (fancy_time, "%c", &tv)) &&
328        (NULL == strptime (fancy_time, "%Ec", &tv)) &&
329        (NULL == strptime (fancy_time, "%Y-%m-%d %H:%M:%S", &tv)) &&
330        (NULL == strptime (fancy_time, "%Y-%m-%d %H:%M", &tv)) &&
331        (NULL == strptime (fancy_time, "%x", &tv)) &&
332        (NULL == strptime (fancy_time, "%Ex", &tv)) &&
333        (NULL == strptime (fancy_time, "%Y-%m-%d", &tv)) &&
334        (NULL == strptime (fancy_time, "%Y-%m", &tv)) &&
335        (NULL == strptime (fancy_time, "%Y", &tv)) )
336     return GNUNET_SYSERR;
337   t = mktime (&tv);
338   atime->abs_value = (uint64_t) ((uint64_t) t * 1000LL);
339   return GNUNET_OK;
340 }
341
342
343 /**
344  * Convert the len characters long character sequence
345  * given in input that is in the given input charset
346  * to a string in given output charset.
347  * @return the converted string (0-terminated),
348  *  if conversion fails, a copy of the orignal
349  *  string is returned.
350  */
351 char *
352 GNUNET_STRINGS_conv (const char *input, size_t len, const char *input_charset, const char *output_charset)
353 {
354   char *ret;
355
356 #if ENABLE_NLS && HAVE_ICONV
357   size_t tmpSize;
358   size_t finSize;
359   char *tmp;
360   char *itmp;
361   iconv_t cd;
362
363   cd = iconv_open (output_charset, input_charset);
364   if (cd == (iconv_t) - 1)
365   {
366     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "iconv_open");
367     LOG (GNUNET_ERROR_TYPE_WARNING, _("Character sets requested were `%s'->`%s'\n"),
368          input_charset, output_charset);
369     ret = GNUNET_malloc (len + 1);
370     memcpy (ret, input, len);
371     ret[len] = '\0';
372     return ret;
373   }
374   tmpSize = 3 * len + 4;
375   tmp = GNUNET_malloc (tmpSize);
376   itmp = tmp;
377   finSize = tmpSize;
378   if (iconv (cd,
379 #if FREEBSD || DARWIN || WINDOWS
380              (const char **) &input,
381 #else
382              (char **) &input,
383 #endif
384              &len, &itmp, &finSize) == SIZE_MAX)
385   {
386     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "iconv");
387     iconv_close (cd);
388     GNUNET_free (tmp);
389     ret = GNUNET_malloc (len + 1);
390     memcpy (ret, input, len);
391     ret[len] = '\0';
392     return ret;
393   }
394   ret = GNUNET_malloc (tmpSize - finSize + 1);
395   memcpy (ret, tmp, tmpSize - finSize);
396   ret[tmpSize - finSize] = '\0';
397   GNUNET_free (tmp);
398   if (0 != iconv_close (cd))
399     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "iconv_close");
400   return ret;
401 #else
402   ret = GNUNET_malloc (len + 1);
403   memcpy (ret, input, len);
404   ret[len] = '\0';
405   return ret;
406 #endif
407 }
408
409
410 /**
411  * Convert the len characters long character sequence
412  * given in input that is in the given charset
413  * to UTF-8.
414  * @return the converted string (0-terminated),
415  *  if conversion fails, a copy of the orignal
416  *  string is returned.
417  */
418 char *
419 GNUNET_STRINGS_to_utf8 (const char *input, size_t len, const char *charset)
420 {
421   return GNUNET_STRINGS_conv (input, len, charset, "UTF-8");
422 }
423
424
425 /**
426  * Convert the len bytes-long UTF-8 string
427  * given in input to the given charset.
428  *
429  * @return the converted string (0-terminated),
430  *  if conversion fails, a copy of the orignal
431  *  string is returned.
432  */
433 char *
434 GNUNET_STRINGS_from_utf8 (const char *input, size_t len, const char *charset)
435 {
436   return GNUNET_STRINGS_conv (input, len, "UTF-8", charset);
437 }
438
439
440 /**
441  * Convert the utf-8 input string to lowercase
442  * Output needs to be allocated appropriately
443  *
444  * @param input input string
445  * @param output output buffer
446  */
447 void
448 GNUNET_STRINGS_utf8_tolower(const char* input, char** output)
449 {
450   uint8_t *tmp_in;
451   size_t len;
452
453   tmp_in = u8_tolower ((uint8_t*)input, strlen ((char *) input),
454                        NULL, UNINORM_NFD, NULL, &len);
455   memcpy(*output, tmp_in, len);
456   (*output)[len] = '\0';
457   free(tmp_in);
458 }
459
460
461 /**
462  * Convert the utf-8 input string to uppercase
463  * Output needs to be allocated appropriately
464  *
465  * @param input input string
466  * @param output output buffer
467  */
468 void
469 GNUNET_STRINGS_utf8_toupper(const char* input, char** output)
470 {
471   uint8_t *tmp_in;
472   size_t len;
473
474   tmp_in = u8_toupper ((uint8_t*)input, strlen ((char *) input),
475                        NULL, UNINORM_NFD, NULL, &len);
476   memcpy(*output, tmp_in, len);
477   (*output)[len] = '\0';
478   free(tmp_in);
479 }
480
481
482 /**
483  * Complete filename (a la shell) from abbrevition.
484  * @param fil the name of the file, may contain ~/ or
485  *        be relative to the current directory
486  * @returns the full file name,
487  *          NULL is returned on error
488  */
489 char *
490 GNUNET_STRINGS_filename_expand (const char *fil)
491 {
492   char *buffer;
493 #ifndef MINGW
494   size_t len;
495   size_t n;
496   char *fm;
497   const char *fil_ptr;
498 #else
499   char *fn;
500   long lRet;
501 #endif
502
503   if (fil == NULL)
504     return NULL;
505
506 #ifndef MINGW
507   if (fil[0] == DIR_SEPARATOR)
508     /* absolute path, just copy */
509     return GNUNET_strdup (fil);
510   if (fil[0] == '~')
511   {
512     fm = getenv ("HOME");
513     if (fm == NULL)
514     {
515       LOG (GNUNET_ERROR_TYPE_WARNING,
516            _("Failed to expand `$HOME': environment variable `HOME' not set"));
517       return NULL;
518     }
519     fm = GNUNET_strdup (fm);
520     /* do not copy '~' */
521     fil_ptr = fil + 1;
522
523     /* skip over dir seperator to be consistent */
524     if (fil_ptr[0] == DIR_SEPARATOR)
525       fil_ptr++;
526   }
527   else
528   {
529     /* relative path */
530     fil_ptr = fil;
531     len = 512;
532     fm = NULL;
533     while (1)
534     {
535       buffer = GNUNET_malloc (len);
536       if (getcwd (buffer, len) != NULL)
537       {
538         fm = buffer;
539         break;
540       }
541       if ((errno == ERANGE) && (len < 1024 * 1024 * 4))
542       {
543         len *= 2;
544         GNUNET_free (buffer);
545         continue;
546       }
547       GNUNET_free (buffer);
548       break;
549     }
550     if (fm == NULL)
551     {
552       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "getcwd");
553       buffer = getenv ("PWD");  /* alternative */
554       if (buffer != NULL)
555         fm = GNUNET_strdup (buffer);
556     }
557     if (fm == NULL)
558       fm = GNUNET_strdup ("./");        /* give up */
559   }
560   n = strlen (fm) + 1 + strlen (fil_ptr) + 1;
561   buffer = GNUNET_malloc (n);
562   GNUNET_snprintf (buffer, n, "%s%s%s", fm,
563                    (fm[strlen (fm) - 1] ==
564                     DIR_SEPARATOR) ? "" : DIR_SEPARATOR_STR, fil_ptr);
565   GNUNET_free (fm);
566   return buffer;
567 #else
568   fn = GNUNET_malloc (MAX_PATH + 1);
569
570   if ((lRet = plibc_conv_to_win_path (fil, fn)) != ERROR_SUCCESS)
571   {
572     SetErrnoFromWinError (lRet);
573     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "plibc_conv_to_win_path");
574     return NULL;
575   }
576   /* is the path relative? */
577   if ((strncmp (fn + 1, ":\\", 2) != 0) && (strncmp (fn, "\\\\", 2) != 0))
578   {
579     char szCurDir[MAX_PATH + 1];
580
581     lRet = GetCurrentDirectory (MAX_PATH + 1, szCurDir);
582     if (lRet + strlen (fn) + 1 > (MAX_PATH + 1))
583     {
584       SetErrnoFromWinError (ERROR_BUFFER_OVERFLOW);
585       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetCurrentDirectory");
586       return NULL;
587     }
588     buffer = GNUNET_malloc (MAX_PATH + 1);
589     GNUNET_snprintf (buffer, MAX_PATH + 1, "%s\\%s", szCurDir, fn);
590     GNUNET_free (fn);
591     fn = buffer;
592   }
593
594   return fn;
595 #endif
596 }
597
598
599 /**
600  * Give relative time in human-readable fancy format.
601  *
602  * @param delta time in milli seconds
603  * @return time as human-readable string
604  */
605 char *
606 GNUNET_STRINGS_relative_time_to_string (struct GNUNET_TIME_Relative delta)
607 {
608   const char *unit = _( /* time unit */ "ms");
609   char *ret;
610   uint64_t dval = delta.rel_value;
611
612   if (delta.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
613     return GNUNET_strdup (_("eternity"));
614   if (dval > 5 * 1000)
615   {
616     dval = dval / 1000;
617     unit = _( /* time unit */ "s");
618     if (dval > 5 * 60)
619     {
620       dval = dval / 60;
621       unit = _( /* time unit */ "m");
622       if (dval > 5 * 60)
623       {
624         dval = dval / 60;
625         unit = _( /* time unit */ "h");
626         if (dval > 5 * 24)
627         {
628           dval = dval / 24;
629           unit = _( /* time unit */ " days");
630         }
631       }
632     }
633   }
634   GNUNET_asprintf (&ret, "%llu %s", dval, unit);
635   return ret;
636 }
637
638
639 /**
640  * "man ctime_r", except for GNUnet time; also, unlike ctime, the
641  * return value does not include the newline character.
642  *
643  * @param t time to convert
644  * @return absolute time in human-readable format
645  */
646 char *
647 GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t)
648 {
649   time_t tt;
650   char *ret;
651
652   if (t.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value)
653     return GNUNET_strdup (_("end of time"));
654   tt = t.abs_value / 1000;
655 #ifdef ctime_r
656   ret = ctime_r (&tt, GNUNET_malloc (32));
657 #else
658   ret = GNUNET_strdup (ctime (&tt));
659 #endif
660   ret[strlen (ret) - 1] = '\0';
661   return ret;
662 }
663
664
665 /**
666  * "man basename"
667  * Returns a pointer to a part of filename (allocates nothing)!
668  *
669  * @param filename filename to extract basename from
670  * @return short (base) name of the file (that is, everything following the
671  *         last directory separator in filename. If filename ends with a
672  *         directory separator, the result will be a zero-length string.
673  *         If filename has no directory separators, the result is filename
674  *         itself.
675  */
676 const char *
677 GNUNET_STRINGS_get_short_name (const char *filename)
678 {
679   const char *short_fn = filename;
680   const char *ss;
681   while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR))
682       && (ss[1] != '\0'))
683     short_fn = 1 + ss;
684   return short_fn;
685 }
686
687
688 /**
689  * Get the numeric value corresponding to a character.
690  *
691  * @param a a character
692  * @return corresponding numeric value
693  */
694 static unsigned int
695 getValue__ (unsigned char a)
696 {
697   if ((a >= '0') && (a <= '9'))
698     return a - '0';
699   if ((a >= 'A') && (a <= 'V'))
700     return (a - 'A' + 10);
701   return -1;
702 }
703
704
705 /**
706  * Convert binary data to ASCII encoding.  The ASCII encoding is rather
707  * GNUnet specific.  It was chosen such that it only uses characters
708  * in [0-9A-V], can be produced without complex arithmetics and uses a
709  * small number of characters.  
710  * Does not append 0-terminator, but returns a pointer to the place where
711  * it should be placed, if needed.
712  *
713  * @param data data to encode
714  * @param size size of data (in bytes)
715  * @param out buffer to fill
716  * @param out_size size of the buffer. Must be large enough to hold
717  * ((size*8) + (((size*8) % 5) > 0 ? 5 - ((size*8) % 5) : 0)) / 5 bytes
718  * @return pointer to the next byte in 'out' or NULL on error.
719  */
720 char *
721 GNUNET_STRINGS_data_to_string (const unsigned char *data, size_t size, char *out, size_t out_size)
722 {
723   /**
724    * 32 characters for encoding 
725    */
726   static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
727   unsigned int wpos;
728   unsigned int rpos;
729   unsigned int bits;
730   unsigned int vbit;
731
732   GNUNET_assert (data != NULL);
733   GNUNET_assert (out != NULL);
734   if (out_size < (((size*8) + ((size*8) % 5)) % 5))
735   {
736     GNUNET_break (0);
737     return NULL;
738   }
739   vbit = 0;
740   wpos = 0;
741   rpos = 0;
742   bits = 0;
743   while ((rpos < size) || (vbit > 0))
744   {
745     if ((rpos < size) && (vbit < 5))
746     {
747       bits = (bits << 8) | data[rpos++];   /* eat 8 more bits */
748       vbit += 8;
749     }
750     if (vbit < 5)
751     {
752       bits <<= (5 - vbit);      /* zero-padding */
753       GNUNET_assert (vbit == ((size * 8) % 5));
754       vbit = 5;
755     }
756     if (wpos >= out_size)
757     {
758       GNUNET_break (0);
759       return NULL;
760     }
761     out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31];
762     vbit -= 5;
763   }
764   if (wpos != out_size)
765   {
766     GNUNET_break (0);
767     return NULL;
768   }
769   GNUNET_assert (vbit == 0);
770   return &out[wpos];
771 }
772
773
774 /**
775  * Convert ASCII encoding back to data
776  * out_size must match exactly the size of the data before it was encoded.
777  *
778  * @param enc the encoding
779  * @param enclen number of characters in 'enc' (without 0-terminator, which can be missing)
780  * @param out location where to store the decoded data
781  * @param out_size sizeof the output buffer
782  * @return GNUNET_OK on success, GNUNET_SYSERR if result has the wrong encoding
783  */
784 int
785 GNUNET_STRINGS_string_to_data (const char *enc, size_t enclen,
786                               unsigned char *out, size_t out_size)
787 {
788   unsigned int rpos;
789   unsigned int wpos;
790   unsigned int bits;
791   unsigned int vbit;
792   int ret;
793   int shift;
794   int encoded_len = out_size * 8;
795   if (encoded_len % 5 > 0)
796   {
797     vbit = encoded_len % 5; /* padding! */
798     shift = 5 - vbit;
799   }
800   else
801   {
802     vbit = 0;
803     shift = 0;
804   }
805   if ((encoded_len + shift) / 5 != enclen)
806     return GNUNET_SYSERR;
807
808   wpos = out_size;
809   rpos = enclen;
810   bits = (ret = getValue__ (enc[--rpos])) >> (5 - encoded_len % 5);
811   if (-1 == ret)
812     return GNUNET_SYSERR;
813   while (wpos > 0)
814   {
815     GNUNET_assert (rpos > 0);
816     bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits;
817     if (-1 == ret)
818       return GNUNET_SYSERR;
819     vbit += 5;
820     if (vbit >= 8)
821     {
822       out[--wpos] = (unsigned char) bits;
823       bits >>= 8;
824       vbit -= 8;
825     }
826   }
827   GNUNET_assert (rpos == 0);
828   GNUNET_assert (vbit == 0);
829   return GNUNET_OK;
830 }
831
832
833 /**
834  * Parse a path that might be an URI.
835  *
836  * @param path path to parse. Must be NULL-terminated.
837  * @param scheme_part a pointer to 'char *' where a pointer to a string that
838  *        represents the URI scheme will be stored. Can be NULL. The string is
839  *        allocated by the function, and should be freed by GNUNET_free() when
840  *        it is no longer needed.
841  * @param path_part a pointer to 'const char *' where a pointer to the path
842  *        part of the URI will be stored. Can be NULL. Points to the same block
843  *        of memory as 'path', and thus must not be freed. Might point to '\0',
844  *        if path part is zero-length.
845  * @return GNUNET_YES if it's an URI, GNUNET_NO otherwise. If 'path' is not
846  *         an URI, '* scheme_part' and '*path_part' will remain unchanged
847  *         (if they weren't NULL).
848  */
849 int
850 GNUNET_STRINGS_parse_uri (const char *path, char **scheme_part,
851     const char **path_part)
852 {
853   size_t len;
854   int i, end;
855   int pp_state = 0;
856   const char *post_scheme_part = NULL;
857   len = strlen (path);
858   for (end = 0, i = 0; !end && i < len; i++)
859   {
860     switch (pp_state)
861     {
862     case 0:
863       if (path[i] == ':' && i > 0)
864       {
865         pp_state += 1;
866         continue;
867       }
868       if (!((path[i] >= 'A' && path[i] <= 'Z') || (path[i] >= 'a' && path[i] <= 'z')
869           || (path[i] >= '0' && path[i] <= '9') || path[i] == '+' || path[i] == '-'
870           || (path[i] == '.')))
871         end = 1;
872       break;
873     case 1:
874     case 2:
875       if (path[i] == '/')
876       {
877         pp_state += 1;
878         continue;
879       }
880       end = 1;
881       break;
882     case 3:
883       post_scheme_part = &path[i];
884       end = 1;
885       break;
886     default:
887       end = 1;
888     }
889   }
890   if (post_scheme_part == NULL)
891     return GNUNET_NO;
892   if (scheme_part)
893   {
894     *scheme_part = GNUNET_malloc (post_scheme_part - path + 1);
895     memcpy (*scheme_part, path, post_scheme_part - path);
896     (*scheme_part)[post_scheme_part - path] = '\0';
897   }
898   if (path_part)
899     *path_part = post_scheme_part;
900   return GNUNET_YES;
901 }
902
903
904 /**
905  * Check whether 'filename' is absolute or not, and if it's an URI
906  *
907  * @param filename filename to check
908  * @param can_be_uri GNUNET_YES to check for being URI, GNUNET_NO - to
909  *        assume it's not URI
910  * @param r_is_uri a pointer to an int that is set to GNUNET_YES if 'filename'
911  *        is URI and to GNUNET_NO otherwise. Can be NULL. If 'can_be_uri' is
912  *        not GNUNET_YES, *r_is_uri is set to GNUNET_NO.
913  * @param r_uri_scheme a pointer to a char * that is set to a pointer to URI scheme.
914  *        The string is allocated by the function, and should be freed with
915  *        GNUNET_free (). Can be NULL.
916  * @return GNUNET_YES if 'filename' is absolute, GNUNET_NO otherwise.
917  */
918 int
919 GNUNET_STRINGS_path_is_absolute (const char *filename, int can_be_uri,
920     int *r_is_uri, char **r_uri_scheme)
921 {
922 #if WINDOWS
923   size_t len;
924 #endif
925   const char *post_scheme_path;
926   int is_uri;
927   char * uri;
928   /* consider POSIX paths to be absolute too, even on W32,
929    * as plibc expansion will fix them for us.
930    */
931   if (filename[0] == '/')
932     return GNUNET_YES;
933   if (can_be_uri)
934   {
935     is_uri = GNUNET_STRINGS_parse_uri (filename, &uri, &post_scheme_path);
936     if (r_is_uri)
937       *r_is_uri = is_uri;
938     if (is_uri)
939     {
940       if (r_uri_scheme)
941         *r_uri_scheme = uri;
942       else
943         GNUNET_free_non_null (uri);
944 #if WINDOWS
945       len = strlen(post_scheme_path);
946       /* Special check for file:///c:/blah
947        * We want to parse 'c:/', not '/c:/'
948        */
949       if (post_scheme_path[0] == '/' && len >= 3 && post_scheme_path[2] == ':')
950         post_scheme_path = &post_scheme_path[1];
951 #endif
952       return GNUNET_STRINGS_path_is_absolute (post_scheme_path, GNUNET_NO, NULL, NULL);
953     }
954   }
955   else
956   {
957     is_uri = GNUNET_NO;
958     if (r_is_uri)
959       *r_is_uri = GNUNET_NO;
960   }
961 #if WINDOWS
962   len = strlen (filename);
963   if (len >= 3 &&
964       ((filename[0] >= 'A' && filename[0] <= 'Z')
965       || (filename[0] >= 'a' && filename[0] <= 'z'))
966       && filename[1] == ':' && (filename[2] == '/' || filename[2] == '\\'))
967     return GNUNET_YES;
968 #endif
969   return GNUNET_NO;
970 }
971
972 #if MINGW
973 #define         _IFMT           0170000 /* type of file */
974 #define         _IFLNK          0120000 /* symbolic link */
975 #define  S_ISLNK(m)     (((m)&_IFMT) == _IFLNK)
976 #endif
977
978
979 /**
980  * Perform 'checks' on 'filename'
981  * 
982  * @param filename file to check
983  * @param checks checks to perform
984  * @return GNUNET_YES if all checks pass, GNUNET_NO if at least one of them
985  *         fails, GNUNET_SYSERR when a check can't be performed
986  */
987 int
988 GNUNET_STRINGS_check_filename (const char *filename,
989                                enum GNUNET_STRINGS_FilenameCheck checks)
990 {
991   struct stat st;
992   if ( (NULL == filename) || (filename[0] == '\0') )
993     return GNUNET_SYSERR;
994   if (0 != (checks & GNUNET_STRINGS_CHECK_IS_ABSOLUTE))
995     if (!GNUNET_STRINGS_path_is_absolute (filename, GNUNET_NO, NULL, NULL))
996       return GNUNET_NO;
997   if (0 != (checks & (GNUNET_STRINGS_CHECK_EXISTS
998                       | GNUNET_STRINGS_CHECK_IS_DIRECTORY
999                       | GNUNET_STRINGS_CHECK_IS_LINK)))
1000   {
1001     if (0 != STAT (filename, &st))
1002     {
1003       if (0 != (checks & GNUNET_STRINGS_CHECK_EXISTS))
1004         return GNUNET_NO;
1005       else
1006         return GNUNET_SYSERR;
1007     }
1008   }
1009   if (0 != (checks & GNUNET_STRINGS_CHECK_IS_DIRECTORY))
1010     if (!S_ISDIR (st.st_mode))
1011       return GNUNET_NO;
1012   if (0 != (checks & GNUNET_STRINGS_CHECK_IS_LINK))
1013     if (!S_ISLNK (st.st_mode))
1014       return GNUNET_NO;
1015   return GNUNET_YES;
1016 }
1017
1018
1019 /**
1020  * Tries to convert 'zt_addr' string to an IPv6 address.
1021  * The string is expected to have the format "[ABCD::01]:80".
1022  * 
1023  * @param zt_addr 0-terminated string. May be mangled by the function.
1024  * @param addrlen length of zt_addr (not counting 0-terminator).
1025  * @param r_buf a buffer to fill. Initially gets filled with zeroes,
1026  *        then its sin6_port, sin6_family and sin6_addr are set appropriately.
1027  * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which
1028  *         case the contents of r_buf are undefined.
1029  */
1030 int
1031 GNUNET_STRINGS_to_address_ipv6 (const char *zt_addr, 
1032                                 uint16_t addrlen,
1033                                 struct sockaddr_in6 *r_buf)
1034 {
1035   char zbuf[addrlen + 1];
1036   int ret;
1037   char *port_colon;
1038   unsigned int port;
1039
1040   if (addrlen < 6)
1041     return GNUNET_SYSERR;  
1042   memcpy (zbuf, zt_addr, addrlen);
1043   if ('[' != zbuf[0])
1044   {
1045     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1046                 _("IPv6 address did not start with `['\n"));
1047     return GNUNET_SYSERR;
1048   }
1049   zbuf[addrlen] = '\0';
1050   port_colon = strrchr (zbuf, ':');
1051   if (NULL == port_colon)
1052   {
1053     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1054                 _("IPv6 address did contain ':' to separate port number\n"));
1055     return GNUNET_SYSERR;
1056   }
1057   if (']' != *(port_colon - 1))
1058   {
1059     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1060                 _("IPv6 address did contain ']' before ':' to separate port number\n"));
1061     return GNUNET_SYSERR;
1062   }
1063   ret = SSCANF (port_colon, ":%u", &port);
1064   if ( (1 != ret) || (port > 65535) )
1065   {
1066     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1067                 _("IPv6 address did contain a valid port number after the last ':'\n"));
1068     return GNUNET_SYSERR;
1069   }
1070   *(port_colon-1) = '\0';
1071   memset (r_buf, 0, sizeof (struct sockaddr_in6));
1072   ret = inet_pton (AF_INET6, &zbuf[1], &r_buf->sin6_addr);
1073   if (ret <= 0)
1074   {
1075     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1076                 _("Invalid IPv6 address `%s': %s\n"),
1077                 &zbuf[1],
1078                 STRERROR (errno));
1079     return GNUNET_SYSERR;
1080   }
1081   r_buf->sin6_port = htons (port);
1082   r_buf->sin6_family = AF_INET6;
1083 #if HAVE_SOCKADDR_IN_SIN_LEN
1084   r_buf->sin6_len = (u_char) sizeof (struct sockaddr_in6);
1085 #endif
1086   return GNUNET_OK;
1087 }
1088
1089
1090 /**
1091  * Tries to convert 'zt_addr' string to an IPv4 address.
1092  * The string is expected to have the format "1.2.3.4:80".
1093  * 
1094  * @param zt_addr 0-terminated string. May be mangled by the function.
1095  * @param addrlen length of zt_addr (not counting 0-terminator).
1096  * @param r_buf a buffer to fill.
1097  * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which case
1098  *         the contents of r_buf are undefined.
1099  */
1100 int
1101 GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen,
1102                                 struct sockaddr_in *r_buf)
1103 {
1104   unsigned int temps[4];
1105   unsigned int port;
1106   unsigned int cnt;
1107
1108   if (addrlen < 9)
1109     return GNUNET_SYSERR;
1110   cnt = SSCANF (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port);
1111   if (5 != cnt)
1112     return GNUNET_SYSERR;
1113   for (cnt = 0; cnt < 4; cnt++)
1114     if (temps[cnt] > 0xFF)
1115       return GNUNET_SYSERR;
1116   if (port > 65535)
1117     return GNUNET_SYSERR;
1118   r_buf->sin_family = AF_INET;
1119   r_buf->sin_port = htons (port);
1120   r_buf->sin_addr.s_addr = htonl ((temps[0] << 24) + (temps[1] << 16) +
1121                                   (temps[2] << 8) + temps[3]);
1122 #if HAVE_SOCKADDR_IN_SIN_LEN
1123   r_buf->sin_len = (u_char) sizeof (struct sockaddr_in);
1124 #endif
1125   return GNUNET_OK;
1126 }
1127
1128
1129 /**
1130  * Tries to convert 'addr' string to an IP (v4 or v6) address.
1131  * Will automatically decide whether to treat 'addr' as v4 or v6 address.
1132  * 
1133  * @param addr a string, may not be 0-terminated.
1134  * @param addrlen number of bytes in addr (if addr is 0-terminated,
1135  *        0-terminator should not be counted towards addrlen).
1136  * @param r_buf a buffer to fill.
1137  * @return GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which
1138  *         case the contents of r_buf are undefined.
1139  */
1140 int
1141 GNUNET_STRINGS_to_address_ip (const char *addr, 
1142                               uint16_t addrlen,
1143                               struct sockaddr_storage *r_buf)
1144 {
1145   if (addr[0] == '[')
1146     return GNUNET_STRINGS_to_address_ipv6 (addr, addrlen, (struct sockaddr_in6 *) r_buf);
1147   return GNUNET_STRINGS_to_address_ipv4 (addr, addrlen, (struct sockaddr_in *) r_buf);
1148 }
1149
1150
1151 /**
1152  * Makes a copy of argv that consists of a single memory chunk that can be
1153  * freed with a single call to GNUNET_free ();
1154  */
1155 static char *const *
1156 _make_continuous_arg_copy (int argc, char *const *argv)
1157 {
1158   size_t argvsize = 0;
1159   int i;
1160   char **new_argv;
1161   char *p;
1162   for (i = 0; i < argc; i++)
1163     argvsize += strlen (argv[i]) + 1 + sizeof (char *);
1164   new_argv = GNUNET_malloc (argvsize + sizeof (char *));
1165   p = (char *) &new_argv[argc + 1];
1166   for (i = 0; i < argc; i++)
1167   {
1168     new_argv[i] = p;
1169     strcpy (p, argv[i]);
1170     p += strlen (argv[i]) + 1;
1171   }
1172   new_argv[argc] = NULL;
1173   return (char *const *) new_argv;
1174 }
1175
1176
1177 /**
1178  * Returns utf-8 encoded arguments.
1179  * Does nothing (returns a copy of argc and argv) on any platform
1180  * other than W32.
1181  * Returned argv has u8argv[u8argc] == NULL.
1182  * Returned argv is a single memory block, and can be freed with a single
1183  *   GNUNET_free () call.
1184  *
1185  * @param argc argc (as given by main())
1186  * @param argv argv (as given by main())
1187  * @param u8argc a location to store new argc in (though it's th same as argc)
1188  * @param u8argv a location to store new argv in
1189  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1190  */
1191 int
1192 GNUNET_STRINGS_get_utf8_args (int argc, char *const *argv, int *u8argc, char *const **u8argv)
1193 {
1194 #if WINDOWS
1195   wchar_t *wcmd;
1196   wchar_t **wargv;
1197   int wargc;
1198   int i;
1199   char **split_u8argv;
1200
1201   wcmd = GetCommandLineW ();
1202   if (NULL == wcmd)
1203     return GNUNET_SYSERR;
1204   wargv = CommandLineToArgvW (wcmd, &wargc);
1205   if (NULL == wargv)
1206     return GNUNET_SYSERR;
1207
1208   split_u8argv = GNUNET_malloc (argc * sizeof (char *));
1209
1210   for (i = 0; i < wargc; i++)
1211   {
1212     size_t strl;
1213     /* Hopefully it will allocate us NUL-terminated strings... */
1214     split_u8argv[i] = (char *) u16_to_u8 (wargv[i], wcslen (wargv[i]) + 1, NULL, &strl);
1215     if (split_u8argv == NULL)
1216     {
1217       int j;
1218       for (j = 0; j < i; j++)
1219         free (split_u8argv[j]);
1220       GNUNET_free (split_u8argv);
1221       LocalFree (wargv);
1222       return GNUNET_SYSERR;
1223     }
1224   }
1225
1226   *u8argv = _make_continuous_arg_copy (wargc, split_u8argv);
1227   *u8argc = wargc;
1228
1229   for (i = 0; i < wargc; i++)
1230     free (split_u8argv[i]);
1231   free (split_u8argv);
1232   return GNUNET_OK;
1233 #else
1234   char *const *new_argv = (char *const *) _make_continuous_arg_copy (argc, argv);
1235   *u8argv = new_argv;
1236   *u8argc = argc;
1237   return GNUNET_OK;
1238 #endif
1239 }
1240
1241 /* end of strings.c */