1/* $Id */
2
3/* This file is based on the GLIB utf8 validation functions. The
4 * original license text follows. */
5
6/* gutf8.c - Operations on UTF-8 strings.
7 *
8 * Copyright (C) 1999 Tom Tromey
9 * Copyright (C) 2000 Red Hat, Inc.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
25 */
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30
31#include <stdlib.h>
32
33#include "utf8.h"
34
35#define UNICODE_VALID(Char)                   \
36    ((Char) < 0x110000 &&                     \
37     (((Char) & 0xFFFFF800) != 0xD800) &&     \
38     ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&  \
39     ((Char) & 0xFFFE) != 0xFFFE)
40
41
42#define CONTINUATION_CHAR                           \
43 do {                                     \
44  if ((*(const unsigned char *)p & 0xc0) != 0x80) /* 10xxxxxx */ \
45    goto error;                                     \
46  val <<= 6;                                        \
47  val |= (*(const unsigned char *)p) & 0x3f;                     \
48 } while(0)
49
50
51const char *
52avahi_utf8_valid (const char *str)
53
54{
55  unsigned val = 0;
56  unsigned min = 0;
57  const char *p;
58
59  for (p = str; *p; p++)
60    {
61      if (*(const unsigned char *)p < 128)
62	/* done */;
63      else
64	{
65	  const char *last;
66
67	  last = p;
68	  if ((*(const unsigned char *)p & 0xe0) == 0xc0) /* 110xxxxx */
69	    {
70	      if ( ((*(const unsigned char *)p & 0x1e) == 0))
71		goto error;
72	      p++;
73	      if ( ((*(const unsigned char *)p & 0xc0) != 0x80)) /* 10xxxxxx */
74		goto error;
75	    }
76	  else
77	    {
78	      if ((*(const unsigned char *)p & 0xf0) == 0xe0) /* 1110xxxx */
79		{
80		  min = (1 << 11);
81		  val = *(const unsigned char *)p & 0x0f;
82		  goto TWO_REMAINING;
83		}
84	      else if ((*(const unsigned char *)p & 0xf8) == 0xf0) /* 11110xxx */
85		{
86		  min = (1 << 16);
87		  val = *(const unsigned char *)p & 0x07;
88		}
89	      else
90		goto error;
91
92	      p++;
93	      CONTINUATION_CHAR;
94	    TWO_REMAINING:
95	      p++;
96	      CONTINUATION_CHAR;
97	      p++;
98	      CONTINUATION_CHAR;
99
100	      if ( (val < min))
101		goto error;
102
103	      if ( (!UNICODE_VALID(val)))
104		goto error;
105	    }
106
107	  continue;
108
109	error:
110	  return NULL;
111	}
112    }
113
114  return str;
115}
116