1ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpackage com.android.hotspot2.omadm; 2ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 3ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport org.xml.sax.Attributes; 4ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport org.xml.sax.SAXException; 5ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 6ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.io.IOException; 7ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.ArrayList; 8ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Arrays; 9ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Collections; 10ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashMap; 11ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.HashSet; 12ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.List; 13ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Map; 14ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistimport java.util.Set; 15ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 16ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvistpublic class XMLNode { 17ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final String mTag; 18ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final Map<String, NodeAttribute> mAttributes; 19ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final List<XMLNode> mChildren; 20ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private final XMLNode mParent; 21ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private MOTree mMO; 22ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private StringBuilder mTextBuilder; 23ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private String mText; 24ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 25ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final String XML_SPECIAL_CHARS = "\"'<>&"; 26ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final Set<Character> XML_SPECIAL = new HashSet<>(); 27ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final String CDATA_OPEN = "<![CDATA["; 28ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static final String CDATA_CLOSE = "]]>"; 29ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 30ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist static { 31ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (int n = 0; n < XML_SPECIAL_CHARS.length(); n++) { 32ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist XML_SPECIAL.add(XML_SPECIAL_CHARS.charAt(n)); 33ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 34ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 35ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 36ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public XMLNode(XMLNode parent, String tag, Attributes attributes) throws SAXException { 37ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTag = tag; 38ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 39ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mAttributes = new HashMap<>(); 40ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 41ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (attributes.getLength() > 0) { 42ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (int n = 0; n < attributes.getLength(); n++) 43ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mAttributes.put(attributes.getQName(n), new NodeAttribute(attributes.getQName(n), 44ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist attributes.getType(n), attributes.getValue(n))); 45ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 46ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 47ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mParent = parent; 48ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mChildren = new ArrayList<>(); 49ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 50ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTextBuilder = new StringBuilder(); 51ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 52ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 53ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public XMLNode(XMLNode parent, String tag, Map<String, String> attributes) { 54ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTag = tag; 55ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 56ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mAttributes = new HashMap<>(attributes == null ? 0 : attributes.size()); 57ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 58ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (attributes != null) { 59ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (Map.Entry<String, String> entry : attributes.entrySet()) { 60ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mAttributes.put(entry.getKey(), 61ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist new NodeAttribute(entry.getKey(), "", entry.getValue())); 62ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 63ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 64ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 65ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mParent = parent; 66ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mChildren = new ArrayList<>(); 67ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 68ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTextBuilder = new StringBuilder(); 69ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 70ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 71ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void setText(String text) { 72ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mText = text; 73ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTextBuilder = null; 74ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 75ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 76ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void addText(char[] chs, int start, int length) { 77ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String s = new String(chs, start, length); 78ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String trimmed = s.trim(); 79ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (trimmed.isEmpty()) 80ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return; 81ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 82ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (s.charAt(0) != trimmed.charAt(0)) 83ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTextBuilder.append(' '); 84ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTextBuilder.append(trimmed); 85ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (s.charAt(s.length() - 1) != trimmed.charAt(trimmed.length() - 1)) 86ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTextBuilder.append(' '); 87ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 88ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 89ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void addChild(XMLNode child) { 90ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mChildren.add(child); 91ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 92ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 93ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public void close() throws IOException, SAXException { 94ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String text = mTextBuilder.toString().trim(); 95ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist StringBuilder filtered = new StringBuilder(text.length()); 96ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (int n = 0; n < text.length(); n++) { 97ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist char ch = text.charAt(n); 98ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (ch >= ' ') 99ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist filtered.append(ch); 100ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 101ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 102ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mText = filtered.toString(); 103ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mTextBuilder = null; 104ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 105ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (MOTree.hasMgmtTreeTag(mText)) { 106ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist try { 107ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist NodeAttribute urn = mAttributes.get(OMAConstants.SppMOAttribute); 108ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist OMAParser omaParser = new OMAParser(); 109ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mMO = omaParser.parse(mText, urn != null ? urn.getValue() : null); 110ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } catch (SAXException | IOException e) { 111ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist mMO = null; 112ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 113ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 114ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 115ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 116ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String getTag() { 117ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mTag; 118ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 119ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 120ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String getNameSpace() throws OMAException { 121ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String[] nsn = mTag.split(":"); 122ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (nsn.length != 2) { 123ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throw new OMAException("Non-namespaced tag: '" + mTag + "'"); 124ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 125ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return nsn[0]; 126ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 127ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 128ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String getStrippedTag() throws OMAException { 129ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist String[] nsn = mTag.split(":"); 130ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (nsn.length != 2) { 131ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throw new OMAException("Non-namespaced tag: '" + mTag + "'"); 132ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 133ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return nsn[1].toLowerCase(); 134ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 135ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 136ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public XMLNode getSoleChild() throws OMAException { 137ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (mChildren.size() != 1) { 138ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist throw new OMAException("Expected exactly one child to " + mTag); 139ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 140ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mChildren.get(0); 141ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 142ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 143ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public XMLNode getParent() { 144ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mParent; 145ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 146ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 147ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String getText() { 148ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mText; 149ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 150ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 151ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public Map<String, NodeAttribute> getAttributes() { 152ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return Collections.unmodifiableMap(mAttributes); 153ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 154ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 155ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public Map<String, String> getTextualAttributes() { 156ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Map<String, String> map = new HashMap<>(mAttributes.size()); 157ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (Map.Entry<String, NodeAttribute> entry : mAttributes.entrySet()) { 158ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist map.put(entry.getKey(), entry.getValue().getValue()); 159ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 160ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return map; 161ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 162ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 163ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String getAttributeValue(String name) { 164ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist NodeAttribute nodeAttribute = mAttributes.get(name); 165ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return nodeAttribute != null ? nodeAttribute.getValue() : null; 166ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 167ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 168ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public List<XMLNode> getChildren() { 169ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mChildren; 170ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 171ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 172ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public MOTree getMOTree() { 173ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return mMO; 174ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 175ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 176ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private void toString(char[] indent, StringBuilder sb) { 177ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist Arrays.fill(indent, ' '); 178ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 179ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append(indent).append('<').append(mTag); 180ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (Map.Entry<String, NodeAttribute> entry : mAttributes.entrySet()) { 181ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append(' ').append(entry.getKey()).append("='") 182ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist .append(entry.getValue().getValue()).append('\''); 183ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 184ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 185ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (mText != null && !mText.isEmpty()) { 186ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append('>').append(escapeCdata(mText)).append("</").append(mTag).append(">\n"); 187ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else if (mChildren.isEmpty()) { 188ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append("/>\n"); 189ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 190ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append(">\n"); 191ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist char[] subIndent = Arrays.copyOf(indent, indent.length + 2); 192ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (XMLNode child : mChildren) { 193ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist child.toString(subIndent, sb); 194ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 195ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append(indent).append("</").append(mTag).append(">\n"); 196ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 197ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 198ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 199ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static String escapeCdata(String text) { 200ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (!escapable(text)) { 201ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return text; 202ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 203ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 204ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // Any appearance of ]]> in the text must be split into "]]" | "]]>" | <![CDATA[ | ">" 205ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist // i.e. "split the sequence by putting a close CDATA and a new open CDATA before the '>' 206ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist StringBuilder sb = new StringBuilder(); 207ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append(CDATA_OPEN); 208ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist int start = 0; 209ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (; ; ) { 210ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist int etoken = text.indexOf(CDATA_CLOSE); 211ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (etoken >= 0) { 212ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append(text.substring(start, etoken + 2)).append(CDATA_CLOSE).append(CDATA_OPEN); 213ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist start = etoken + 2; 214ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } else { 215ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (start < text.length() - 1) { 216ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append(text.substring(start)); 217ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 218ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist break; 219ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 220ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 221ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist sb.append(CDATA_CLOSE); 222ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return sb.toString(); 223ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 224ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 225ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist private static boolean escapable(String s) { 226ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist for (int n = 0; n < s.length(); n++) { 227ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist if (XML_SPECIAL.contains(s.charAt(n))) { 228ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return true; 229ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 230ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 231ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return false; 232ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 233ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist 234ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist @Override 235ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist public String toString() { 236ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist StringBuilder sb = new StringBuilder(); 237ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist toString(new char[0], sb); 238ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist return sb.toString(); 239ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist } 240ee699a61a5687d7c8518b639a940c8e9d1b384ddJan Nordqvist} 241