@@ -49,24 +49,6 @@ private record FormatCheck(Predicate<String> isValid, String message) {}
4949
5050 private static final Pattern EMAIL = Pattern .compile ("^[^\\ s@]+@[^\\ s@]+\\ .[^\\ s@]+$" );
5151
52- private static final Pattern IPV4 =
53- Pattern .compile (
54- "^((25[0-5]|2[0-4]\\ d|1\\ d{2}|[1-9]\\ d|\\ d)\\ .){3}(25[0-5]|2[0-4]\\ d|1\\ d{2}|[1-9]\\ d|\\ d)$" );
55-
56- private static final Pattern IPV6 =
57- Pattern .compile (
58- "^("
59- + "([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}"
60- + "|([0-9a-fA-F]{1,4}:){1,7}:"
61- + "|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}"
62- + "|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}"
63- + "|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}"
64- + "|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}"
65- + "|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}"
66- + "|[0-9a-fA-F]{1,4}:(:[0-9a-fA-F]{1,4}){1,6}"
67- + "|:((:[0-9a-fA-F]{1,4}){1,7}|:)"
68- + ")$" );
69-
7052 private static final Pattern HOSTNAME =
7153 Pattern .compile (
7254 "^(?=.{1,253}$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?"
@@ -86,8 +68,8 @@ private record FormatCheck(Predicate<String> isValid, String message) {}
8668 Map .entry (
8769 "hostname" ,
8870 new FormatCheck (s -> HOSTNAME .matcher (s ).matches (), "not a valid hostname" )),
89- Map .entry ("ipv4" , new FormatCheck (s -> IPV4 . matcher ( s ). matches () , "not a valid ipv4" )),
90- Map .entry ("ipv6" , new FormatCheck (s -> IPV6 . matcher ( s ). matches () , "not a valid ipv6" )),
71+ Map .entry ("ipv4" , new FormatCheck (DefaultValidator :: isIpv4 , "not a valid ipv4" )),
72+ Map .entry ("ipv6" , new FormatCheck (DefaultValidator :: isIpv6 , "not a valid ipv6" )),
9173 Map .entry ("regex" , new FormatCheck (DefaultValidator ::isRegex , "not a valid regex" )),
9274 Map .entry ("byte" , new FormatCheck (DefaultValidator ::isByte , "not valid base64" )),
9375 Map .entry ("binary" , new FormatCheck (s -> true , "not valid binary" )),
@@ -234,6 +216,86 @@ private static boolean isUriReference(String s) {
234216 }
235217 }
236218
219+ private static boolean isIpv4 (String s ) {
220+ String [] parts = s .split ("\\ ." , -1 );
221+ if (parts .length != 4 ) {
222+ return false ;
223+ }
224+ for (String part : parts ) {
225+ if (!isIpv4Octet (part )) {
226+ return false ;
227+ }
228+ }
229+ return true ;
230+ }
231+
232+ private static boolean isIpv4Octet (String part ) {
233+ int len = part .length ();
234+ if (len == 0 || len > 3 ) {
235+ return false ;
236+ }
237+ if (len > 1 && part .charAt (0 ) == '0' ) {
238+ return false ;
239+ }
240+ int n = 0 ;
241+ for (int i = 0 ; i < len ; i ++) {
242+ char c = part .charAt (i );
243+ if (c < '0' || c > '9' ) {
244+ return false ;
245+ }
246+ n = n * 10 + (c - '0' );
247+ }
248+ return n <= 255 ;
249+ }
250+
251+ private static boolean isIpv6 (String s ) {
252+ int doubleColon = s .indexOf ("::" );
253+ if (doubleColon != s .lastIndexOf ("::" )) {
254+ return false ;
255+ }
256+ boolean compressed = doubleColon >= 0 ;
257+ String [] left ;
258+ String [] right ;
259+ if (compressed ) {
260+ String l = s .substring (0 , doubleColon );
261+ String r = s .substring (doubleColon + 2 );
262+ left = l .isEmpty () ? new String [0 ] : l .split (":" , -1 );
263+ right = r .isEmpty () ? new String [0 ] : r .split (":" , -1 );
264+ } else {
265+ left = s .split (":" , -1 );
266+ right = new String [0 ];
267+ }
268+ int total = left .length + right .length ;
269+ if (compressed ? total > 7 : total != 8 ) {
270+ return false ;
271+ }
272+ return allHextets (left ) && allHextets (right );
273+ }
274+
275+ private static boolean allHextets (String [] parts ) {
276+ for (String hextet : parts ) {
277+ if (!isHextet (hextet )) {
278+ return false ;
279+ }
280+ }
281+ return true ;
282+ }
283+
284+ private static boolean isHextet (String hextet ) {
285+ int len = hextet .length ();
286+ if (len == 0 || len > 4 ) {
287+ return false ;
288+ }
289+ for (int i = 0 ; i < len ; i ++) {
290+ char c = hextet .charAt (i );
291+ boolean hex = (c >= '0' && c <= '9' ) || (c >= 'a' && c <= 'f' ) || (c >= 'A' && c <= 'F' );
292+ if (!hex ) {
293+ return false ;
294+ }
295+ }
296+ return true ;
297+ }
298+
237299 private void validateInteger (Object value , IntegerSchema s , String pointer ) {
238300 long n ;
239301 switch (value ) {
0 commit comments