Package nu.validator.xml

Source Code of nu.validator.xml.BaseUriTracker$Node

/*
* Copyright (c) 2008 Mozilla Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

package nu.validator.xml;

import java.net.URI;
import java.util.LinkedList;

import org.relaxng.datatype.DatatypeException;
import org.whattf.datatype.Language;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

import com.hp.hpl.jena.iri.IRI;
import com.hp.hpl.jena.iri.IRIFactory;

public class BaseUriTracker implements ContentHandler, UriLangContext {

    private enum Direction {
        LTR, RTL, INHERIT
    }

    private class Node {
        public URI currentAbsolute; // not null

        public String originalRelative; // null if no xml:base

        public String lang; // null if no xml:lang

        private boolean langSpeficied;

        private boolean rtl;

        /**
         * @param currentAbsolute
         * @param originalRelative
         */
        public Node(URI currentAbsolute, String originalRelative, String lang,
                boolean langSpecified, boolean rtl) {
            this.currentAbsolute = currentAbsolute;
            this.originalRelative = originalRelative;
            this.lang = lang;
            this.langSpeficied = langSpecified;
            this.rtl = rtl;
        }
    }

    private LinkedList<Node> stack = new LinkedList<Node>();

    private final IRIFactory iriFactory;

    private boolean baseSeen = false;

    private boolean contentLanguageSeen = false;

    /**
     * -1 at start
     * 0 in html
     * >=1 in head
     * -2 situation over
     */
    private int inHeadDepth = -1;

    private int inCruftDepth = 0;

    private boolean equalsIgnoreAsciiCase(CharSequence one, CharSequence other) {
        if (other == null && one == null) {
            return true;
        }
        if (other == null || one == null) {
            return false;
        }
        if (one.length() != other.length()) {
            return false;
        }
        for (int i = 0; i < other.length(); i++) {
            char c0 = one.charAt(i);
            if (c0 >= 'A' && c0 <= 'Z') {
                c0 += 0x20;
            }
            char c1 = other.charAt(i);
            if (c1 >= 'A' && c1 <= 'Z') {
                c1 += 0x20;
            }
            if (c0 != c1) {
                return false;
            }
        }
        return true;
    }

    public BaseUriTracker(String systemId, String contentLanguage) {
        this.iriFactory = new IRIFactory();
        this.iriFactory.shouldViolation(false, false);
        this.iriFactory.securityViolation(false, false);
        this.iriFactory.dnsViolation(false, false);
        this.iriFactory.mintingViolation(false, false);
        this.iriFactory.useSpecificationIRI(false);
        this.iriFactory.useSchemeSpecificRules("http", false);
        this.iriFactory.useSchemeSpecificRules("https", false);
        this.iriFactory.useSchemeSpecificRules("ftp", false);
        this.iriFactory.useSchemeSpecificRules("data", false);

        URI uri = null;
        try {
            IRI iri = iriFactory.construct(systemId);
            uri = new URI(iri.toASCIIString());
            if (!uri.isAbsolute()) {
                uri = null;
            }
        } catch (Exception e) {
            uri = null;
        }

        String lang = "";
        boolean langSpecified = false;
        if (contentLanguage != null) {
            try {
                if (!"".equals(contentLanguage)) {
                    Language.THE_INSTANCE.checkValid(contentLanguage);
                }
                lang = contentLanguage;
                langSpecified = true;
            } catch (DatatypeException e) {
            }
        }
        stack.add(new Node(uri, null, lang, langSpecified, false));
        stack.add(new Node(uri, null, lang, false, false)); // base/content-language placeholder       
    }

    private Node peek() {
        return stack.getLast();
    }

    private void pop() {
        stack.removeLast();
    }

    private void push(String relative, String language, Direction dir) {
        String lang = "";
        boolean langSpecified = false;
        if (language != null) {
            try {
                if (!"".equals(language)) {
                    Language.THE_INSTANCE.checkValid(language);
                }
                lang = language;
                langSpecified = true;
            } catch (DatatypeException e) {
            }
        }

        Node curr = peek();
        URI base = curr.currentAbsolute;
        if (!langSpecified) {
            lang = curr.lang;
        }
        boolean rtl;
        switch (dir) {
            case RTL:
                rtl = true;
                break;
            case LTR:
                rtl = false;
                break;
            default:
                rtl = curr.rtl;
                break;
        }

        if (relative == null) {
            stack.addLast(new Node(base, null, lang, langSpecified, rtl));
        } else {
            URI newBase;
            String ascii = null;
            try {
                IRI relIri = iriFactory.construct(relative);
                ascii = relIri.toASCIIString();
                if (base != null) {
                    newBase = base.resolve(ascii);
                    if (!newBase.isAbsolute()) {
                        newBase = base;
                    }
                } else {
                    newBase = new URI(ascii);
                    if (!newBase.isAbsolute()) {
                        newBase = null;
                    }
                }
            } catch (Exception e) {
                newBase = base;
            }
            stack.addLast(new Node(newBase, ascii, lang, langSpecified, rtl));
        }
    }

    private void installBase(String href) {
        if (baseSeen) {
            return;
        }
        baseSeen = true;

        LinkedList<Node> oldStack = stack;
        stack = new LinkedList<Node>();
        int i = 0;
        for (Node node : oldStack) {
            if (i == 0) {
                stack.addLast(node); // root
            } else if (i == 1) {
                push(href, node.langSpeficied ? node.lang : null,
                        node.rtl ? Direction.RTL : Direction.LTR);
            } else {
                push(node.originalRelative, node.langSpeficied ? node.lang
                        : null, node.rtl ? Direction.RTL : Direction.LTR);
            }
            i++;
        }
    }

    private void installContentLanguage(String language) {
        if (contentLanguageSeen) {
            return;
        }
        contentLanguageSeen = true;

        String lang = "";
        boolean langSpecified = false;
        if (language != null) {
            try {
                if (!"".equals(language)) {
                    Language.THE_INSTANCE.checkValid(language);
                }
                lang = language;
                langSpecified = true;
            } catch (DatatypeException e) {
            }
        }
        if (!langSpecified) {
            return;
        }

        int i = 0;
        for (Node node : stack) {
            if (i == 0) {
                // nop
            } else if (i == 1) {
                node.lang = lang;
                node.langSpeficied = true; // probably unnecessary...
            } else {
                if (node.langSpeficied) {
                    return;
                } else {
                    node.lang = lang;
                }
            }
            i++;
        }
    }

    /**
     * @see nu.validator.xml.UriLangContext#currentLanguage()
     */
    public String currentLanguage() {
        return stack.getLast().lang;
    }

    /**
     * @see nu.validator.xml.UriLangContext#isCurrentRtl()
     */
    public boolean isCurrentRtl() {
        return stack.getLast().rtl;
    }
   
    /**
     * @see nu.validator.xml.UriLangContext#toAbsoluteUriWithCurrentBase(java.lang.String)
     */
    public String toAbsoluteUriWithCurrentBase(String uri) {
        try {
            IRI relIri = iriFactory.construct(uri);
            String ascii;
            ascii = relIri.toASCIIString();

            URI base = stack.getLast().currentAbsolute;
            URI rv;
            if (base == null) {
                rv = new URI(ascii);
            } else {
                rv = base.resolve(ascii);

            }
            if (rv.isAbsolute()) {
                return rv.toASCIIString();
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }

    public void characters(char[] ch, int start, int length)
            throws SAXException {
    }

    public void endDocument() throws SAXException {
    }

    public void endElement(String uri, String localName, String name)
            throws SAXException {
        if (inHeadDepth > 0) {
            inHeadDepth--;
            if (inHeadDepth == 0) {
                inHeadDepth = -2;
            }
        }
        if (inCruftDepth > 0) {
            inCruftDepth--;
        }
        pop();
    }

    public void endPrefixMapping(String prefix) throws SAXException {
    }

    public void ignorableWhitespace(char[] ch, int start, int length)
            throws SAXException {
    }

    public void processingInstruction(String target, String data)
            throws SAXException {
    }

    public void setDocumentLocator(Locator locator) {
    }

    public void skippedEntity(String name) throws SAXException {
    }

    public void startDocument() throws SAXException {
        inHeadDepth = -1;
        inCruftDepth = 0;
    }

    public void startElement(String uri, String localName, String n,
            Attributes atts) throws SAXException {
        if (inHeadDepth >= 1) {
            inHeadDepth++;
            if ("http://www.w3.org/1999/xhtml" == uri) {
                if ("base" == localName) {
                    String href = atts.getValue("", "href");
                    if (href != null) {
                        installBase(href);
                    }
                } else if ("meta" == localName) {
                    String httpEquiv = atts.getValue("", "http-equiv");
                    if (equalsIgnoreAsciiCase("content-language", httpEquiv)) {
                        String content = atts.getValue("", "content");
                        if (content == null) {
                            content = "";
                        }
                        installContentLanguage(content);
                    }
                }
            }
        } else if (inHeadDepth == -1) {
            if ("html" == localName && "http://www.w3.org/1999/xhtml" == uri) {
                inHeadDepth = 0;
            } else {
                inHeadDepth = -2;
            }
        } else if (inHeadDepth == 0 && inCruftDepth == 0) {
            if ("head" == localName && "http://www.w3.org/1999/xhtml" == uri) {
                inHeadDepth = 1;
            } else {
                inCruftDepth = 1;
            }
        }

        String base = null;
        String lang = null;
        Direction dir = Direction.INHERIT;
        int len = atts.getLength();
        for (int i = 0; i < len; i++) {
            String ns = atts.getURI(i);
            if ("http://www.w3.org/XML/1998/namespace" == ns) {
                String name = atts.getLocalName(i);
                if ("lang" == name) {
                    lang = atts.getValue(i);
                } else if ("base" == name) {
                    base = atts.getValue(i);
                }
            } else if ("" == ns) {
                String name = atts.getLocalName(i);
                if (("dir" == name && "http://www.w3.org/1999/xhtml" == uri)
                        || ("direction" == name && "http://www.w3.org/2000/svg" == uri)) {
                    String value = atts.getValue(i);
                    if (equalsIgnoreAsciiCase("ltr", value)) {
                        dir = Direction.LTR;
                    } else if (equalsIgnoreAsciiCase("rtl", value)) {
                        dir = Direction.RTL;
                    }
                }
            }
        }
        push(base, lang, dir);
    }

    public void startPrefixMapping(String prefix, String uri)
            throws SAXException {
    }
}
TOP

Related Classes of nu.validator.xml.BaseUriTracker$Node

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.