1/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2 *
3 * This program and the accompanying materials are made available under
4 * the terms of the Common Public License v1.0 which accompanies this distribution,
5 * and is available at http://www.eclipse.org/legal/cpl-v10.html
6 *
7 * $Id: LineNumberTableAttribute_info.java,v 1.1.1.1 2004/05/09 16:57:48 vlad_r Exp $
8 */
9package com.vladium.jcd.cls.attribute;
10
11import java.io.IOException;
12import java.util.ArrayList;
13import java.util.List;
14
15import com.vladium.jcd.lib.UDataInputStream;
16import com.vladium.jcd.lib.UDataOutputStream;
17
18// ----------------------------------------------------------------------------
19/**
20 * The LineNumberTable attribute is an optional variable-length attribute in
21 * the attributes table of a {@link CodeAttribute_info} attribute. It may be
22 * used by debuggers to determine which part of the JVM code array corresponds
23 * to a given line number in the original source file. If LineNumberTable
24 * attributes are present in the attributes table of a given Code attribute,
25 * then they may appear in any order. Furthermore, multiple LineNumberTable
26 * attributes may together represent a given line of a source file; that is,
27 * LineNumberTable attributes need not be one-to-one with source lines.<P>
28 *
29 * The LineNumberTable attribute has the following format:
30 * <PRE>
31 * LineNumberTable_attribute {
32 *          u2 attribute_name_index;
33 *          u4 attribute_length;
34 *          u2 line_number_table_length;
35 *          {  u2 start_pc;
36 *             u2 line_number;
37 *          } line_number_table[line_number_table_length];
38 *  }
39 * <PRE>
40 *
41 * LineNumberTable_attribute structure contains the following items:
42 * <PRE>
43 *    line_number_table_length
44 * </PRE>
45 * The value of the line_number_table_length item indicates the number of
46 * entries in the line_number_table array.
47 * <PRE>
48 *    line_number_table[]
49 * </PRE>
50 * Each entry in the line_number_table array indicates that the line number
51 * in the original source file changes at a given point in the code array.<P>
52 *
53 * Each line_number_table entry must contain the following two items:
54 * <PRE>
55 *    start_pc
56 * </PRE>
57 * The value of the start_pc item must indicate the index into the code array
58 * at which the code for a new line in the original source file begins. The
59 * value of start_pc must be less than the value of the code_length item of
60 * the {@link CodeAttribute_info} attribute of which this LineNumberTable
61 * is an attribute.<P>
62 * <PRE>
63 *    line_number
64 * </PRE>
65 * The value of the line_number item must give the corresponding line number
66 * in the original source file.
67 *
68 * @author Vlad Roubtsov, (C) 2003
69 */
70public
71final class LineNumberTableAttribute_info extends Attribute_info
72{
73    // public: ................................................................
74
75    // ACCESSORS:
76
77    /**
78     * Returns {@link LineNumber_info} descriptor at a given offset.
79     *
80     * @param offset line number entry offset [must be in [0, size()) range;
81     * input not checked]
82     * @return LineNumber_info descriptor [never null]
83     *
84     * @throws IndexOutOfBoundsException if 'offset' is outside of valid range
85     */
86    public LineNumber_info get (final int offset)
87    {
88        return (LineNumber_info) m_lines.get (offset);
89    }
90
91    /**
92     * Returns the number of descriptors in this collection [can be 0].
93     */
94    public int size ()
95    {
96        return m_lines.size ();
97    }
98
99    public long length ()
100    {
101        return 8 + (m_lines.size () << 2); // use size() if class becomes non-final
102    }
103
104    // Visitor:
105
106    public void accept (final IAttributeVisitor visitor, final Object ctx)
107    {
108        visitor.visit (this, ctx);
109    }
110
111    public String toString ()
112    {
113        final StringBuffer s = new StringBuffer ("LineNumberTableAttribute_info: [attribute_name_index = " + m_name_index + ", attribute_length = " + length () + "]\n");
114
115        for (int l = 0; l < size (); ++ l)
116        {
117            s.append ("            " + get (l));
118            s.append ("\n"); // TODO: proper EOL const
119        }
120
121        return s.toString ();
122    }
123
124    // Cloneable:
125
126    /**
127     * Performs a deep copy.
128     */
129    public Object clone ()
130    {
131        final LineNumberTableAttribute_info _clone = (LineNumberTableAttribute_info) super.clone ();
132
133        // do deep copy:
134        final int lines_count = m_lines.size (); // use size() if class becomes non-final
135        _clone.m_lines = new ArrayList (lines_count);
136        for (int e = 0; e < lines_count; ++ e)
137        {
138            _clone.m_lines.add (((LineNumber_info) m_lines.get (e)).clone ());
139        }
140
141        return _clone;
142    }
143
144    // IClassFormatOutput:
145
146    public void writeInClassFormat (final UDataOutputStream out) throws IOException
147    {
148        super.writeInClassFormat (out);
149
150        final int lines_count = m_lines.size (); // use size() if class becomes non-final
151        out.writeU2 (lines_count);
152
153        for (int l = 0; l < lines_count; ++ l)
154        {
155            ((LineNumber_info) m_lines.get (l)).writeInClassFormat (out);
156        }
157    }
158
159    // protected: .............................................................
160
161    // package: ...............................................................
162
163
164    LineNumberTableAttribute_info (final int attribute_name_index, final long attribute_length,
165                                   final UDataInputStream bytes)
166        throws IOException
167    {
168        super (attribute_name_index, attribute_length);
169
170        final int lines_count = bytes.readU2 ();
171        m_lines = new ArrayList (lines_count);
172
173        for (int i = 0; i < lines_count; i++)
174        {
175            m_lines.add (new LineNumber_info (bytes));
176        }
177    }
178
179    // private: ...............................................................
180
181
182    private List/* LineNumber_info */ m_lines; // never null
183
184} // end of class
185// ----------------------------------------------------------------------------