Files
libmicrohttpd/src/daemon/https/opencdk/misc.c
T

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