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 }