001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.harmony.pack200;
020
021import org.objectweb.asm.Attribute;
022import org.objectweb.asm.ClassReader;
023import org.objectweb.asm.Label;
024
025/**
026 * NewAttribute extends {@code Attribute} and manages unknown attributes encountered by ASM that have had a layout definition given to pack200 (for example via
027 * one of the -C, -M, -F or -D command line options)
028 */
029public class NewAttribute extends Attribute {
030    /**
031     * ErrorAttribute extends {@code NewAttribute} and manages attributes encountered by ASM that have had an error action specified to pack200 (for example via
032     * one of the -C, -M, -F or -D command line options such as -Cattribute-name=error)
033     */
034    public static class ErrorAttribute extends NewAttribute {
035        public ErrorAttribute(final String type, final int context) {
036            super(type, "", context);
037        }
038
039        @Override
040        protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) {
041            throw new Error("Attribute " + type + " was found");
042        }
043    }
044
045    /**
046     * PassAttribute extends {@code NewAttribute} and manages attributes encountered by ASM that have had a pass action specified to pack200 (for example via
047     * one of the -C, -M, -F or -D command line options such as -Cattribute-name=pass)
048     */
049    public static class PassAttribute extends NewAttribute {
050        public PassAttribute(final String type, final int context) {
051            super(type, "", context);
052        }
053
054        @Override
055        protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) {
056            throw new Segment.PassException();
057        }
058    }
059
060    /**
061     * StripAttribute extends {@code NewAttribute} and manages attributes encountered by ASM that have had a strip action specified to pack200 (for example via
062     * one of the -C, -M, -F or -D command line options such as -Cattribute-name=strip)
063     */
064    public static class StripAttribute extends NewAttribute {
065        public StripAttribute(final String type, final int context) {
066            super(type, "", context);
067        }
068
069        @Override
070        protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) {
071            // TODO Not sure if this works, can we really strip an attribute if we don't know the layout?
072            return null;
073        }
074    }
075
076    private boolean contextClass;
077    private boolean contextMethod;
078    private boolean contextField;
079    private boolean contextCode;
080    private final String layout;
081    private byte[] contents;
082    private int codeOff;
083    private Label[] labels;
084    private ClassReader classReader;
085    private char[] buf;
086
087    public NewAttribute(final ClassReader classReader, final String type, final String layout, final byte[] contents, final char[] buf, final int codeOff,
088            final Label[] labels) {
089        super(type);
090        this.classReader = classReader;
091        this.contents = contents;
092        this.layout = layout;
093        this.codeOff = codeOff;
094        this.labels = labels;
095        this.buf = buf;
096    }
097
098    public NewAttribute(final String type, final String layout, final int context) {
099        super(type);
100        this.layout = layout;
101        addContext(context);
102    }
103
104    public void addContext(final int context) {
105        switch (context) {
106        case AttributeDefinitionBands.CONTEXT_CLASS:
107            contextClass = true;
108            break;
109        case AttributeDefinitionBands.CONTEXT_METHOD:
110            contextMethod = true;
111            break;
112        case AttributeDefinitionBands.CONTEXT_FIELD:
113            contextField = true;
114            break;
115        case AttributeDefinitionBands.CONTEXT_CODE:
116            contextCode = true;
117            break;
118        }
119    }
120
121    public byte[] getBytes() {
122        return contents;
123    }
124
125    public Label getLabel(final int index) {
126        return labels[index];
127    }
128
129    public String getLayout() {
130        return layout;
131    }
132
133    @Override
134    public boolean isCodeAttribute() {
135        return codeOff != -1;
136    }
137
138    public boolean isContextClass() {
139        return contextClass;
140    }
141
142    public boolean isContextCode() {
143        return contextCode;
144    }
145
146    public boolean isContextField() {
147        return contextField;
148    }
149
150    public boolean isContextMethod() {
151        return contextMethod;
152    }
153
154    @Override
155    public boolean isUnknown() {
156        return false;
157    }
158
159    public boolean isUnknown(final int context) {
160        switch (context) {
161        case AttributeDefinitionBands.CONTEXT_CLASS:
162            return !contextClass;
163        case AttributeDefinitionBands.CONTEXT_METHOD:
164            return !contextMethod;
165        case AttributeDefinitionBands.CONTEXT_FIELD:
166            return !contextField;
167        case AttributeDefinitionBands.CONTEXT_CODE:
168            return !contextCode;
169        }
170        return false;
171    }
172
173    @Override
174    protected Attribute read(final ClassReader cr, final int off, final int len, final char[] buf, final int codeOff, final Label[] labels) {
175        final byte[] attributeContents = new byte[len];
176        System.arraycopy(cr.b, off, attributeContents, 0, len);
177        return new NewAttribute(cr, type, layout, attributeContents, buf, codeOff, labels);
178    }
179
180    public String readClass(final int index) {
181        return classReader.readClass(index, buf);
182    }
183
184    public Object readConst(final int index) {
185        return classReader.readConst(index, buf);
186    }
187
188    public String readUTF8(final int index) {
189        return classReader.readUTF8(index, buf);
190    }
191}