1 /// <summary> Copyright (C) 2004 Free Software Foundation, Inc.
3 /// Author: Alexander Gnauck AG-Software
5 /// This file is part of GNU Libidn.
7 /// This library is free software; you can redistribute it and/or
8 /// modify it under the terms of the GNU Lesser General Public License
9 /// as published by the Free Software Foundation; either version 2.1 of
10 /// the License, or (at your option) any later version.
12 /// This library is distributed in the hope that it will be useful, but
13 /// WITHOUT ANY WARRANTY; without even the implied warranty of
14 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 /// Lesser General Public License for more details.
17 /// You should have received a copy of the GNU Lesser General Public
18 /// License along with this library; if not, write to the Free Software
19 /// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
25 namespace gnu
.inet
.encoding
27 /// <summary> This class offers static methods for preparing internationalized
28 /// strings. It supports the following stringprep profiles:
30 /// <li>RFC3491 nameprep
31 /// <li>RFC3920 XMPP nodeprep and resourceprep
33 /// Note that this implementation only supports 16-bit Unicode code
36 public class Stringprep
38 /// <summary> Preps a name according to the Stringprep profile defined in
39 /// RFC3491. Unassigned code points are not allowed.
42 /// <param name="input">the name to prep.
44 /// <returns> the prepped name.
45 /// @throws StringprepException If the name cannot be prepped with
47 /// @throws NullPointerException If the name is null.
50 public static System
.String
nameprep(System
.String input
)
52 return nameprep(input
, false);
55 /// <summary> Preps a name according to the Stringprep profile defined in
59 /// <param name="input">the name to prep.
61 /// <param name="allowUnassigned">true if the name may contain unassigned
64 /// <returns> the prepped name.
65 /// @throws StringprepException If the name cannot be prepped with
67 /// @throws NullPointerException If the name is null.
70 public static System
.String
nameprep(System
.String input
, bool allowUnassigned
)
74 throw new System
.NullReferenceException();
77 System
.Text
.StringBuilder s
= new System
.Text
.StringBuilder(input
);
79 if (!allowUnassigned
&& contains(s
, RFC3454
.A1
))
81 throw new StringprepException(StringprepException
.CONTAINS_UNASSIGNED
);
84 filter(s
, RFC3454
.B1
);
85 map(s
, RFC3454
.B2search
, RFC3454
.B2replace
);
87 s
= new System
.Text
.StringBuilder(NFKC
.normalizeNFKC(s
.ToString()));
88 // B.3 is only needed if NFKC is not used, right?
89 // map(s, RFC3454.B3search, RFC3454.B3replace);
91 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
))
93 // Table C.9 only contains code points > 0xFFFF which Java
95 throw new StringprepException(StringprepException
.CONTAINS_PROHIBITED
);
99 bool r
= contains(s
, RFC3454
.D1
);
100 bool l
= contains(s
, RFC3454
.D2
);
102 // RFC 3454, section 6, requirement 1: already handled above (table C.8)
104 // RFC 3454, section 6, requirement 2
107 throw new StringprepException(StringprepException
.BIDI_BOTHRAL
);
110 // RFC 3454, section 6, requirement 3
113 if (!contains(s
[0], RFC3454
.D1
) || !contains(s
[s
.Length
- 1], RFC3454
.D1
))
115 throw new StringprepException(StringprepException
.BIDI_LTRAL
);
123 * Characters prohibited by RFC3920 nodeprep that aren't defined as
124 * part of the RFC3454 tables.
126 private static char [] RFC3920_NODEPREP_PROHIBIT
= new char [] {
127 '\u0022', '\u0026', '\'', '\u002F',
128 '\u003A', '\u003C', '\u003E', '\u0040'
131 /// <summary> Preps a node name according to the Stringprep profile defined in
132 /// RFC3920. Unassigned code points are not allowed.
135 /// <param name="input">the node name to prep.
137 /// <returns> the prepped node name.
138 /// @throws StringprepException If the node name cannot be prepped
139 /// with this profile.
140 /// @throws NullPointerException If the node name is null.
143 public static System
.String
nodeprep(System
.String input
)
145 return nodeprep(input
, false);
148 /// <summary> Preps a node name according to the Stringprep profile defined in
152 /// <param name="input">the node name to prep.
154 /// <param name="allowUnassigned">true if the node name may contain
155 /// unassigned code points.
157 /// <returns> the prepped node name.
158 /// @throws StringprepException If the node name cannot be prepped
159 /// with this profile.
160 /// @throws NullPointerException If the node name is null.
163 public static System
.String
nodeprep(System
.String input
, bool allowUnassigned
)
167 throw new System
.NullReferenceException();
170 System
.Text
.StringBuilder s
= new System
.Text
.StringBuilder(input
);
172 if (!allowUnassigned
&& contains(s
, RFC3454
.A1
))
174 throw new StringprepException(StringprepException
.CONTAINS_UNASSIGNED
);
177 filter(s
, RFC3454
.B1
);
178 map(s
, RFC3454
.B2search
, RFC3454
.B2replace
);
180 s
= new System
.Text
.StringBuilder(NFKC
.normalizeNFKC(s
.ToString()));
182 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
))
184 // Table C.9 only contains code points > 0xFFFF which Java
186 throw new StringprepException(StringprepException
.CONTAINS_PROHIBITED
);
190 bool r
= contains(s
, RFC3454
.D1
);
191 bool l
= contains(s
, RFC3454
.D2
);
193 // RFC 3454, section 6, requirement 1: already handled above (table C.8)
195 // RFC 3454, section 6, requirement 2
198 throw new StringprepException(StringprepException
.BIDI_BOTHRAL
);
201 // RFC 3454, section 6, requirement 3
204 if (!contains(s
[0], RFC3454
.D1
) || !contains(s
[s
.Length
- 1], RFC3454
.D1
))
206 throw new StringprepException(StringprepException
.BIDI_LTRAL
);
213 /// <summary> Preps a resource name according to the Stringprep profile defined
214 /// in RFC3920. Unassigned code points are not allowed.
217 /// <param name="input">the resource name to prep.
219 /// <returns> the prepped node name.
220 /// @throws StringprepException If the resource name cannot be prepped
221 /// with this profile.
222 /// @throws NullPointerException If the resource name is null.
225 public static System
.String
resourceprep(System
.String input
)
227 return resourceprep(input
, false);
230 /// <summary> Preps a resource name according to the Stringprep profile defined
234 /// <param name="input">the resource name to prep.
236 /// <param name="allowUnassigned">true if the resource name may contain
237 /// unassigned code points.
239 /// <returns> the prepped node name.
240 /// @throws StringprepException If the resource name cannot be prepped
241 /// with this profile.
242 /// @throws NullPointerException If the resource name is null.
245 public static System
.String
resourceprep(System
.String input
, bool allowUnassigned
)
249 throw new System
.NullReferenceException();
252 System
.Text
.StringBuilder s
= new System
.Text
.StringBuilder(input
);
254 if (!allowUnassigned
&& contains(s
, RFC3454
.A1
))
256 throw new StringprepException(StringprepException
.CONTAINS_UNASSIGNED
);
259 filter(s
, RFC3454
.B1
);
261 s
= new System
.Text
.StringBuilder(NFKC
.normalizeNFKC(s
.ToString()));
263 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
))
265 // Table C.9 only contains code points > 0xFFFF which Java
267 throw new StringprepException(StringprepException
.CONTAINS_PROHIBITED
);
271 bool r
= contains(s
, RFC3454
.D1
);
272 bool l
= contains(s
, RFC3454
.D2
);
274 // RFC 3454, section 6, requirement 1: already handled above (table C.8)
276 // RFC 3454, section 6, requirement 2
279 throw new StringprepException(StringprepException
.BIDI_BOTHRAL
);
282 // RFC 3454, section 6, requirement 3
285 if (!contains(s
[0], RFC3454
.D1
) || !contains(s
[s
.Length
- 1], RFC3454
.D1
))
287 throw new StringprepException(StringprepException
.BIDI_LTRAL
);
294 internal static bool contains(System
.Text
.StringBuilder s
, char[] p
)
296 for (int i
= 0; i
< p
.Length
; i
++)
299 for (int j
= 0; j
< s
.Length
; j
++)
310 internal static bool contains(System
.Text
.StringBuilder s
, char[][] p
)
312 for (int i
= 0; i
< p
.Length
; i
++)
318 for (int j
= 0; j
< s
.Length
; j
++)
326 else if (2 == r
.Length
)
330 for (int j
= 0; j
< s
.Length
; j
++)
332 if (f
<= s
[j
] && t
>= s
[j
])
342 internal static bool contains(char c
, char[][] p
)
344 for (int i
= 0; i
< p
.Length
; i
++)
354 else if (2 == r
.Length
)
358 if (f
<= c
&& t
>= c
)
367 internal static void filter(System
.Text
.StringBuilder s
, char[] f
)
369 for (int i
= 0; i
< f
.Length
; i
++)
389 internal static void filter(System
.Text
.StringBuilder s
, char[][] f
)
391 for (int i
= 0; i
< f
.Length
; i
++)
413 else if (2 == r
.Length
)
421 if (from <= s
[j
] && to
>= s
[j
])
435 internal static void map(System
.Text
.StringBuilder s
, char[] search
, System
.String
[] replace
)
437 for (int i
= 0; i
< search
.Length
; i
++)
448 if (null != replace
[i
])
450 s
.Insert(j
, replace
[i
]);
451 j
+= replace
[i
].Length
- 1;