/*
This file is part of GNUnet.
- (C) 2005-2013 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2005-2017 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
*/
-
/**
* @file util/strings.c
* @brief string functions
#if HAVE_ICONV
#include <iconv.h>
#endif
-#include "gnunet_util_lib.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_strings_lib.h"
#include <unicase.h>
#include <unistr.h>
#include <uniconv.h>
-#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+#define LOG(kind,...) GNUNET_log_from (kind, "util-strings", __VA_ARGS__)
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-strings", syscall)
/**
*
* Unlike using "snprintf" with "%s", this function
* will add 0-terminators after each string. The
- * "GNUNET_string_buffer_tokenize" function can be
+ * #GNUNET_string_buffer_tokenize() function can be
* used to parse the buffer back into individual
* strings.
*
if (buffer != NULL)
{
GNUNET_assert (needed + slen <= size);
- memcpy (&buffer[needed], s, slen);
+ GNUNET_memcpy (&buffer[needed], s, slen);
}
needed += slen;
count--;
}
+/**
+ * Convert a peer path to a human-readable string.
+ *
+ * @param pids array of PIDs to convert to a string
+ * @param num_pids length of the @a pids array
+ * @return string representing the array of @a pids
+ */
+char *
+GNUNET_STRINGS_pp2s (const struct GNUNET_PeerIdentity *pids,
+ unsigned int num_pids)
+{
+ char *buf;
+ size_t off;
+ size_t plen = num_pids * 5 + 1;
+
+ off = 0;
+ buf = GNUNET_malloc (plen);
+ for (unsigned int i = 0;
+ i < num_pids;
+ i++)
+ {
+ off += GNUNET_snprintf (&buf[off],
+ plen - off,
+ "%s%s",
+ GNUNET_i2s (&pids[i]),
+ (i == num_pids -1) ? "" : "-");
+ }
+ return buf;
+}
+
+
/**
* Given a buffer of a given size, find "count"
* 0-terminated strings in the buffer and assign
{ "\"", 1000 * 1000LL },
{ "m", 60 * 1000 * 1000LL},
{ "min", 60 * 1000 * 1000LL},
+ { "minute", 60 * 1000 * 1000LL},
{ "minutes", 60 * 1000 * 1000LL},
{ "'", 60 * 1000 * 1000LL},
{ "h", 60 * 60 * 1000 * 1000LL},
+ { "hour", 60 * 60 * 1000 * 1000LL},
+ { "hours", 60 * 60 * 1000 * 1000LL},
{ "d", 24 * 60 * 60 * 1000LL * 1000LL},
{ "day", 24 * 60 * 60 * 1000LL * 1000LL},
{ "days", 24 * 60 * 60 * 1000LL * 1000LL},
{ "week", 7 * 24 * 60 * 60 * 1000LL * 1000LL},
{ "weeks", 7 * 24 * 60 * 60 * 1000LL * 1000LL},
+ { "year", 31536000000000LL /* year */ },
+ { "years", 31536000000000LL /* year */ },
{ "a", 31536000000000LL /* year */ },
{ NULL, 0}
};
struct tm tv;
time_t t;
- if (0 == strcasecmp ("end of time", fancy_time))
+ if (0 == strcasecmp ("end of time",
+ fancy_time))
{
*atime = GNUNET_TIME_UNIT_FOREVER_ABS;
return GNUNET_OK;
return GNUNET_SYSERR;
t = mktime (&tv);
atime->abs_value_us = (uint64_t) ((uint64_t) t * 1000LL * 1000LL);
-#if WINDOWS
- {
- DWORD tzv;
- TIME_ZONE_INFORMATION tzi;
- tzv = GetTimeZoneInformation (&tzi);
- if (TIME_ZONE_ID_INVALID != tzv)
- {
- atime->abs_value_us -= 1000LL * 1000LL * tzi.Bias * 60LL;
- }
- }
-#endif
return GNUNET_OK;
}
if (0 == strcmp (output_charset, "UTF-8"))
{
ret = GNUNET_malloc (u8_string_length + 1);
- memcpy (ret, u8_string, u8_string_length);
+ GNUNET_memcpy (ret, u8_string, u8_string_length);
ret[u8_string_length] = '\0';
free (u8_string);
return ret;
goto fail;
}
ret = GNUNET_malloc (encoded_string_length + 1);
- memcpy (ret, encoded_string, encoded_string_length);
+ GNUNET_memcpy (ret, encoded_string, encoded_string_length);
ret[encoded_string_length] = '\0';
free (encoded_string);
return ret;
fail:
- LOG (GNUNET_ERROR_TYPE_WARNING, _("Character sets requested were `%s'->`%s'\n"),
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Character sets requested were `%s'->`%s'\n"),
"UTF-8", output_charset);
ret = GNUNET_malloc (len + 1);
- memcpy (ret, input, len);
+ GNUNET_memcpy (ret, input, len);
ret[len] = '\0';
return ret;
}
tmp_in = u8_tolower ((uint8_t*)input, strlen ((char *) input),
NULL, UNINORM_NFD, NULL, &len);
- memcpy(output, tmp_in, len);
+ GNUNET_memcpy(output, tmp_in, len);
output[len] = '\0';
free(tmp_in);
}
tmp_in = u8_toupper ((uint8_t*)input, strlen ((char *) input),
NULL, UNINORM_NFD, NULL, &len);
- memcpy (output, tmp_in, len);
+ GNUNET_memcpy (output, tmp_in, len);
output[len] = '\0';
free (tmp_in);
}
char *buffer;
#ifndef MINGW
size_t len;
- size_t n;
char *fm;
const char *fil_ptr;
#else
}
if (fm == NULL)
{
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "getcwd");
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+ "getcwd");
buffer = getenv ("PWD"); /* alternative */
if (buffer != NULL)
fm = GNUNET_strdup (buffer);
if (fm == NULL)
fm = GNUNET_strdup ("./"); /* give up */
}
- n = strlen (fm) + 1 + strlen (fil_ptr) + 1;
- buffer = GNUNET_malloc (n);
- GNUNET_snprintf (buffer, n, "%s%s%s", fm,
+ GNUNET_asprintf (&buffer,
+ "%s%s%s",
+ fm,
(fm[strlen (fm) - 1] ==
DIR_SEPARATOR) ? "" : DIR_SEPARATOR_STR, fil_ptr);
GNUNET_free (fm);
if ((lRet = plibc_conv_to_win_path (fil, fn)) != ERROR_SUCCESS)
{
SetErrnoFromWinError (lRet);
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "plibc_conv_to_win_path");
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+ "plibc_conv_to_win_path");
return NULL;
}
/* is the path relative? */
- if ((strncmp (fn + 1, ":\\", 2) != 0) && (strncmp (fn, "\\\\", 2) != 0))
+ if ( (0 != strncmp (fn + 1, ":\\", 2)) &&
+ (0 != strncmp (fn, "\\\\", 2)) )
{
char szCurDir[MAX_PATH + 1];
- lRet = GetCurrentDirectory (MAX_PATH + 1, szCurDir);
+ lRet = GetCurrentDirectory (MAX_PATH + 1,
+ szCurDir);
if (lRet + strlen (fn) + 1 > (MAX_PATH + 1))
{
SetErrnoFromWinError (ERROR_BUFFER_OVERFLOW);
- LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetCurrentDirectory");
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+ "GetCurrentDirectory");
return NULL;
}
- buffer = GNUNET_malloc (MAX_PATH + 1);
- GNUNET_snprintf (buffer, MAX_PATH + 1, "%s\\%s", szCurDir, fn);
+ GNUNET_asprintf (&buffer,
+ "%s\\%s",
+ szCurDir,
+ fn);
GNUNET_free (fn);
fn = buffer;
}
/**
- * Get the numeric value corresponding to a character.
+ * Get the decoded value corresponding to a character according to Crockford
+ * Base32 encoding.
*
* @param a a character
* @return corresponding numeric value
static unsigned int
getValue__ (unsigned char a)
{
+ unsigned int dec;
+
+ switch (a)
+ {
+ case 'O':
+ case 'o':
+ a = '0';
+ break;
+ case 'i':
+ case 'I':
+ case 'l':
+ case 'L':
+ a = '1';
+ break;
+ /* also consider U to be V */
+ case 'u':
+ case 'U':
+ a = 'V';
+ break;
+ default:
+ break;
+ }
if ((a >= '0') && (a <= '9'))
return a - '0';
- if ((a >= 'A') && (a <= 'V'))
- return (a - 'A' + 10);
- if ((a >= 'a') && (a <= 'v'))
- return (a - 'a' + 10);
+ if ((a >= 'a') && (a <= 'z'))
+ a = toupper (a);
+ /* return (a - 'a' + 10); */
+ dec = 0;
+ if ((a >= 'A') && (a <= 'Z'))
+ {
+ if ('I' < a)
+ dec++;
+ if ('L' < a)
+ dec++;
+ if ('O' < a)
+ dec++;
+ if ('U' < a)
+ dec++;
+ return (a - 'A' + 10 - dec);
+ }
return -1;
}
/**
- * Convert binary data to ASCII encoding. The ASCII encoding is rather
- * GNUnet specific. It was chosen such that it only uses characters
- * in [0-9A-V], can be produced without complex arithmetics and uses a
- * small number of characters.
- * Does not append 0-terminator, but returns a pointer to the place where
- * it should be placed, if needed.
+ * Convert binary data to ASCII encoding using Crockford Base32 encoding.
+ * Returns a pointer to the byte after the last byte in the string, that
+ * is where the 0-terminator was placed if there was room.
*
* @param data data to encode
* @param size size of data (in bytes)
* @param out buffer to fill
* @param out_size size of the buffer. Must be large enough to hold
- * ((size*8) + (((size*8) % 5) > 0 ? 5 - ((size*8) % 5) : 0)) / 5 bytes
- * @return pointer to the next byte in 'out' or NULL on error.
+ * (size * 8 + 4) / 5 bytes
+ * @return pointer to the next byte in @a out or NULL on error.
*/
char *
-GNUNET_STRINGS_data_to_string (const void *data, size_t size, char *out, size_t out_size)
+GNUNET_STRINGS_data_to_string (const void *data,
+ size_t size,
+ char *out,
+ size_t out_size)
{
/**
* 32 characters for encoding
*/
- static char *encTable__ = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+ static char *encTable__ = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
unsigned int wpos;
unsigned int rpos;
unsigned int bits;
unsigned int vbit;
const unsigned char *udata;
- GNUNET_assert (data != NULL);
- GNUNET_assert (out != NULL);
udata = data;
- if (out_size < (((size*8) + ((size*8) % 5)) % 5))
+ if (out_size < (size * 8 + 4) / 5)
{
GNUNET_break (0);
return NULL;
out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31];
vbit -= 5;
}
- GNUNET_assert (vbit == 0);
+ GNUNET_assert (0 == vbit);
if (wpos < out_size)
out[wpos] = '\0';
return &out[wpos];
/**
- * Convert ASCII encoding back to data
- * out_size must match exactly the size of the data before it was encoded.
+ * Return the base32crockford encoding of the given buffer.
+ *
+ * The returned string will be freshly allocated, and must be free'd
+ * with GNUNET_free().
+ *
+ * @param buffer with data
+ * @param size size of the buffer
+ * @return freshly allocated, null-terminated string
+ */
+char *
+GNUNET_STRINGS_data_to_string_alloc (const void *buf,
+ size_t size)
+{
+ char *str_buf;
+ size_t len = size * 8;
+ char *end;
+
+ if (len % 5 > 0)
+ len += 5 - len % 5;
+ len /= 5;
+ str_buf = GNUNET_malloc (len + 1);
+ end = GNUNET_STRINGS_data_to_string (buf, size, str_buf, len);
+ if (NULL == end)
+ {
+ GNUNET_free (str_buf);
+ return NULL;
+ }
+ *end = '\0';
+ return str_buf;
+}
+
+
+/**
+ * Convert Crockford Base32hex encoding back to data.
+ * @a out_size must match exactly the size of the data before it was encoded.
*
* @param enc the encoding
* @param enclen number of characters in @a enc (without 0-terminator, which can be missing)
{
vbit = encoded_len % 5; /* padding! */
shift = 5 - vbit;
- bits = (ret = getValue__ (enc[--rpos])) >> (5 - (encoded_len % 5));
+ bits = (ret = getValue__ (enc[--rpos])) >> shift;
}
else
{
if (scheme_part)
{
*scheme_part = GNUNET_malloc (post_scheme_part - path + 1);
- memcpy (*scheme_part, path, post_scheme_part - path);
+ GNUNET_memcpy (*scheme_part, path, post_scheme_part - path);
(*scheme_part)[post_scheme_part - path] = '\0';
}
if (path_part)
/**
- * Tries to convert 'zt_addr' string to an IPv6 address.
+ * Tries to convert @a zt_addr string to an IPv6 address.
* The string is expected to have the format "[ABCD::01]:80".
*
* @param zt_addr 0-terminated string. May be mangled by the function.
if (addrlen < 6)
return GNUNET_SYSERR;
- memcpy (zbuf, zt_addr, addrlen);
+ GNUNET_memcpy (zbuf, zt_addr, addrlen);
if ('[' != zbuf[0])
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
* the contents of @a r_buf are undefined.
*/
int
-GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen,
+GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr,
+ uint16_t addrlen,
struct sockaddr_in *r_buf)
{
unsigned int temps[4];
if (addrlen < 9)
return GNUNET_SYSERR;
- cnt = SSCANF (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port);
+ cnt = SSCANF (zt_addr,
+ "%u.%u.%u.%u:%u",
+ &temps[0],
+ &temps[1],
+ &temps[2],
+ &temps[3],
+ &port);
if (5 != cnt)
return GNUNET_SYSERR;
for (cnt = 0; cnt < 4; cnt++)
* @param addrlen number of bytes in @a addr (if addr is 0-terminated,
* 0-terminator should not be counted towards addrlen).
* @param r_buf a buffer to fill.
- * @return #GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which
- * case the contents of r_buf are undefined.
+ * @return #GNUNET_OK if conversion succeded. #GNUNET_SYSERR otherwise, in which
+ * case the contents of @a r_buf are undefined.
*/
int
GNUNET_STRINGS_to_address_ip (const char *addr,
}
+/**
+ * Parse an address given as a string into a
+ * `struct sockaddr`.
+ *
+ * @param addr the address
+ * @param[out] af set to the parsed address family (i.e. AF_INET)
+ * @param[out] sa set to the parsed address
+ * @return 0 on error, otherwise number of bytes in @a sa
+ */
+size_t
+GNUNET_STRINGS_parse_socket_addr (const char *addr,
+ uint8_t *af,
+ struct sockaddr **sa)
+{
+ char *cp = GNUNET_strdup (addr);
+
+ *af = AF_UNSPEC;
+ if ('[' == *addr)
+ {
+ /* IPv6 */
+ *sa = GNUNET_malloc (sizeof (struct sockaddr_in6));
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_to_address_ipv6 (cp,
+ strlen (cp),
+ (struct sockaddr_in6 *) *sa))
+ {
+ GNUNET_free (*sa);
+ *sa = NULL;
+ GNUNET_free (cp);
+ return 0;
+ }
+ *af = AF_INET6;
+ GNUNET_free (cp);
+ return sizeof (struct sockaddr_in6);
+ }
+ else
+ {
+ /* IPv4 */
+ *sa = GNUNET_malloc (sizeof (struct sockaddr_in));
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_to_address_ipv4 (cp,
+ strlen (cp),
+ (struct sockaddr_in *) *sa))
+ {
+ GNUNET_free (*sa);
+ *sa = NULL;
+ GNUNET_free (cp);
+ return 0;
+ }
+ *af = AF_INET;
+ GNUNET_free (cp);
+ return sizeof (struct sockaddr_in);
+ }
+}
+
+
/**
* Makes a copy of argv that consists of a single memory chunk that can be
* freed with a single call to GNUNET_free();
* @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
*/
int
-GNUNET_STRINGS_get_utf8_args (int argc, char *const *argv, int *u8argc, char *const **u8argv)
+GNUNET_STRINGS_get_utf8_args (int argc,
+ char *const *argv,
+ int *u8argc,
+ char *const **u8argv)
{
#if WINDOWS
wchar_t *wcmd;