# XmlReaderDelegate.java

    /**
     *  Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
     *
     *  WSO2 Inc. licenses this file to you under the Apache License,
     *  Version 2.0 (the "License"); you may not use this file except
     *  in compliance with the License.
     *  You may obtain a copy of the License at
     *
     *    http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing,
     * software distributed under the License is distributed on an
     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     * KIND, either express or implied.  See the License for the
     * specific language governing permissions and limitations
     * under the License.
     */

    package org.apache.synapse.commons.json;

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    import javax.xml.namespace.QName;
    import javax.xml.stream.XMLStreamReader;
    import javax.xml.stream.util.StreamReaderDelegate;

    /**
     * Detaches the special prefix applied by the JsonReaderDelegate.<br/>
     * Hence this returns the original key value that was read in.
     */
    final class XmlReaderDelegate extends StreamReaderDelegate {
        private static final Log logger = LogFactory.getLog(XmlReaderDelegate.class.getName());

        private boolean processNCNames;

        public XmlReaderDelegate(XMLStreamReader reader, boolean processNCNames) {
            super(reader);
            /** Possible reader implementations include;
             com.ctc.wstx.sr.ValidatingStreamReader
             de.odysseus.staxon.json.JsonXMLStreamReader
             com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl
             */
            if (logger.isDebugEnabled()) {
                logger.debug("#XmlReaderDelegate. Setting XMLStreamReader: " + reader.getClass().getName());
            }
            this.processNCNames = processNCNames;
        }

        public String getLocalName() {
            String localName = super.getLocalName();
            String newName = localName;
            if (localName == null || "".equals(localName)) {
                return localName;
            }
            boolean checked = false;
            String subStr;
            if (localName.charAt(0) == Constants.C_USOCRE) {
                if (localName.startsWith(Constants.PRECEDING_DIGIT)) {
                    subStr = localName.substring(Constants.PRECEDING_DIGIT.length(),
                            localName.length());
                    if (processNCNames) {
                        newName = toOrigJsonKey(subStr);
                        checked = true;
                    } else {
                        newName = subStr;
                    }
                } else if (localName.startsWith(Constants.PRECEDING_DOLLOR)) {
                    subStr = localName.substring(Constants.PRECEDING_DOLLOR.length(),
                            localName.length());
                    if (processNCNames) {
                        newName = (char) Constants.C_DOLLOR + toOrigJsonKey(subStr);
                        checked = true;
                    } else {
                        newName = (char) Constants.C_DOLLOR + subStr;
                    }
                }
            }
            if (!checked && processNCNames) {
                newName = toOrigJsonKey(newName);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("#getLocalName. old=" + localName + ", new=" + newName);
            }
            return newName;
        }

        public QName getName() {
            QName qName = super.getName();
            String localName = qName.getLocalPart();
            QName newName = qName;
            if (localName == null || "".equals(localName)) {
                return qName;
            }
            boolean checked = false;
            String subStr;
            if (localName.charAt(0) == Constants.C_USOCRE) {
                if (localName.startsWith(Constants.PRECEDING_DIGIT)) {
                    subStr = localName.substring(Constants.PRECEDING_DIGIT.length(),
                            localName.length());
                    if (processNCNames) {
                        localName = toOrigJsonKey(subStr);
                        checked = true;
                    } else {
                        localName = subStr;
                    }
                    newName = new QName(qName.getNamespaceURI(), localName, qName.getPrefix());
                } else if (localName.startsWith(Constants.PRECEDING_DOLLOR)) {
                    subStr = localName.substring(Constants.PRECEDING_DOLLOR.length(),
                            localName.length());
                    if (processNCNames) {
                        localName = (char) Constants.C_DOLLOR + toOrigJsonKey(subStr);
                        checked = true;
                    } else {
                        localName = (char) Constants.C_DOLLOR + subStr;
                    }
                    newName = new QName(qName.getNamespaceURI(), localName, qName.getPrefix());
                }
            }
            if (!checked && processNCNames) {
                String newNameP = toOrigJsonKey(localName);
                if (!localName.equals(newNameP)) {
                    newName = new QName(qName.getNamespaceURI(), newNameP, qName.getPrefix());
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("#getName. old=" + localName + ", new=" + newName.getLocalPart());
            }
            return newName;
        }

        private String toOrigJsonKey(String src) {
            int indexO, indexN;
            indexO = indexN = 0;
            int length = Constants.ID_KEY.length();
            StringBuilder newStr = new StringBuilder(src.length());
            int[] index = new int[1];
            while (indexN < src.length()) {
                indexN = src.indexOf(Constants.ID_KEY, indexO);
                if (indexN == -1) {
                    if (indexO == 0) {
                        return src;
                    }
                    copyChars(src, indexO, src.length(), newStr);
                    break;
                }
                copyChars(src, indexO, indexN, newStr);
                indexO = indexN + length;
                index[0] = indexO;
                int character = readInt(src, index);
                if (character != -1) {
                    newStr.append((char) character);
                    indexO = index[0] + 1;
                } else {
                    copyChars(src, indexO - length, indexO, newStr);
                }
            }
            return newStr.toString();
        }

        private static void copyChars(String src, int low, int high, StringBuilder newStr) {
            for (int i = low; i < high; ++i) {
                newStr.append(src.charAt(i));
            }
        }

        private static int readInt(String s, int[] index) {
            int value = 0;
            int l = s.length();
            while (index[0] < l && index[0] != -1 && s.charAt(index[0]) != '_') {
                int n = s.charAt(index[0]++) - '0';
                n = (n >= 0 && n <= 9) ? n : -1;
                if (n == -1) {
                    return -1;
                }
                value = value * 10 + n;
            }
            if (value <= 0) {
                return -1;
            }
            return value;
        }
    }