/* Jaxe - Editeur XML en Java Copyright (C) 2006 Observatoire de Paris-Meudon Ce programme est un logiciel libre ; vous pouvez le redistribuer et/ou le modifier conformément aux dispositions de la Licence Publique Générale GNU, telle que publiée par la Free Software Foundation ; version 2 de la licence, ou encore (à votre choix) toute version ultérieure. Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de COMMERCIALISATION ou D'ADAPTATION A UN OBJET PARTICULIER. Pour plus de détail, voir la Licence Publique Générale GNU . Vous devez avoir reçu un exemplaire de la Licence Publique Générale GNU en même temps que ce programme ; si ce n'est pas le cas, écrivez à la Free Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, Etats-Unis. */ package jaxe; import jaxe.JaxeDocument; import java.math.BigInteger; import java.util.ArrayList; //jakarta-oro import org.apache.oro.text.regex.*; import org.apache.oro.text.awk.*; import org.w3c.dom.*; /** * Classe permettant de vérifier la validité d'un type simple (= simpleType dans les schémas XML) */ public class VerifTypeSimple { protected String baseType = null; protected ArrayList enumeration = null; // de String protected ArrayList patterns = null; // de String protected ArrayList restrictions = null; // de Restriction protected PatternCompiler compiler; protected PatternMatcher matcher; /** * Constructeur prenant en paramètre le document Jaxe et un élément "element" ou "attribute" du schéma */ public VerifTypeSimple(JaxeDocument doc, Element snodedef) { compiler = new AwkCompiler(); matcher = new AwkMatcher(); String stype = snodedef.getAttribute("type"); if (!"".equals(stype)) { String schemaPrefix = snodedef.getPrefix(); int indp = stype.indexOf(':'); if (indp == -1 && schemaPrefix == null || indp != -1 && stype.substring(0, indp).equals(schemaPrefix)) { baseType = stype.substring(indp+1); } else { String nomType; if (indp == -1) nomType = stype; else nomType = stype.substring(indp+1); Element eltype = doc.cfg.getSchemaTypeElement(nomType); if (eltype == null) System.err.println("typesimple: attention: pas de définition de " + nomType + " dans le schéma"); else lireTypeEtRestrictions(eltype); } } else { NodeList lsn = snodedef.getChildNodes(); for (int i=0; i&#!/?'\",0-9.\\-\\s]"); val = remplacer(val, "\\I", "[^a-zA-Z]"); val = remplacer(val, "\\c", "[^<>&#!/?'\",\\s]"); val = remplacer(val, "\\C", "\\W"); patterns.add(val); } else { String val = facet.getAttribute("value"); if (restrictions == null) restrictions = new ArrayList(); restrictions.add(new Restriction(facet.getLocalName(), val)); } } protected String remplacer(String s, String sremp, String spar) { int ind = s.indexOf(sremp); while (ind != -1) { s = s.substring(0, ind) + spar + s.substring(ind + sremp.length()); ind = s.indexOf(sremp); } return(s); } protected boolean verifType(String type, String valeur) { if ("string".equals(type)) return(true); else if ("normalizedString".equals(type)) return(verifExpr(valeur, "[^\\t\\r\\n]*")); else if ("token".equals(type)) { if (valeur.indexOf('\n') != -1 || valeur.indexOf('\r') != -1 || valeur.indexOf('\t') != -1 || valeur.indexOf(" ") != -1) return(false); return(!valeur.startsWith(" ") && !valeur.endsWith(" ")); } else if ("base64Binary".equals(type)) return(verifExpr(valeur, "(([a-zA-Z0-9+/=]\\s?){4})*")); else if ("hexBinary".equals(type)) return(verifExpr(valeur, "(([0-9a-fA-F]){2})*")); else if ("integer".equals(type)) return(verifExpr(valeur, "[+\\-]?\\d+")); else if ("positiveInteger".equals(type)) return(verifExpr(valeur, "\\+?0*[1-9]\\d*")); else if ("negativeInteger".equals(type)) return(verifExpr(valeur, "-0*[1-9]\\d*")); else if ("nonNegativeInteger".equals(type)) return(verifExpr(valeur, "(-0+)|(\\+?\\d+)")); else if ("nonPositiveInteger".equals(type)) return(verifExpr(valeur, "(\\+?0+)|(-\\d+)")); else if ("long".equals(type)) { if (!verifExpr(valeur, "[+\\-]?\\d+")) return(false); try { BigInteger big = new BigInteger(valeur); BigInteger max = new BigInteger("9223372036854775807"); BigInteger min = new BigInteger("-9223372036854775808"); if (big.compareTo(max) > 0) return(false); if (big.compareTo(min) < 0) return(false); return(true); } catch (NumberFormatException ex) { System.err.println("NumberFormatException: " + ex.getMessage()); return(false); } } else if ("unsignedLong".equals(type)) { if (!verifExpr(valeur, "\\d+")) return(false); try { BigInteger big = new BigInteger(valeur); BigInteger max = new BigInteger("18446744073709551615"); return(big.compareTo(max) <= 0); } catch (NumberFormatException ex) { System.err.println("NumberFormatException: " + ex.getMessage()); return(false); } } else if ("int".equals(type)) { if (!verifExpr(valeur, "[+\\-]?\\d+")) return(false); try { long val = (Long.valueOf(valeur)).longValue(); return(val <= 2147483647l && val >= -2147483648l); } catch (NumberFormatException ex) { System.err.println("NumberFormatException: " + ex.getMessage()); return(false); } } else if ("unsignedInt".equals(type)) { if (!verifExpr(valeur, "\\d+")) return(false); try { long val = (Long.valueOf(valeur)).longValue(); return(val <= 4294967295l && val >= 0); } catch (NumberFormatException ex) { System.err.println("NumberFormatException: " + ex.getMessage()); return(false); } } else if ("short".equals(type)) { if (!verifExpr(valeur, "[+\\-]?\\d+")) return(false); try { int val = (Integer.valueOf(valeur)).intValue(); return(val <= 32767 && val >= -32768); } catch (NumberFormatException ex) { System.err.println("NumberFormatException: " + ex.getMessage()); return(false); } } else if ("unsignedShort".equals(type)) { if (!verifExpr(valeur, "\\d+")) return(false); try { int val = (Integer.valueOf(valeur)).intValue(); return(val <= 65535 && val >= 0); } catch (NumberFormatException ex) { System.err.println("NumberFormatException: " + ex.getMessage()); return(false); } } else if ("byte".equals(type)) { if (!verifExpr(valeur, "[+\\-]?\\d+")) return(false); try { int val = (Integer.valueOf(valeur)).intValue(); return(val <= 127 && val >= -128); } catch (NumberFormatException ex) { System.err.println("NumberFormatException: " + ex.getMessage()); return(false); } } else if ("unsignedByte".equals(type)) { if (!verifExpr(valeur, "\\d+")) return(false); try { int val = (Integer.valueOf(valeur)).intValue(); return(val <= 255 && val >= 0); } catch (NumberFormatException ex) { System.err.println("NumberFormatException: " + ex.getMessage()); return(false); } } else if ("decimal".equals(type)) { return(verifExpr(valeur, "[+\\-]?\\d+\\.?\\d*")); } else if ("float".equals(type)) { if (!verifExpr(valeur, "(-?INF)|(NaN)|([+\\-]?\\d+\\.?\\d*[eE]?[+\\-]?\\d{1,3})")) return(false); if ("INF".equals(valeur) || "-INF".equals(valeur)) // "Infinity" en Java return(true); try { Float val = Float.valueOf(valeur); return(true); } catch (NumberFormatException ex) { return(false); } } else if ("double".equals(type)) { if (!verifExpr(valeur, "(-?INF)|(NaN)|([+\\-]?\\d+\\.?\\d*[eE]?[+\\-]?\\d{1,3})")) return(false); if ("INF".equals(valeur) || "-INF".equals(valeur)) return(true); try { Double val = Double.valueOf(valeur); return(true); } catch (NumberFormatException ex) { return(false); } } else if ("boolean".equals(type)) return(verifExpr(valeur, "(true)|(false)|1|0")); else if ("duration".equals(type)) return(verifExpr(valeur, "-?P(\\d{1,4}Y)?(\\d{1,2}M)?(\\d{1,2}D)?T?(\\d{1,2}H)?(\\d{1,2}M)?(\\d{1,2}(\\.\\d+)?S)?")); else if ("dateTime".equals(type)) return(verifExpr(valeur, "-?\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d(\\.\\d+)?(([+\\-][01]\\d:\\d{2})|Z)?")); else if ("date".equals(type)) return(verifExpr(valeur, "-?\\d{4}-[01]\\d-[0-3]\\d(([+\\-][01]\\d:\\d{2})|Z)?")); else if ("time".equals(type)) return(verifExpr(valeur, "[0-2]\\d:[0-5]\\d:[0-5]\\d(\\.\\d+)?(([+\\-][01]\\d:\\d{2})|Z)?")); else if ("gYear".equals(type)) return(verifExpr(valeur, "-?\\d{4}(([+\\-][01]\\d:\\d{2})|Z)?")); else if ("gYearMonth".equals(type)) return(verifExpr(valeur, "-?\\d{4}-[01]\\d(([+\\-][01]\\d:\\d{2})|Z)?")); else if ("gMonth".equals(type)) return(verifExpr(valeur, "--[01]\\d(([+\\-][01]\\d:\\d{2})|Z)?")); else if ("gMonthDay".equals(type)) return(verifExpr(valeur, "--[01]\\d-[0-3]\\d(([+\\-][01]\\d:\\d{2})|Z)?")); else if ("gDay".equals(type)) return(verifExpr(valeur, "---[0-3]\\d(([+\\-][01]\\d:\\d{2})|Z)?")); else if ("Name".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",0-9.\\-\\s][^<>&#!/?'\",\\s]*")); // en fait plus restrictif: \i\c* else if ("QName".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",0-9.\\-\\s][^<>&#!/?'\",\\s]*")); // en fait plus restrictif else if ("NCName".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",0-9.\\-\\s:][^<>&#!/?'\",:\\s]*")); // en fait plus restrictif: [\i-[:]][\c-[:]]* else if ("anyURI".equals(type)) return(true); //return(verifExpr(valeur, "([^:/?#]+:)?(//[^/?#]*)?[^?#]*(\\?[^#]*)?(#.*)?")); // pb: cette expression autorise tout! // (mais les RFC 2396 et 2732 ne restreignent rien) else if ("language".equals(type)) return(verifExpr(valeur, "[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*")); else if ("ID".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",0-9.\\-\\s:][^<>&#!/?'\",:\\s]*")); // comme NCName else if ("IDREF".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",0-9.\\-\\s:][^<>&#!/?'\",:\\s]*")); // comme NCName else if ("IDREFS".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",0-9.\\-\\s:][^<>&#!/?'\",:]*")); else if ("ENTITY".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",0-9.\\-\\s:][^<>&#!/?'\",:\\s]*")); // comme NCName else if ("ENTITIES".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",0-9.\\-\\s:][^<>&#!/?'\",:]*")); // comme IDREFS else if ("NOTATION".equals(type)) return(verifExpr(valeur, "[^0-9.\\-\\s][^\\s]*(\\s[^0-9.\\-\\s][^\\s]*)*")); // la facette enumeration est obligatoire -> contrainte supplémentaire else if ("NMTOKEN".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",\\s]+")); // en fait plus restrictif: \c+ else if ("NMTOKENS".equals(type)) return(verifExpr(valeur, "[^<>&#!/?'\",]+")); // en fait plus restrictif else return(true); } protected boolean verifExpr(String valeur, String regexp) { try { Pattern r = compiler.compile("^" + regexp + "$"); // on pourrait utiliser un cache, comme dans Config return(matcher.matches(valeur, r)); } catch (MalformedPatternException ex) { System.err.println("MalformedPatternException: " + ex.getMessage()); System.err.println(regexp); return(true); } } class Restriction { private String nom; private String param; private int iparam; public Restriction(String nom, String param) { this.nom = nom; this.param = param; try { this.iparam = (Integer.valueOf(param)).intValue(); } catch (NumberFormatException ex) { } } public boolean valide(String valeur) { if ("length".equals(nom)) return(valeur.length() == iparam); else if ("minLength".equals(nom)) return(valeur.length() >= iparam); else if ("maxLength".equals(nom)) return(valeur.length() <= iparam); else if ("maxInclusive".equals(nom)) { try { int val = (Integer.valueOf(valeur)).intValue(); return(val <= iparam); } catch (NumberFormatException ex) { return(false); } } else if ("maxExclusive".equals(nom)) { try { int val = (Integer.valueOf(valeur)).intValue(); return(val < iparam); } catch (NumberFormatException ex) { return(false); } } else if ("minInclusive".equals(nom)) { try { int val = (Integer.valueOf(valeur)).intValue(); return(val >= iparam); } catch (NumberFormatException ex) { return(false); } } else if ("minExclusive".equals(nom)) { try { int val = (Integer.valueOf(valeur)).intValue(); return(val > iparam); } catch (NumberFormatException ex) { return(false); } } else if ("whiteSpace".equals(nom)) { if ("collapse".equals(param)) return(!"replace".equals(valeur) && !"preserve".equals(valeur)); else if ("replace".equals(param)) return(!"preserve".equals(valeur)); else return(true); } else if ("totalDigits".equals(nom)) { int nb = 0; for (int i=0; i= '0' && valeur.charAt(i) <= '9') nb++; return(nb <= iparam); } else if ("fractionDigits".equals(nom)) { int nb = 0; boolean apres = false; for (int i=0; i= '0' && valeur.charAt(i) <= '9') nb++; } return(nb <= iparam); } else return(true); } } }