/* stringprep.c --- Core stringprep implementation.
* Copyright (C) 2002, 2003, 2004 Simon Josefsson
*
* This file is part of GNU Libidn.
*
* GNU Libidn is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* GNU Libidn 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GNU Libidn; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "stringprep.h"
static ssize_t
stringprep_find_character_in_table (uint32_t ucs4,
const Stringprep_table_element * table)
{
ssize_t i;
/* This is where typical uses of Libidn spends very close to all CPU
time and causes most cache misses. One could easily do a binary
search instead. Before rewriting this, I want hard evidence this
slowness is at all relevant in typical applications. (I don't
dispute optimization may improve matters significantly, I'm
mostly interested in having someone give real-world benchmark on
the impact of libidn.) */
for (i = 0; table[i].start || table[i].end; i++)
if (ucs4 >= table[i].start &&
ucs4 <= (table[i].end ? table[i].end : table[i].start))
return i;
return -1;
}
static ssize_t
stringprep_find_string_in_table (uint32_t * ucs4,
size_t ucs4len,
size_t * tablepos,
const Stringprep_table_element * table)
{
size_t j;
ssize_t pos;
for (j = 0; j < ucs4len; j++)
if ((pos = stringprep_find_character_in_table (ucs4[j], table)) != -1)
{
if (tablepos)
*tablepos = pos;
return j;
}
return -1;
}
static int
stringprep_apply_table_to_string (uint32_t * ucs4,
size_t * ucs4len,
size_t maxucs4len,
const Stringprep_table_element * table)
{
ssize_t pos;
size_t i, maplen;
while ((pos = stringprep_find_string_in_table (ucs4, *ucs4len,
&i, table)) != -1)
{
for (maplen = STRINGPREP_MAX_MAP_CHARS;
maplen > 0 && table[i].map[maplen - 1] == 0; maplen--)
;
if (*ucs4len - 1 + maplen >= maxucs4len)
return STRINGPREP_TOO_SMALL_BUFFER;
memmove (&ucs4[pos + maplen], &ucs4[pos + 1],
sizeof (uint32_t) * (*ucs4len - pos - 1));
memcpy (&ucs4[pos], table[i].map, sizeof (uint32_t) * maplen);
*ucs4len = *ucs4len - 1 + maplen;
}