1 /* 2 * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package build.tools.dtdbuilder; 27 28 import javax.swing.text.html.parser.*; 29 import java.io.IOException; 30 import java.io.FileInputStream; 31 import java.io.InputStream; 32 import java.io.Reader; 33 import java.io.InputStreamReader; 34 import java.io.CharArrayReader; 35 import java.io.FilterReader; 36 import java.util.Stack; 37 import java.net.URL; 38 39 /** 40 * A stream for reading HTML files. This stream takes care 41 * of \r\n conversions and parameter entity expansion. 42 * 43 * @see DTD 44 * @see DTDParser 45 * @author Arthur van Hoff 46 * @author Steven B. Byrne 47 */ 48 public final 49 class DTDInputStream extends FilterReader implements DTDConstants { 50 public DTD dtd; 51 public Stack<Object> stack = new Stack<>(); 52 public char str[] = new char[64]; 53 public int replace = 0; 54 public int ln = 1; 55 public int ch; 56 57 /** 58 * Create the stream. 59 */ 60 public DTDInputStream(InputStream in, DTD dtd) throws IOException { 61 super(new InputStreamReader(in)); 62 this.dtd = dtd; 63 this.ch = in.read(); 64 } 65 66 /** 67 * Error 68 */ 69 public void error(String msg) { 70 System.out.println("line " + ln + ": dtd input error: " + msg); 71 } 72 73 /** 74 * Push a single character 75 */ 76 public void push(int ch) throws IOException { 77 char data[] = {(char)ch}; 78 push(new CharArrayReader(data)); 79 } 80 81 82 /** 83 * Push an array of bytes. 84 */ 85 public void push(char data[]) throws IOException { 86 if (data.length > 0) { 87 push(new CharArrayReader(data)); 88 } 89 } 90 91 /** 92 * Push an entire input stream 93 */ 94 void push(Reader in) throws IOException { 95 stack.push(Integer.valueOf(ln)); 96 stack.push(Integer.valueOf(ch)); 97 stack.push(this.in); 98 this.in = in; 99 ch = in.read(); 100 } 101 102 /** 103 * Read a character from the input. Automatically pop 104 * a stream of the stack if the EOF is reached. Also replaces 105 * parameter entities. 106 * [60] 350:22 107 */ 108 @SuppressWarnings("fallthrough") 109 public int read() throws IOException { 110 switch (ch) { 111 case '%': { 112 ch = in.read(); 113 if (replace > 0) { 114 return '%'; 115 } 116 117 int pos = 0; 118 while (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || 119 ((ch >= '0') && (ch <= '9')) || (ch == '.') || (ch == '-')) { 120 str[pos++] = (char)ch; 121 ch = in.read(); 122 } 123 if (pos == 0) { 124 return '%'; 125 } 126 127 String nm = new String(str, 0, pos); 128 Entity ent = dtd.getEntity(nm); 129 if (ent == null) { 130 error("undefined entity reference: " + nm); 131 return read(); 132 } 133 134 // Skip ; or RE 135 switch (ch) { 136 case '\r': 137 ln++; 138 /* fall through */ 139 case ';': 140 ch = in.read(); 141 break; 142 case '\n': 143 ln++; 144 if ((ch = in.read()) == '\r') { 145 ch = in.read(); 146 } 147 break; 148 } 149 150 // Push the entity. 151 try { 152 push(getEntityInputReader(ent)); 153 } catch (Exception e) { 154 error("entity data not found: " + ent + ", " + ent.getString()); 155 } 156 return read(); 157 } 158 159 case '\n': 160 ln++; 161 if ((ch = in.read()) == '\r') { 162 ch = in.read(); 163 } 164 return '\n'; 165 166 case '\r': 167 ln++; 168 ch = in.read(); 169 return '\n'; 170 171 case -1: 172 if (stack.size() > 0) { 173 in = (Reader)stack.pop(); 174 ch = ((Integer)stack.pop()).intValue(); 175 ln = ((Integer)stack.pop()).intValue(); 176 return read(); 177 } 178 return -1; 179 180 default: 181 int c = ch; 182 ch = in.read(); 183 return c; 184 } 185 } 186 187 /** 188 * Return the data as a stream. 189 */ 190 private Reader getEntityInputReader(Entity ent) throws IOException { 191 if ((ent.type & Entity.PUBLIC) != 0) { 192 // InputStream is = DTDBuilder.mapping.get(ent.getString()).openStream(); 193 // return new InputStreamReader(is); 194 String path = DTDBuilder.mapping.get(ent.getString()); 195 196 return new InputStreamReader(new FileInputStream(path)); 197 } 198 if ((ent.type & Entity.SYSTEM) != 0) { 199 //InputStream is = new URL(DTDBuilder.mapping.base, ent.getString()).openStream(); 200 String path = DTDBuilder.mapping.baseStr + ent.getString(); 201 return new InputStreamReader(new FileInputStream(path)); 202 } 203 return new CharArrayReader(ent.data); 204 } 205 206 }