mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-10-07 04:02:18 +03:00
572 lines
14 KiB
C
572 lines
14 KiB
C
/* misc.c
|
|
* Copyright (C) 2002, 2003 Timo Schulz
|
|
* Copyright (C) 1998-2002, 2007 Free Software Foundation, Inc.
|
|
*
|
|
* This file is part of OpenCDK.
|
|
*
|
|
* OpenCDK is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* OpenCDK is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "opencdk.h"
|
|
#include "main.h"
|
|
|
|
|
|
u32
|
|
_cdk_buftou32 (const byte * buf)
|
|
{
|
|
u32 u;
|
|
|
|
if (!buf)
|
|
return 0;
|
|
u = buf[0] << 24;
|
|
u |= buf[1] << 16;
|
|
u |= buf[2] << 8;
|
|
u |= buf[3];
|
|
return u;
|
|
}
|
|
|
|
|
|
void
|
|
_cdk_u32tobuf (u32 u, byte * buf)
|
|
{
|
|
if (!buf)
|
|
return;
|
|
buf[0] = u >> 24;
|
|
buf[1] = u >> 16;
|
|
buf[2] = u >> 8;
|
|
buf[3] = u;
|
|
}
|
|
|
|
|
|
static const char *
|
|
parse_version_number (const char *s, int *number)
|
|
{
|
|
int val = 0;
|
|
|
|
if (*s == '0' && isdigit (s[1]))
|
|
return NULL;
|
|
/* leading zeros are not allowed */
|
|
for (; isdigit (*s); s++)
|
|
{
|
|
val *= 10;
|
|
val += *s - '0';
|
|
}
|
|
*number = val;
|
|
return val < 0 ? NULL : s;
|
|
}
|
|
|
|
|
|
static const char *
|
|
parse_version_string (const char *s, int *major, int *minor, int *micro)
|
|
{
|
|
s = parse_version_number (s, major);
|
|
if (!s || *s != '.')
|
|
return NULL;
|
|
s++;
|
|
s = parse_version_number (s, minor);
|
|
if (!s || *s != '.')
|
|
return NULL;
|
|
s++;
|
|
s = parse_version_number (s, micro);
|
|
if (!s)
|
|
return NULL;
|
|
return s; /* patchlevel */
|
|
}
|
|
|
|
|
|
/**
|
|
* cdk_check_version:
|
|
* @req_version: The requested version
|
|
*
|
|
* Check that the the version of the library is at minimum the requested
|
|
* one and return the version string; return NULL if the condition is
|
|
* not satisfied. If a NULL is passed to this function, no check is done,
|
|
*but the version string is simply returned.
|
|
**/
|
|
const char *
|
|
cdk_check_version (const char *req_version)
|
|
{
|
|
const char *ver = VERSION;
|
|
int my_major, my_minor, my_micro;
|
|
int rq_major, rq_minor, rq_micro;
|
|
const char *my_plvl, *rq_plvl;
|
|
|
|
if (!req_version)
|
|
return ver;
|
|
my_plvl = parse_version_string (ver, &my_major, &my_minor, &my_micro);
|
|
if (!my_plvl)
|
|
return NULL;
|
|
/* very strange our own version is bogus */
|
|
rq_plvl = parse_version_string (req_version, &rq_major, &rq_minor,
|
|
&rq_micro);
|
|
if (!rq_plvl)
|
|
return NULL; /* req version string is invalid */
|
|
if (my_major > rq_major
|
|
|| (my_major == rq_major && my_minor > rq_minor)
|
|
|| (my_major == rq_major && my_minor == rq_minor
|
|
&& my_micro > rq_micro)
|
|
|| (my_major == rq_major && my_minor == rq_minor
|
|
&& my_micro == rq_micro && strcmp (my_plvl, rq_plvl) >= 0))
|
|
return ver;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* cdk_strlist_free:
|
|
* @sl: the string list
|
|
*
|
|
* Release the string list object.
|
|
**/
|
|
void
|
|
cdk_strlist_free (cdk_strlist_t sl)
|
|
{
|
|
cdk_strlist_t sl2;
|
|
|
|
for (; sl; sl = sl2)
|
|
{
|
|
sl2 = sl->next;
|
|
cdk_free (sl);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* cdk_strlist_add:
|
|
* @list: destination string list
|
|
* @string: the string to add
|
|
*
|
|
* Add the given list to the string list.
|
|
**/
|
|
cdk_strlist_t
|
|
cdk_strlist_add (cdk_strlist_t * list, const char *string)
|
|
{
|
|
cdk_strlist_t sl;
|
|
|
|
if (!string)
|
|
return NULL;
|
|
|
|
sl = cdk_calloc (1, sizeof *sl + strlen (string) + 1);
|
|
if (!sl)
|
|
return NULL;
|
|
strcpy (sl->d, string);
|
|
sl->next = *list;
|
|
*list = sl;
|
|
return sl;
|
|
}
|
|
|
|
|
|
/**
|
|
* cdk_strlist_next:
|
|
* @root: the opaque string list.
|
|
* @r_str: optional argument to store the string data.
|
|
*
|
|
* Return the next string list node from @root. The optional
|
|
* argument @r_str return the data of the current (!) node.
|
|
**/
|
|
cdk_strlist_t
|
|
cdk_strlist_next (cdk_strlist_t root, const char **r_str)
|
|
{
|
|
cdk_strlist_t node;
|
|
|
|
if (root && r_str)
|
|
*r_str = root->d;
|
|
for (node = root->next; node; node = node->next)
|
|
return node;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const char *
|
|
_cdk_memistr (const char *buf, size_t buflen, const char *sub)
|
|
{
|
|
const byte *t, *s;
|
|
size_t n;
|
|
|
|
for (t = (byte *) buf, n = buflen, s = (byte *) sub; n; t++, n--)
|
|
{
|
|
if (toupper (*t) == toupper (*s))
|
|
{
|
|
for (buf = t++, buflen = n--, s++;
|
|
n && toupper (*t) == toupper ((byte) * s); t++, s++, n--)
|
|
;
|
|
if (!*s)
|
|
return buf;
|
|
t = (byte *) buf;
|
|
n = buflen;
|
|
s = (byte *) sub;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* cdk_utf8_encode:
|
|
* @string:
|
|
*
|
|
* Encode the given string in utf8 and return it.
|
|
**/
|
|
char *
|
|
cdk_utf8_encode (const char *string)
|
|
{
|
|
const byte *s;
|
|
char *buffer;
|
|
byte *p;
|
|
size_t length;
|
|
|
|
/* FIXME: We should use iconv if possible for utf8 issues. */
|
|
for (s = (const byte *) string, length = 0; *s; s++)
|
|
{
|
|
length++;
|
|
if (*s & 0x80)
|
|
length++;
|
|
}
|
|
|
|
buffer = cdk_calloc (1, length + 1);
|
|
for (p = (byte *) buffer, s = (byte *) string; *s; s++)
|
|
{
|
|
if (*s & 0x80)
|
|
{
|
|
*p++ = 0xc0 | ((*s >> 6) & 3);
|
|
*p++ = 0x80 | (*s & 0x3f);
|
|
}
|
|
else
|
|
*p++ = *s;
|
|
}
|
|
*p = 0;
|
|
return buffer;
|
|
}
|
|
|
|
|
|
/**
|
|
* cdk_utf8_decode:
|
|
* @string: the string to decode
|
|
* @length: the length of the string
|
|
* @delim: the delimiter
|
|
*
|
|
* Decode the given utf8 string and return the native representation.
|
|
**/
|
|
char *
|
|
cdk_utf8_decode (const char *string, size_t length, int delim)
|
|
{
|
|
int nleft;
|
|
int i;
|
|
byte encbuf[8];
|
|
int encidx;
|
|
const byte *s;
|
|
size_t n;
|
|
byte *buffer = NULL, *p = NULL;
|
|
unsigned long val = 0;
|
|
size_t slen;
|
|
int resync = 0;
|
|
|
|
/* 1. pass (p==NULL): count the extended utf-8 characters */
|
|
/* 2. pass (p!=NULL): create string */
|
|
for (;;)
|
|
{
|
|
for (slen = length, nleft = encidx = 0, n = 0, s = (byte *) string;
|
|
slen; s++, slen--)
|
|
{
|
|
if (resync)
|
|
{
|
|
if (!(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)))
|
|
{
|
|
/* still invalid */
|
|
if (p)
|
|
{
|
|
sprintf ((char *) p, "\\x%02x", *s);
|
|
p += 4;
|
|
}
|
|
n += 4;
|
|
continue;
|
|
}
|
|
resync = 0;
|
|
}
|
|
if (!nleft)
|
|
{
|
|
if (!(*s & 0x80))
|
|
{ /* plain ascii */
|
|
if (*s < 0x20 || *s == 0x7f || *s == delim ||
|
|
(delim && *s == '\\'))
|
|
{
|
|
n++;
|
|
if (p)
|
|
*p++ = '\\';
|
|
switch (*s)
|
|
{
|
|
case '\n':
|
|
n++;
|
|
if (p)
|
|
*p++ = 'n';
|
|
break;
|
|
case '\r':
|
|
n++;
|
|
if (p)
|
|
*p++ = 'r';
|
|
break;
|
|
case '\f':
|
|
n++;
|
|
if (p)
|
|
*p++ = 'f';
|
|
break;
|
|
case '\v':
|
|
n++;
|
|
if (p)
|
|
*p++ = 'v';
|
|
break;
|
|
case '\b':
|
|
n++;
|
|
if (p)
|
|
*p++ = 'b';
|
|
break;
|
|
case 0:
|
|
n++;
|
|
if (p)
|
|
*p++ = '0';
|
|
break;
|
|
default:
|
|
n += 3;
|
|
if (p)
|
|
{
|
|
sprintf ((char *) p, "x%02x", *s);
|
|
p += 3;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (p)
|
|
*p++ = *s;
|
|
n++;
|
|
}
|
|
}
|
|
else if ((*s & 0xe0) == 0xc0)
|
|
{ /* 110x xxxx */
|
|
val = *s & 0x1f;
|
|
nleft = 1;
|
|
encidx = 0;
|
|
encbuf[encidx++] = *s;
|
|
}
|
|
else if ((*s & 0xf0) == 0xe0)
|
|
{ /* 1110 xxxx */
|
|
val = *s & 0x0f;
|
|
nleft = 2;
|
|
encidx = 0;
|
|
encbuf[encidx++] = *s;
|
|
}
|
|
else if ((*s & 0xf8) == 0xf0)
|
|
{ /* 1111 0xxx */
|
|
val = *s & 0x07;
|
|
nleft = 3;
|
|
encidx = 0;
|
|
encbuf[encidx++] = *s;
|
|
}
|
|
else if ((*s & 0xfc) == 0xf8)
|
|
{ /* 1111 10xx */
|
|
val = *s & 0x03;
|
|
nleft = 4;
|
|
encidx = 0;
|
|
encbuf[encidx++] = *s;
|
|
}
|
|
else if ((*s & 0xfe) == 0xfc)
|
|
{ /* 1111 110x */
|
|
val = *s & 0x01;
|
|
nleft = 5;
|
|
encidx = 0;
|
|
encbuf[encidx++] = *s;
|
|
}
|
|
else
|
|
{ /* invalid encoding: print as \xnn */
|
|
if (p)
|
|
{
|
|
sprintf ((char *) p, "\\x%02x", *s);
|
|
p += 4;
|
|
}
|
|
n += 4;
|
|
resync = 1;
|
|
}
|
|
}
|
|
else if (*s < 0x80 || *s >= 0xc0)
|
|
{ /* invalid */
|
|
if (p)
|
|
{
|
|
for (i = 0; i < encidx; i++)
|
|
{
|
|
sprintf ((char *) p, "\\x%02x", encbuf[i]);
|
|
p += 4;
|
|
}
|
|
sprintf ((char *) p, "\\x%02x", *s);
|
|
p += 4;
|
|
}
|
|
n += 4 + 4 * encidx;
|
|
nleft = 0;
|
|
encidx = 0;
|
|
resync = 1;
|
|
}
|
|
else
|
|
{
|
|
encbuf[encidx++] = *s;
|
|
val <<= 6;
|
|
val |= *s & 0x3f;
|
|
if (!--nleft)
|
|
{ /* ready native set */
|
|
if (val >= 0x80 && val < 256)
|
|
{
|
|
n++; /* we can simply print this character */
|
|
if (p)
|
|
*p++ = val;
|
|
}
|
|
else
|
|
{ /* we do not have a translation: print utf8 */
|
|
if (p)
|
|
{
|
|
for (i = 0; i < encidx; i++)
|
|
{
|
|
sprintf ((char *) p, "\\x%02x", encbuf[i]);
|
|
p += 4;
|
|
}
|
|
}
|
|
n += encidx * 4;
|
|
encidx = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
if (!buffer) /* allocate the buffer after the first pass */
|
|
buffer = p = cdk_malloc (n + 1);
|
|
else
|
|
{
|
|
*p = 0; /* make a string */
|
|
return (char *) buffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Map the gcrypt error to a valid opencdk error constant. */
|
|
cdk_error_t
|
|
_cdk_map_gcry_error (gcry_error_t err)
|
|
{
|
|
/* FIXME: We need to catch them all. */
|
|
switch (gpg_err_code (err))
|
|
{
|
|
case GPG_ERR_NO_ERROR:
|
|
return CDK_Success;
|
|
case GPG_ERR_INV_VALUE:
|
|
return CDK_Inv_Value;
|
|
case GPG_ERR_GENERAL:
|
|
return CDK_General_Error;
|
|
case GPG_ERR_INV_PACKET:
|
|
return CDK_Inv_Packet;
|
|
case GPG_ERR_TOO_SHORT:
|
|
return CDK_Too_Short;
|
|
case GPG_ERR_TOO_LARGE:
|
|
return CDK_Inv_Value;
|
|
case GPG_ERR_NO_PUBKEY:
|
|
case GPG_ERR_NO_SECKEY:
|
|
return CDK_Error_No_Key;
|
|
case GPG_ERR_BAD_SIGNATURE:
|
|
return CDK_Bad_Sig;
|
|
case GPG_ERR_NO_DATA:
|
|
return CDK_No_Data;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (cdk_error_t) err;
|
|
}
|
|
|
|
|
|
/* Remove all trailing white spaces from the string. */
|
|
void
|
|
_cdk_trim_string (char *s, int canon)
|
|
{
|
|
while (s && *s &&
|
|
(s[strlen (s) - 1] == '\t' ||
|
|
s[strlen (s) - 1] == '\r' ||
|
|
s[strlen (s) - 1] == '\n' || s[strlen (s) - 1] == ' '))
|
|
s[strlen (s) - 1] = '\0';
|
|
if (canon)
|
|
strcat (s, "\r\n");
|
|
}
|
|
|
|
|
|
int
|
|
_cdk_check_args (int overwrite, const char *in, const char *out)
|
|
{
|
|
struct stat stbuf;
|
|
|
|
if (!in || !out)
|
|
return CDK_Inv_Value;
|
|
if (strlen (in) == strlen (out) && strcmp (in, out) == 0)
|
|
return CDK_Inv_Mode;
|
|
if (!overwrite && !stat (out, &stbuf))
|
|
return CDK_Inv_Mode;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
|
|
FILE *
|
|
my_tmpfile (void)
|
|
{
|
|
/* Because the tmpfile() version of wine is not really useful,
|
|
we implement our own version to avoid problems with 'make check'. */
|
|
static const char *letters = "abcdefghijklmnopqrstuvwxyz";
|
|
char buf[512], rnd[24];
|
|
FILE *fp;
|
|
int fd, i;
|
|
|
|
gcry_create_nonce (rnd, DIM (rnd));
|
|
for (i = 0; i < DIM (rnd) - 1; i++)
|
|
{
|
|
char c = letters[(unsigned char) rnd[i] % 26];
|
|
rnd[i] = c;
|
|
}
|
|
rnd[DIM (rnd) - 1] = 0;
|
|
if (!GetTempPath (464, buf))
|
|
return NULL;
|
|
strcat (buf, "_cdk_");
|
|
strcat (buf, rnd);
|
|
|
|
/* We need to make sure the file will be deleted when it is closed. */
|
|
fd = _open (buf, _O_CREAT | _O_EXCL | _O_TEMPORARY |
|
|
_O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE);
|
|
if (fd == -1)
|
|
return NULL;
|
|
fp = fdopen (fd, "w+b");
|
|
if (fp != NULL)
|
|
return fp;
|
|
_close (fd);
|
|
return NULL;
|
|
}
|
|
#else
|
|
FILE *
|
|
my_tmpfile (void)
|
|
{
|
|
return tmpfile ();
|
|
}
|
|
#endif
|