All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.admin.rest.readers.XmlInputReader Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2009-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
// Portions Copyright [2019] Payara Foundation and/or affiliates

package org.glassfish.admin.rest.readers;

import java.io.Reader;


/**
 * @author Rajeshwar Patil
 */
public class XmlInputReader extends InputReader {

    /**
     * Construct a XmlInputReader from a string.
     * @param reader     A reader.
     */
    public XmlInputReader(Reader reader) {
        super(reader);
    }


    /**
     * Construct a InputReader from a string.
     * @param s     A source string.
     */
    public XmlInputReader(String s) {
        super(s);
    }


    /**
     * Get the text in the CDATA block.
     * @return The string up to the ]]>.
     * @throws InputException If the ]]> is not found.
     */
    public String nextCDATA() throws InputException {
        char         c;
        int          i;
        StringBuilder sb = new StringBuilder();
        for (;;) {
            c = next();
            if (c == 0) {
                throw error("Unclosed CDATA");
            }
            sb.append(c);
            i = sb.length() - 3;
            if (i >= 0 && sb.charAt(i) == ']' &&
                          sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
                sb.setLength(i);
                return sb.toString();
            }
        }
    }


    /**
     * Get the next XML outer token, trimming whitespace. There are two kinds
     * of tokens: the '<' character which begins a markup tag, and the content
     * text between markup tags.
     *
     * @return  A string, or a '<' Character, or null if there is no more
     * source text.
     * @throws InputException
     */
    public Object nextContent() throws InputException {
        char         c;
        StringBuilder sb;
        do {
            c = next();
        } while (Character.isWhitespace(c));
        if (c == 0) {
            return null;
        }
        if (c == '<') {
            return XmlInputObject.LT;
        }
        sb = new StringBuilder();
        for (;;) {
            if (c == '<' || c == 0) {
                back();
                return sb.toString().trim();
            }
            if (c == '&') {
                sb.append(nextEntity(c));
            } else {
                sb.append(c);
            }
            c = next();
        }
    }


    /**
     * Return the next entity. These entities are translated to Characters:
     *     &  '  >  <  ".
     * @param a An ampersand character.
     * @return  A Character or an entity String if the entity is not recognized.
     * @throws InputException If missing ';' in XML entity.
     */
    public Object nextEntity(char a) throws InputException {
        StringBuilder sb = new StringBuilder();
        for (;;) {
            char c = next();
            if (Character.isLetterOrDigit(c) || c == '#') {
                sb.append(Character.toLowerCase(c));
            } else if (c == ';') {
                break;
            } else {
                throw error("Missing ';' in XML entity: &" + sb);
            }
        }
        String s = sb.toString();
        Object e = entity.get(s);
        return e != null ? e : a + s + ";";
    }


    /**
     * Returns the next XML meta token. This is used for skipping over 
     * and  structures.
     * @return Syntax characters (< > / = ! ?) are returned as
     *  Character, and strings and names are returned as Boolean. We don't care
     *  what the values actually are.
     * @throws InputException If a string is not properly closed or if the XML
     *  is badly structured.
     */
    public Object nextMeta() throws InputException {
        char c;
        char q;
        do {
            c = next();
        } while (Character.isWhitespace(c));
        switch (c) {
        case 0:
            throw error("Misshaped meta tag");
        case '<':
            return XmlInputObject.LT;
        case '>':
            return XmlInputObject.GT;
        case '/':
            return XmlInputObject.SLASH;
        case '=':
            return XmlInputObject.EQ;
        case '!':
            return XmlInputObject.BANG;
        case '?':
            return XmlInputObject.QUEST;
        case '"':
        case '\'':
            q = c;
            for (;;) {
                c = next();
                if (c == 0) {
                    throw error("Unterminated string");
                }
                if (c == q) {
                    return Boolean.TRUE;
                }
            }
        default:
            for (;;) {
                c = next();
                if (Character.isWhitespace(c)) {
                    return Boolean.TRUE;
                }
                switch (c) {
                case 0:
                case '<':
                case '>':
                case '/':
                case '=':
                case '!':
                case '?':
                case '"':
                case '\'':
                    back();
                    return Boolean.TRUE;
                }
            }
        }
    }


    /**
     * Get the next XML Token. These tokens are found inside of angle
     * brackets. It may be one of these characters: / > = ! ? or it
     * may be a string wrapped in single quotes or double quotes, or it may be a
     * name.
     * @return a String or a Character.
     * @throws InputException If the XML is not well formed.
     */
    public Object nextToken() throws InputException {
        char c;
        char q;
        StringBuilder sb;
        do {
            c = next();
        } while (Character.isWhitespace(c));
        switch (c) {
        case 0:
            throw error("Misshaped element");
        case '<':
            throw error("Misplaced '<'");
        case '>':
            return XmlInputObject.GT;
        case '/':
            return XmlInputObject.SLASH;
        case '=':
            return XmlInputObject.EQ;
        case '!':
            return XmlInputObject.BANG;
        case '?':
            return XmlInputObject.QUEST;
        // Quoted string
        case '"':
        case '\'':
            q = c;
            sb = new StringBuilder();
            for (;;) {
                c = next();
                if (c == 0) {
                    throw error("Unterminated string");
                }
                if (c == q) {
                    return sb.toString();
                }
                if (c == '&') {
                    sb.append(nextEntity(c));
                } else {
                    sb.append(c);
                }
            }
        default:
            // Name
            sb = new StringBuilder();
            for (;;) {
                sb.append(c);
                c = next();
                if (Character.isWhitespace(c)) {
                    return sb.toString();
                }
                switch (c) {
                case 0:
                	return sb.toString();
                case '>':
                case '/':
                case '=':
                case '!':
                case '?':
                case '[':
                case ']':
                    back();
                    return sb.toString();
                case '<':
                case '"':
                case '\'':
                    throw error("Bad character in a name");
                }
            }
        }
    }


    /**
     * Skip characters until past the requested string.
     * If it is not found, we are left at the end of the source with a result of false.
     * @param to A string to skip past.
     * @throws InputException
     */
    public boolean skipPast(String to) throws InputException {
    	boolean b;
    	char c;
    	int i;
    	int j;
    	int offset = 0;
    	int n = to.length();
        char[] circle = new char[n];

        /*
         * First fill the circle buffer with as many characters as are in the
         * to string. If we reach an early end, bail.
         */

    	for (i = 0; i < n; i += 1) {
    		c = next();
    		if (c == 0) {
    			return false;
    		}
    		circle[i] = c;
    	}
    	/*
    	 * We will loop, possibly for all of the remaining characters.
    	 */
    	for (;;) {
    		j = offset;
    		b = true;
    		/*
    		 * Compare the circle buffer with the to string.
    		 */
    		for (i = 0; i < n; i += 1) {
    			if (circle[j] != to.charAt(i)) {
    				b = false;
    				break;
    			}
    			j += 1;
    			if (j >= n) {
    				j -= n;
    			}
    		}
    		/*
    		 * If we exit the loop with b intact, then victory is ours.
    		 */
    		if (b) {
    			return true;
    		}
    		/*
    		 * Get the next character. If there isn't one, then defeat is ours.
    		 */
    		c = next();
    		if (c == 0) {
    			return false;
    		}
    		/*
    		 * Shove the character in the circle buffer and advance the
    		 * circle offset. The offset is mod n.
    		 */
    		circle[offset] = c;
    		offset += 1;
    		if (offset >= n) {
    			offset -= n;
    		}
    	}
    }


   /** The table of entity values. It initially contains Character values for
    * amp, apos, gt, lt, quot.
    */
   public static final java.util.HashMap entity;

   static {
       entity = new java.util.HashMap(8);
       entity.put("amp",  XmlInputObject.AMP);
       entity.put("apos", XmlInputObject.APOS);
       entity.put("gt",   XmlInputObject.GT);
       entity.put("lt",   XmlInputObject.LT);
       entity.put("quot", XmlInputObject.QUOT);
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy