~ubuntu-branches/ubuntu/jaunty/psi/jaunty

« back to all changes in this revision

Viewing changes to iris/libidn/stringprep.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2005-01-10 17:41:43 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050110174143-ltocv5zapl6blf5d
Tags: 0.9.3-1
* New upstream release
* Cleaned up debian/rules (some things are done by upstream Makefiles now)
* Fixed some lintian warnings:
  - removed executable bit from some .png files
  - moved psi.desktop to /usr/share/applications
* Updated menu files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* stringprep.c         Core stringprep implementation.
 
2
 * Copyright (C) 2002, 2003  Simon Josefsson
 
3
 *
 
4
 * This file is part of GNU Libidn.
 
5
 *
 
6
 * GNU Libidn is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2.1 of the License, or (at your option) any later version.
 
10
 *
 
11
 * GNU Libidn is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with GNU Libidn; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 *
 
20
 */
 
21
 
 
22
#include "internal.h"
 
23
 
 
24
static ssize_t
 
25
stringprep_find_character_in_table (my_uint32_t ucs4,
 
26
                                    Stringprep_table_element * table)
 
27
{
 
28
  ssize_t i;
 
29
 
 
30
  for (i = 0; table[i].start; i++)
 
31
    if (ucs4 >= table[i].start &&
 
32
        ucs4 <= (table[i].end ? table[i].end : table[i].start))
 
33
      return i;
 
34
 
 
35
  return -1;
 
36
}
 
37
 
 
38
static ssize_t
 
39
stringprep_find_string_in_table (my_uint32_t * ucs4,
 
40
                                 size_t ucs4len,
 
41
                                 size_t * tablepos,
 
42
                                 Stringprep_table_element * table)
 
43
{
 
44
  size_t j;
 
45
  ssize_t pos;
 
46
 
 
47
  for (j = 0; j < ucs4len; j++)
 
48
    if ((pos = stringprep_find_character_in_table (ucs4[j], table)) != -1)
 
49
      {
 
50
        if (tablepos)
 
51
          *tablepos = pos;
 
52
        return j;
 
53
      }
 
54
 
 
55
  return -1;
 
56
}
 
57
 
 
58
static int
 
59
stringprep_apply_table_to_string (my_uint32_t * ucs4,
 
60
                                  size_t * ucs4len,
 
61
                                  size_t maxucs4len,
 
62
                                  Stringprep_table_element * table,
 
63
                                  const char *tablename)
 
64
{
 
65
  ssize_t pos;
 
66
  size_t i, maplen;
 
67
 
 
68
  while ((pos = stringprep_find_string_in_table (ucs4, *ucs4len,
 
69
                                                 &i, table)) != -1)
 
70
    {
 
71
      for (maplen = STRINGPREP_MAX_MAP_CHARS;
 
72
           maplen > 0 && table[i].map[maplen - 1] == 0; maplen--)
 
73
        ;
 
74
 
 
75
      if (*ucs4len - 1 + maplen >= maxucs4len)
 
76
        return STRINGPREP_TOO_SMALL_BUFFER;
 
77
 
 
78
      memmove (&ucs4[pos + maplen], &ucs4[pos + 1],
 
79
               *ucs4len * sizeof (my_uint32_t) - (&ucs4[pos + 1] - ucs4));
 
80
      memcpy (&ucs4[pos], table[i].map, sizeof (my_uint32_t) * maplen);
 
81
      *ucs4len = *ucs4len - 1 + maplen;
 
82
    }
 
83
 
 
84
  return STRINGPREP_OK;
 
85
}
 
86
 
 
87
#define INVERTED(x) ((x) & ((~0UL) >> 1))
 
88
#define UNAPPLICAPLEFLAGS(flags, profileflags) \
 
89
  ((!INVERTED(profileflags) && !(profileflags & flags) && profileflags) || \
 
90
   ( INVERTED(profileflags) && (profileflags & flags)))
 
91
 
 
92
/**
 
93
 * stringprep:
 
94
 * @in: input/ouput array with string to prepare.
 
95
 * @maxlen: maximum length of input/output array.
 
96
 * @flags: optional stringprep profile flags.
 
97
 * @profile: pointer to stringprep profile to use.
 
98
 *
 
99
 * Prepare the input UTF-8 string according to the stringprep profile.
 
100
 * Normally application programmers use stringprep profile macros such
 
101
 * as stringprep_nameprep(), stringprep_kerberos5() etc instead of
 
102
 * calling this function directly.
 
103
 *
 
104
 * Since the stringprep operation can expand the string, @maxlen
 
105
 * indicate how large the buffer holding the string is.  The @flags
 
106
 * are one of Stringprep_profile_flags, or 0.  The profile indicates
 
107
 * processing details specific to that profile.  Your application can
 
108
 * define new profiles, possibly re-using the generic stringprep
 
109
 * tables that always will be part of the library.
 
110
 *
 
111
 * Note that you must convert strings entered in the systems locale
 
112
 * into UTF-8 before using this function.
 
113
 *
 
114
 * Return value: Returns 0 iff successful, or an error code.
 
115
 **/
 
116
int
 
117
stringprep (char *in,
 
118
            size_t maxlen,
 
119
            Stringprep_profile_flags flags, Stringprep_profile * profile)
 
120
{
 
121
  size_t i, j;
 
122
  ssize_t k;
 
123
  int rc;
 
124
  char *p = 0;
 
125
  my_uint32_t *q = 0;
 
126
  my_uint32_t *ucs4;
 
127
  size_t ucs4len, maxucs4len;
 
128
 
 
129
  ucs4 = stringprep_utf8_to_ucs4 (in, -1, &ucs4len);
 
130
  maxucs4len = 4 * ucs4len + 10;        /* XXX */
 
131
  ucs4 = realloc (ucs4, 1 + maxucs4len * sizeof (my_uint32_t));
 
132
  if (!ucs4)
 
133
    {
 
134
      rc = STRINGPREP_MALLOC_ERROR;
 
135
      goto done;
 
136
    }
 
137
 
 
138
  for (i = 0; profile[i].operation; i++)
 
139
    {
 
140
      switch (profile[i].operation)
 
141
        {
 
142
        case STRINGPREP_NFKC:
 
143
          if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
 
144
            {
 
145
              break;
 
146
            }
 
147
 
 
148
          if (flags & STRINGPREP_NO_NFKC && !profile[i].flags)
 
149
            {
 
150
              /* Profile requires NFKC, but callee asked for no NFKC. */
 
151
              rc = STRINGPREP_FLAG_ERROR;
 
152
              goto done;
 
153
            }
 
154
 
 
155
          q = stringprep_ucs4_nfkc_normalize (ucs4, ucs4len);
 
156
 
 
157
          if (!q)
 
158
            {
 
159
              rc = STRINGPREP_NFKC_FAILED;
 
160
              goto done;
 
161
            }
 
162
 
 
163
          for (j = 0; q[j]; j++)
 
164
            ;
 
165
 
 
166
          free (ucs4);
 
167
          ucs4 = q;
 
168
          ucs4len = j;
 
169
          q = 0;
 
170
          break;
 
171
 
 
172
        case STRINGPREP_PROHIBIT_TABLE:
 
173
          k = stringprep_find_string_in_table (ucs4, ucs4len,
 
174
                                               NULL, profile[i].table);
 
175
          if (k != -1)
 
176
            {
 
177
              rc = STRINGPREP_CONTAINS_PROHIBITED;
 
178
              goto done;
 
179
            }
 
180
          break;
 
181
 
 
182
        case STRINGPREP_UNASSIGNED_TABLE:
 
183
          if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
 
184
            break;
 
185
          if (flags & STRINGPREP_NO_UNASSIGNED)
 
186
            {
 
187
              k = stringprep_find_string_in_table
 
188
                (ucs4, ucs4len, NULL, profile[i].table);
 
189
              if (k != -1)
 
190
                {
 
191
                  rc = STRINGPREP_CONTAINS_UNASSIGNED;
 
192
                  goto done;
 
193
                }
 
194
            }
 
195
          break;
 
196
 
 
197
        case STRINGPREP_MAP_TABLE:
 
198
          if (UNAPPLICAPLEFLAGS (flags, profile[i].flags))
 
199
            break;
 
200
          rc = stringprep_apply_table_to_string
 
201
            (ucs4, &ucs4len, maxucs4len, profile[i].table, profile[i].name);
 
202
          if (rc != STRINGPREP_OK)
 
203
            goto done;
 
204
          break;
 
205
 
 
206
        case STRINGPREP_BIDI_PROHIBIT_TABLE:
 
207
        case STRINGPREP_BIDI_RAL_TABLE:
 
208
        case STRINGPREP_BIDI_L_TABLE:
 
209
          break;
 
210
 
 
211
        case STRINGPREP_BIDI:
 
212
          {
 
213
            int done_prohibited = 0;
 
214
            int done_ral = 0;
 
215
            int done_l = 0;
 
216
            int contains_ral = -1;
 
217
            int contains_l = -1;
 
218
 
 
219
            for (j = 0; profile[j].operation; j++)
 
220
              if (profile[j].operation == STRINGPREP_BIDI_PROHIBIT_TABLE)
 
221
                {
 
222
                  done_prohibited = 1;
 
223
                  k = stringprep_find_string_in_table (ucs4, ucs4len,
 
224
                                                       NULL,
 
225
                                                       profile[j].table);
 
226
                  if (k != -1)
 
227
                    {
 
228
                      rc = STRINGPREP_BIDI_CONTAINS_PROHIBITED;
 
229
                      goto done;
 
230
                    }
 
231
                }
 
232
              else if (profile[j].operation == STRINGPREP_BIDI_RAL_TABLE)
 
233
                {
 
234
                  done_ral = 1;
 
235
                  if (stringprep_find_string_in_table
 
236
                      (ucs4, ucs4len, NULL, profile[j].table) != -1)
 
237
                    contains_ral = j;
 
238
                }
 
239
              else if (profile[j].operation == STRINGPREP_BIDI_L_TABLE)
 
240
                {
 
241
                  done_l = 1;
 
242
                  if (stringprep_find_string_in_table
 
243
                      (ucs4, ucs4len, NULL, profile[j].table) != -1)
 
244
                    contains_l = j;
 
245
                }
 
246
 
 
247
            if (!done_prohibited || !done_ral || !done_l)
 
248
              {
 
249
                rc = STRINGPREP_PROFILE_ERROR;
 
250
                goto done;
 
251
              }
 
252
 
 
253
            if (contains_ral != -1 && contains_l != -1)
 
254
              {
 
255
                rc = STRINGPREP_BIDI_BOTH_L_AND_RAL;
 
256
                goto done;
 
257
              }
 
258
 
 
259
            if (contains_ral != -1)
 
260
              {
 
261
                if (!(stringprep_find_character_in_table
 
262
                      (ucs4[0], profile[contains_ral].table) != -1 &&
 
263
                      stringprep_find_character_in_table
 
264
                      (ucs4[ucs4len - 1], profile[contains_ral].table) != -1))
 
265
                  {
 
266
                    rc = STRINGPREP_BIDI_LEADTRAIL_NOT_RAL;
 
267
                    goto done;
 
268
                  }
 
269
              }
 
270
          }
 
271
          break;
 
272
 
 
273
        default:
 
274
          rc = STRINGPREP_PROFILE_ERROR;
 
275
          goto done;
 
276
          break;
 
277
        }
 
278
    }
 
279
 
 
280
  p = stringprep_ucs4_to_utf8 (ucs4, ucs4len, 0, 0);
 
281
 
 
282
  if (strlen (p) >= maxlen)
 
283
    {
 
284
      rc = STRINGPREP_TOO_SMALL_BUFFER;
 
285
      goto done;
 
286
    }
 
287
 
 
288
  strcpy (in, p);               /* flawfinder: ignore */
 
289
 
 
290
  rc = STRINGPREP_OK;
 
291
 
 
292
done:
 
293
  if (p)
 
294
    free (p);
 
295
  if (q)
 
296
    free (q);
 
297
  if (ucs4)
 
298
    free (ucs4);
 
299
  return rc;
 
300
}
 
301
 
 
302
/**
 
303
 * stringprep_profile:
 
304
 * @in: input/ouput array with string to prepare.
 
305
 * @out: output variable with newly allocate string.
 
306
 * @flags: optional stringprep profile flags.
 
307
 * @profile: name of stringprep profile to use.
 
308
 *
 
309
 * Prepare the input UTF-8 string according to the stringprep profile.
 
310
 * Normally application programmers use stringprep profile macros such
 
311
 * as stringprep_nameprep(), stringprep_kerberos5() etc instead of
 
312
 * calling this function directly.
 
313
 *
 
314
 * Note that you must convert strings entered in the systems locale
 
315
 * into UTF-8 before using this function.
 
316
 *
 
317
 * The output @out variable must be deallocated by the caller.
 
318
 *
 
319
 * Return value: Returns 0 iff successful, or an error code.
 
320
 **/
 
321
int
 
322
stringprep_profile (char *in,
 
323
                    char **out, char *profile, Stringprep_profile_flags flags)
 
324
{
 
325
  Stringprep_profiles *p;
 
326
  char *str;
 
327
  size_t len;
 
328
  int rc;
 
329
 
 
330
  for (p = &stringprep_profiles[0]; p->name; p++)
 
331
    if (strcmp (p->name, profile) == 0)
 
332
      break;
 
333
 
 
334
  if (!p || !p->name || !p->tables)
 
335
    return STRINGPREP_UNKNOWN_PROFILE;
 
336
 
 
337
  len = strlen (in) + BUFSIZ;
 
338
  str = (char *) malloc (len);
 
339
  if (str == NULL)
 
340
    return STRINGPREP_MALLOC_ERROR;
 
341
 
 
342
  strcpy (str, in);
 
343
 
 
344
  rc = stringprep (str, len, flags, p->tables);
 
345
 
 
346
  if (rc == STRINGPREP_OK)
 
347
    *out = str;
 
348
  else
 
349
    free (str);
 
350
 
 
351
  return rc;
 
352
}
 
353
 
 
354
/**
 
355
 * STRINGPREP_VERSION
 
356
 *
 
357
 * String defined via CPP denoting the header file version number.
 
358
 * Used together with stringprep_check_version() to verify header file
 
359
 * and run-time library consistency.
 
360
 */
 
361
 
 
362
/**
 
363
 * STRINGPREP_MAX_MAP_CHARS
 
364
 *
 
365
 * Maximum number of code points that can replace a single code point,
 
366
 * during stringprep mapping.
 
367
 */
 
368
 
 
369
/**
 
370
 * Stringprep_rc
 
371
 *
 
372
 * Enumerated return codes of stringprep(), stringprep_profile()
 
373
 * functions (and macros using those functions).  The value 0 is
 
374
 * guaranteed to always correspond to success.
 
375
 */
 
376
 
 
377
/**
 
378
 * Stringprep_profile_flags:
 
379
 * @STRINGPREP_NO_NFKC: Disable the NFKC normalization, as well as
 
380
 *   selecting the non-NFKC case folding tables.  Usually the profile
 
381
 *   specifies BIDI and NFKC settings, and applications should not
 
382
 *   override it unless in special situations.
 
383
 * @STRINGPREP_NO_BIDI: Disable the BIDI step.  Usually the profile
 
384
 *   specifies BIDI and NFKC settings, and applications should not
 
385
 *   override it unless in special situations.
 
386
 * @STRINGPREP_NO_UNASSIGNED: Make the library return with an error if
 
387
 *   string contains unassigned characters according to profile.
 
388
 *
 
389
 * Stringprep profile flags.
 
390
 */
 
391
 
 
392
/**
 
393
 * Stringprep_profile_steps:
 
394
 *
 
395
 * Various steps in the stringprep algorithm.  You really want to
 
396
 * study the source code to understand this one.  Only useful if you
 
397
 * want to add another profile.
 
398
 */
 
399
 
 
400
/**
 
401
 * stringprep_nameprep:
 
402
 * @in: input/ouput array with string to prepare.
 
403
 * @maxlen: maximum length of input/output array.
 
404
 *
 
405
 * Prepare the input UTF-8 string according to the nameprep profile.
 
406
 * The AllowUnassigned flag is true, use
 
407
 * stringprep_nameprep_no_unassigned() for false AllowUnassigned.
 
408
 * Returns 0 iff successful, or an error code.
 
409
 **/
 
410
 
 
411
/**
 
412
 * stringprep_nameprep_no_unassigned:
 
413
 * @in: input/ouput array with string to prepare.
 
414
 * @maxlen: maximum length of input/output array.
 
415
 *
 
416
 * Prepare the input UTF-8 string according to the nameprep profile.
 
417
 * The AllowUnassigned flag is false, use stringprep_nameprep() for
 
418
 * true AllowUnassigned.  Returns 0 iff successful, or an error code.
 
419
 **/
 
420
 
 
421
/**
 
422
 * stringprep_iscsi:
 
423
 * @in: input/ouput array with string to prepare.
 
424
 * @maxlen: maximum length of input/output array.
 
425
 *
 
426
 * Prepare the input UTF-8 string according to the draft iSCSI
 
427
 * stringprep profile.  Returns 0 iff successful, or an error code.
 
428
 **/
 
429
 
 
430
/**
 
431
 * stringprep_kerberos5:
 
432
 * @in: input/ouput array with string to prepare.
 
433
 * @maxlen: maximum length of input/output array.
 
434
 *
 
435
 * Prepare the input UTF-8 string according to the draft Kerberos5
 
436
 * stringprep profile.  Returns 0 iff successful, or an error code.
 
437
 **/
 
438
 
 
439
/**
 
440
 * stringprep_plain:
 
441
 * @in: input/ouput array with string to prepare.
 
442
 * @maxlen: maximum length of input/output array.
 
443
 *
 
444
 * Prepare the input UTF-8 string according to the draft SASL
 
445
 * ANONYMOUS profile.  Returns 0 iff successful, or an error code.
 
446
 **/
 
447
 
 
448
/**
 
449
 * stringprep_xmpp_nodeprep:
 
450
 * @in: input/ouput array with string to prepare.
 
451
 * @maxlen: maximum length of input/output array.
 
452
 *
 
453
 * Prepare the input UTF-8 string according to the draft XMPP node
 
454
 * identifier profile.  Returns 0 iff successful, or an error code.
 
455
 **/
 
456
 
 
457
/**
 
458
 * stringprep_xmpp_resourceprep:
 
459
 * @in: input/ouput array with string to prepare.
 
460
 * @maxlen: maximum length of input/output array.
 
461
 *
 
462
 * Prepare the input UTF-8 string according to the draft XMPP resource
 
463
 * identifier profile.  Returns 0 iff successful, or an error code.
 
464
 **/
 
465
 
 
466
/**
 
467
 * stringprep_generic:
 
468
 * @in: input/ouput array with string to prepare.
 
469
 * @maxlen: maximum length of input/output array.
 
470
 *
 
471
 * Prepare the input UTF-8 string according to a hypotetical "generic"
 
472
 * stringprep profile. This is mostly used for debugging or when
 
473
 * constructing new stringprep profiles. Returns 0 iff successful, or
 
474
 * an error code.
 
475
 **/