2 /// Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
4 /// Author: Alexander Gnauck AG-Software
6 /// This file is part of GNU Libidn.
8 /// This program is free software; you can redistribute it and/or
9 /// modify it under the terms of the GNU General Public License as
10 /// published by the Free Software Foundation; either version 2 of the
11 /// License, or (at your option) any later version.
13 /// This program is distributed in the hope that it will be useful,
14 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 /// General Public License for more details.
18 /// You should have received a copy of the GNU General Public License
19 /// along with this program; if not, write to the Free Software
20 /// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 namespace gnu
.inet
.encoding
28 /// <summary> This class offers static methods for preparing internationalized
29 /// strings. It supports the following stringprep profiles:
31 /// <li>RFC3491 nameprep
32 /// <li>RFC3920 XMPP nodeprep and resourceprep
34 /// Note that this implementation only supports 16-bit Unicode code
37 public class Stringprep
39 /// <summary> Preps a name according to the Stringprep profile defined in
40 /// RFC3491. Unassigned code points are not allowed.
43 /// <param name="input">the name to prep.
45 /// <returns> the prepped name.
46 /// @throws StringprepException If the name cannot be prepped with
48 /// @throws NullPointerException If the name is null.
51 public static System
.String
nameprep(System
.String input
)
53 return nameprep(input
, false);
56 /// <summary> Preps a name according to the Stringprep profile defined in
60 /// <param name="input">the name to prep.
62 /// <param name="allowUnassigned">true if the name may contain unassigned
65 /// <returns> the prepped name.
66 /// @throws StringprepException If the name cannot be prepped with
68 /// @throws NullPointerException If the name is null.
71 public static System
.String
nameprep(System
.String input
, bool allowUnassigned
)
75 throw new System
.NullReferenceException();
78 System
.Text
.StringBuilder s
= new System
.Text
.StringBuilder(input
);
80 if (!allowUnassigned
&& contains(s
, RFC3454
.A1
))
82 throw new StringprepException(StringprepException
.CONTAINS_UNASSIGNED
);
85 filter(s
, RFC3454
.B1
);
86 map(s
, RFC3454
.B2search
, RFC3454
.B2replace
);
88 s
= new System
.Text
.StringBuilder(NFKC
.normalizeNFKC(s
.ToString()));
89 // B.3 is only needed if NFKC is not used, right?
90 // map(s, RFC3454.B3search, RFC3454.B3replace);
92 if (contains(s
, RFC3454
.C12
) || contains(s
, RFC3454
.C22
) || contains(s
, RFC3454
.C3
) || contains(s
, RFC3454
.C4
) || contains(s
, RFC3454
.C5
) || contains(s
, RFC3454
.C6
) || contains(s
, RFC3454
.C7
) || contains(s
, RFC3454
.C8
))
94 // Table C.9 only contains code points > 0xFFFF which Java
96 throw new StringprepException(StringprepException
.CONTAINS_PROHIBITED
);
100 bool r
= contains(s
, RFC3454
.D1
);
101 bool l
= contains(s
, RFC3454
.D2
);
103 // RFC 3454, section 6, requirement 1: already handled above (table C.8)
105 // RFC 3454, section 6, requirement 2
108 throw new StringprepException(StringprepException
.BIDI_BOTHRAL
);
111 // RFC 3454, section 6, requirement 3
114 if (!contains(s
[0], RFC3454
.D1
) || !contains(s
[s
.Length
- 1], RFC3454
.D1
))
116 throw new StringprepException(StringprepException
.BIDI_LTRAL
);
124 * Characters prohibited by RFC3920 nodeprep that aren't defined as
125 * part of the RFC3454 tables.
127 private static char [] RFC3920_NODEPREP_PROHIBIT
= new char [] {
128 '\u0022', '\u0026', '\'', '\u002F',
129 '\u003A', '\u003C', '\u003E', '\u0040'
132 /// <summary> Preps a node name according to the Stringprep profile defined in
133 /// RFC3920. Unassigned code points are not allowed.
136 /// <param name="input">the node name to prep.
138 /// <returns> the prepped node name.
139 /// @throws StringprepException If the node name cannot be prepped
140 /// with this profile.
141 /// @throws NullPointerException If the node name is null.
144 public static System
.String
nodeprep(System
.String input
)
146 return nodeprep(input
, false);
149 /// <summary> Preps a node name according to the Stringprep profile defined in
153 /// <param name="input">the node name to prep.
155 /// <param name="allowUnassigned">true if the node name may contain
156 /// unassigned code points.
158 /// <returns> the prepped node name.
159 /// @throws StringprepException If the node name cannot be prepped
160 /// with this profile.
161 /// @throws NullPointerException If the node name is null.
164 public static System
.String
nodeprep(System
.String input
, bool allowUnassigned
)
168 throw new System
.NullReferenceException();
171 System
.Text
.StringBuilder s
= new System
.Text
.StringBuilder(input
);
173 if (!allowUnassigned
&& contains(s
, RFC3454
.A1
))
175 throw new StringprepException(StringprepException
.CONTAINS_UNASSIGNED
);
178 filter(s
, RFC3454
.B1
);
179 map(s
, RFC3454
.B2search
, RFC3454
.B2replace
);
181 s
= new System
.Text
.StringBuilder(NFKC
.normalizeNFKC(s
.ToString()));
183 if (contains(s
, RFC3454
.C11
) || contains(s
, RFC3454
.C12
) || contains(s
, RFC3454
.C21
) || contains(s
, RFC3454
.C22
) || contains(s
, RFC3454
.C3
) || contains(s
, RFC3454
.C4
) || contains(s
, RFC3454
.C5
) || contains(s
, RFC3454
.C6
) || contains(s
, RFC3454
.C7
) || contains(s
, RFC3454
.C8
) || contains(s
, RFC3920_NODEPREP_PROHIBIT
))
185 // Table C.9 only contains code points > 0xFFFF which Java
187 throw new StringprepException(StringprepException
.CONTAINS_PROHIBITED
);
191 bool r
= contains(s
, RFC3454
.D1
);
192 bool l
= contains(s
, RFC3454
.D2
);
194 // RFC 3454, section 6, requirement 1: already handled above (table C.8)
196 // RFC 3454, section 6, requirement 2
199 throw new StringprepException(StringprepException
.BIDI_BOTHRAL
);
202 // RFC 3454, section 6, requirement 3
205 if (!contains(s
[0], RFC3454
.D1
) || !contains(s
[s
.Length
- 1], RFC3454
.D1
))
207 throw new StringprepException(StringprepException
.BIDI_LTRAL
);
214 /// <summary> Preps a resource name according to the Stringprep profile defined
215 /// in RFC3920. Unassigned code points are not allowed.
218 /// <param name="input">the resource name to prep.
220 /// <returns> the prepped node name.
221 /// @throws StringprepException If the resource name cannot be prepped
222 /// with this profile.
223 /// @throws NullPointerException If the resource name is null.
226 public static System
.String
resourceprep(System
.String input
)
228 return resourceprep(input
, false);
231 /// <summary> Preps a resource name according to the Stringprep profile defined
235 /// <param name="input">the resource name to prep.
237 /// <param name="allowUnassigned">true if the resource name may contain
238 /// unassigned code points.
240 /// <returns> the prepped node name.
241 /// @throws StringprepException If the resource name cannot be prepped
242 /// with this profile.
243 /// @throws NullPointerException If the resource name is null.
246 public static System
.String
resourceprep(System
.String input
, bool allowUnassigned
)
250 throw new System
.NullReferenceException();
253 System
.Text
.StringBuilder s
= new System
.Text
.StringBuilder(input
);
255 if (!allowUnassigned
&& contains(s
, RFC3454
.A1
))
257 throw new StringprepException(StringprepException
.CONTAINS_UNASSIGNED
);
260 filter(s
, RFC3454
.B1
);
262 s
= new System
.Text
.StringBuilder(NFKC
.normalizeNFKC(s
.ToString()));
264 if (contains(s
, RFC3454
.C12
) || contains(s
, RFC3454
.C21
) || contains(s
, RFC3454
.C22
) || contains(s
, RFC3454
.C3
) || contains(s
, RFC3454
.C4
) || contains(s
, RFC3454
.C5
) || contains(s
, RFC3454
.C6
) || contains(s
, RFC3454
.C7
) || contains(s
, RFC3454
.C8
))
266 // Table C.9 only contains code points > 0xFFFF which Java
268 throw new StringprepException(StringprepException
.CONTAINS_PROHIBITED
);
272 bool r
= contains(s
, RFC3454
.D1
);
273 bool l
= contains(s
, RFC3454
.D2
);
275 // RFC 3454, section 6, requirement 1: already handled above (table C.8)
277 // RFC 3454, section 6, requirement 2
280 throw new StringprepException(StringprepException
.BIDI_BOTHRAL
);
283 // RFC 3454, section 6, requirement 3
286 if (!contains(s
[0], RFC3454
.D1
) || !contains(s
[s
.Length
- 1], RFC3454
.D1
))
288 throw new StringprepException(StringprepException
.BIDI_LTRAL
);
295 internal static bool contains(System
.Text
.StringBuilder s
, char[] p
)
297 for (int i
= 0; i
< p
.Length
; i
++)
300 for (int j
= 0; j
< s
.Length
; j
++)
311 internal static bool contains(System
.Text
.StringBuilder s
, char[][] p
)
313 for (int i
= 0; i
< p
.Length
; i
++)
319 for (int j
= 0; j
< s
.Length
; j
++)
327 else if (2 == r
.Length
)
331 for (int j
= 0; j
< s
.Length
; j
++)
333 if (f
<= s
[j
] && t
>= s
[j
])
343 internal static bool contains(char c
, char[][] p
)
345 for (int i
= 0; i
< p
.Length
; i
++)
355 else if (2 == r
.Length
)
359 if (f
<= c
&& t
>= c
)
368 internal static void filter(System
.Text
.StringBuilder s
, char[] f
)
370 for (int i
= 0; i
< f
.Length
; i
++)
390 internal static void filter(System
.Text
.StringBuilder s
, char[][] f
)
392 for (int i
= 0; i
< f
.Length
; i
++)
414 else if (2 == r
.Length
)
422 if (from <= s
[j
] && to
>= s
[j
])
436 internal static void map(System
.Text
.StringBuilder s
, char[] search
, System
.String
[] replace
)
438 for (int i
= 0; i
< search
.Length
; i
++)
449 if (null != replace
[i
])
451 s
.Insert(j
, replace
[i
]);
452 j
+= replace
[i
].Length
- 1;