1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.bcel.internal.classfile;
  23 
  24 
  25 import  com.sun.org.apache.bcel.internal.Constants;
  26 import  java.io.*;
  27 
  28 /**
  29  * This class represents a table of line numbers for debugging
  30  * purposes. This attribute is used by the <em>Code</em> attribute. It
  31  * contains pairs of PCs and line numbers.
  32  *
  33  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  34  * @see     Code
  35  * @see LineNumber
  36  */
  37 public final class LineNumberTable extends Attribute {
  38   private int          line_number_table_length;
  39   private LineNumber[] line_number_table; // Table of line/numbers pairs
  40 
  41   /*
  42    * Initialize from another object. Note that both objects use the same
  43    * references (shallow copy). Use copy() for a physical copy.
  44    */
  45   public LineNumberTable(LineNumberTable c) {
  46     this(c.getNameIndex(), c.getLength(), c.getLineNumberTable(),
  47          c.getConstantPool());
  48   }
  49 
  50   /*
  51    * @param name_index Index of name
  52    * @param length Content length in bytes
  53    * @param line_number_table Table of line/numbers pairs
  54    * @param constant_pool Array of constants
  55    */
  56   public LineNumberTable(int name_index, int length,
  57                          LineNumber[] line_number_table,
  58                          ConstantPool constant_pool)
  59   {
  60     super(Constants.ATTR_LINE_NUMBER_TABLE, name_index, length, constant_pool);
  61     setLineNumberTable(line_number_table);
  62   }
  63 
  64   /**
  65    * Construct object from file stream.
  66    * @param name_index Index of name
  67    * @param length Content length in bytes
  68    * @param file Input stream
  69    * @throws IOException
  70    * @param constant_pool Array of constants
  71    */
  72   LineNumberTable(int name_index, int length, DataInputStream file,
  73                   ConstantPool constant_pool) throws IOException
  74   {
  75     this(name_index, length, (LineNumber[])null, constant_pool);
  76     line_number_table_length = (file.readUnsignedShort());
  77     line_number_table = new LineNumber[line_number_table_length];
  78 
  79     for(int i=0; i < line_number_table_length; i++)
  80       line_number_table[i] = new LineNumber(file);
  81   }
  82   /**
  83    * Called by objects that are traversing the nodes of the tree implicitely
  84    * defined by the contents of a Java class. I.e., the hierarchy of methods,
  85    * fields, attributes, etc. spawns a tree of objects.
  86    *
  87    * @param v Visitor object
  88    */
  89   public void accept(Visitor v) {
  90     v.visitLineNumberTable(this);
  91   }
  92   /**
  93    * Dump line number table attribute to file stream in binary format.
  94    *
  95    * @param file Output file stream
  96    * @throws IOException
  97    */
  98   public final void dump(DataOutputStream file) throws IOException
  99   {
 100     super.dump(file);
 101     file.writeShort(line_number_table_length);
 102     for(int i=0; i < line_number_table_length; i++)
 103       line_number_table[i].dump(file);
 104   }
 105 
 106   /**
 107    * @return Array of (pc offset, line number) pairs.
 108    */
 109   public final LineNumber[] getLineNumberTable() { return line_number_table; }
 110 
 111   /**
 112    * @param line_number_table.
 113    */
 114   public final void setLineNumberTable(LineNumber[] line_number_table) {
 115     this.line_number_table = line_number_table;
 116 
 117     line_number_table_length = (line_number_table == null)? 0 :
 118       line_number_table.length;
 119   }
 120 
 121   /**
 122    * @return String representation.
 123    */
 124   public final String toString() {
 125     StringBuffer buf  = new StringBuffer();
 126     StringBuffer line = new StringBuffer();
 127 
 128     for(int i=0; i < line_number_table_length; i++) {
 129       line.append(line_number_table[i].toString());
 130 
 131       if(i < line_number_table_length - 1)
 132         line.append(", ");
 133 
 134       if(line.length() > 72) {
 135         line.append('\n');
 136         buf.append(line);
 137         line.setLength(0);
 138       }
 139     }
 140 
 141     buf.append(line);
 142 
 143     return buf.toString();
 144   }
 145 
 146   /**
 147    * Map byte code positions to source code lines.
 148    *
 149    * @param pos byte code offset
 150    * @return corresponding line in source code
 151    */
 152   public int getSourceLine(int pos) {
 153     int l = 0, r = line_number_table_length-1;
 154 
 155     if(r < 0) // array is empty
 156       return -1;
 157 
 158     int min_index = -1, min=-1;
 159 
 160     /* Do a binary search since the array is ordered.
 161      */
 162     do {
 163       int i = (l + r) / 2;
 164       int j = line_number_table[i].getStartPC();
 165 
 166       if(j == pos)
 167         return line_number_table[i].getLineNumber();
 168       else if(pos < j) // else constrain search area
 169         r = i - 1;
 170       else // pos > j
 171         l = i + 1;
 172 
 173       /* If exact match can't be found (which is the most common case)
 174        * return the line number that corresponds to the greatest index less
 175        * than pos.
 176        */
 177       if(j < pos && j > min) {
 178         min       = j;
 179         min_index = i;
 180       }
 181     } while(l <= r);
 182 
 183     /* It's possible that we did not find any valid entry for the bytecode
 184      * offset we were looking for.
 185      */
 186     if (min_index < 0)
 187       return -1;
 188 
 189     return line_number_table[min_index].getLineNumber();
 190   }
 191 
 192   /**
 193    * @return deep copy of this attribute
 194    */
 195   public Attribute copy(ConstantPool constant_pool) {
 196     LineNumberTable c = (LineNumberTable)clone();
 197 
 198     c.line_number_table = new LineNumber[line_number_table_length];
 199     for(int i=0; i < line_number_table_length; i++)
 200       c.line_number_table[i] = line_number_table[i].copy();
 201 
 202     c.constant_pool = constant_pool;
 203     return c;
 204   }
 205 
 206   public final int getTableLength() { return line_number_table_length; }
 207 }