1 /*
   2  * Copyright (c) 2009, 2015, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package com.sun.hotspot.tools.compiler;
  26 
  27 import java.io.*;
  28 import java.util.regex.*;
  29 
  30 /**
  31  * This class is a filter class to deal with malformed XML that used
  32  * to be produced by the JVM when generating LogCompilation.  In 1.6
  33  * and later releases it shouldn't be required.
  34  */
  35 class LogCleanupReader extends Reader {
  36     
  37     private Reader reader;
  38 
  39     private char[] buffer = new char[4096];
  40 
  41     private int bufferCount;
  42 
  43     private int bufferOffset;
  44 
  45     private char[] line = new char[1024];
  46 
  47     private int index;
  48 
  49     private int length;
  50 
  51     private char[] one = new char[1];
  52 
  53     LogCleanupReader(Reader r) {
  54         reader = r;
  55     }
  56 
  57     static final private Matcher duplicateCompileID = Pattern.compile(".+ compile_id='[0-9]+'.*( compile_id='[0-9]+)").matcher("");
  58     static final private Matcher compilerName = Pattern.compile("' (C[12]) compile_id=").matcher("");    
  59     static final private Matcher destroyVM = Pattern.compile("'(destroy_vm)/").matcher("");
  60 
  61     /**
  62      * The log cleanup takes place in this method. If any of the three patterns
  63      * ({@link #duplicateCompileID}, {@link #compilerName}, {@link #destroyVM})
  64      * match, that indicates a problem in the log. The cleanup is performed by
  65      * correcting the input line and writing it back into the {@link #line}
  66      * buffer.
  67      */
  68     private void fill() throws IOException {
  69         rawFill();
  70         if (length != -1) {
  71             boolean changed = false;
  72             String s = new String(line, 0, length);
  73 
  74             compilerName.reset(s);
  75             if (compilerName.find()) {
  76                 s = s.substring(0, compilerName.start(1)) + s.substring(compilerName.end(1) + 1);
  77                 changed = true;
  78             }
  79 
  80             duplicateCompileID.reset(s);
  81             if (duplicateCompileID.lookingAt()) {
  82                 s = s.substring(0, duplicateCompileID.start(1)) + s.substring(duplicateCompileID.end(1) + 1);
  83                 changed = true;
  84             }
  85 
  86             destroyVM.reset(s);
  87             if (destroyVM.find()) {
  88                 s = s.substring(0, destroyVM.start(1)) + s.substring(destroyVM.end(1));
  89                 changed = true;
  90             }
  91 
  92             if (changed) {
  93                 s.getChars(0, s.length(), line, 0);
  94                 length = s.length();
  95             }
  96         }
  97     }
  98 
  99     private void rawFill() throws IOException {
 100         if (bufferCount == -1) {
 101             length = -1;
 102             return;
 103         }
 104 
 105         int i = 0;
 106         boolean fillNonEOL = true;
 107         outer:
 108         while (true) {
 109             if (fillNonEOL) {
 110                 int p;
 111                 for (p = bufferOffset; p < bufferCount; p++) {
 112                     char c = buffer[p];
 113                     if (c == '\r' || c == '\n') {
 114                         bufferOffset = p;
 115                         fillNonEOL = false;
 116                         continue outer;
 117                     }
 118                     if (i >= line.length) {
 119                         // copy and enlarge the line array
 120                         char[] newLine = new char[line.length * 2];
 121                         System.arraycopy(line, 0, newLine, 0, line.length);
 122                         line = newLine;
 123                     }
 124                     line[i++] = c;
 125                 }
 126                 bufferOffset = p;
 127             } else {
 128                 int p;
 129                 for (p = bufferOffset; p < bufferCount; p++) {
 130                     char c = buffer[p];
 131                     if (c != '\r' && c != '\n') {
 132                         bufferOffset = p;
 133                         length = i;
 134                         index = 0;
 135                         return;
 136                     }
 137                     line[i++] = c;
 138                 }
 139                 bufferOffset = p;
 140             }
 141             if (bufferCount == -1) {
 142                 if (i == 0) {
 143                     length = -1;
 144                 } else {
 145                     length = i;
 146                 }
 147                 index = 0;
 148                 return;
 149             }
 150             if (bufferOffset != bufferCount) {
 151                 System.out.println(bufferOffset);
 152                 System.out.println(bufferCount);
 153                 throw new InternalError("how did we get here");
 154             }
 155             // load more data and try again.
 156             bufferCount = reader.read(buffer, 0, buffer.length);
 157             bufferOffset = 0;
 158         }
 159     }
 160 
 161     public int read() throws java.io.IOException {
 162         read(one, 0, 1);
 163         return one[0];
 164     }
 165 
 166     public int read(char[] buffer) throws java.io.IOException {
 167         return read(buffer, 0, buffer.length);
 168     }
 169 
 170     public int read(char[] b, int off, int len) throws java.io.IOException {
 171         if (length == -1) {
 172             return -1;
 173         }
 174 
 175         if (index == length) {
 176             fill();
 177             if (length == -1) {
 178                 return -1;
 179             }
 180         }
 181         int n = Math.min(length - index, Math.min(b.length - off, len));
 182         // System.out.printf("%d %d %d %d %d\n", index, length, off, len, n);
 183         System.arraycopy(line, index, b, off, n);
 184         index += n;
 185         return n;
 186     }
 187 
 188     public long skip(long n) throws java.io.IOException {
 189         long result = n;
 190         while (n-- > 0) read();
 191         return result;
 192     }
 193 
 194     public boolean ready() throws java.io.IOException {
 195         return reader.ready() || (line != null && length > 0);
 196     }
 197 
 198     public boolean markSupported() {
 199         return false;
 200     }
 201 
 202     public void mark(int unused) throws java.io.IOException {
 203         throw new UnsupportedOperationException("mark not supported");
 204     }
 205 
 206     public void reset() throws java.io.IOException {
 207         reader.reset();
 208         line = null;
 209         index = 0;
 210     }
 211 
 212     public void close() throws java.io.IOException {
 213         reader.close();
 214         line = null;
 215         index = 0;
 216     }
 217 }