com.android.dx.dex.file.OffsettedItem Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of builder Show documentation
Show all versions of builder Show documentation
Library to build Android applications.
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.dex.file;
import com.android.dex.util.ExceptionWithContext;
import com.android.dx.util.AnnotatedOutput;
/**
* An item in a Dalvik file which is referenced by absolute offset.
*/
public abstract class OffsettedItem extends Item
implements Comparable {
/** {@code > 0;} alignment requirement */
private final int alignment;
/** {@code >= -1;} the size of this instance when written, in bytes, or
* {@code -1} if not yet known */
private int writeSize;
/**
* {@code null-ok;} section the item was added to, or {@code null} if
* not yet added
*/
private Section addedTo;
/**
* {@code >= -1;} assigned offset of the item from the start of its section,
* or {@code -1} if not yet assigned
*/
private int offset;
/**
* Gets the absolute offset of the given item, returning {@code 0}
* if handed {@code null}.
*
* @param item {@code null-ok;} the item in question
* @return {@code >= 0;} the item's absolute offset, or {@code 0}
* if {@code item == null}
*/
public static int getAbsoluteOffsetOr0(OffsettedItem item) {
if (item == null) {
return 0;
}
return item.getAbsoluteOffset();
}
/**
* Constructs an instance. The offset is initially unassigned.
*
* @param alignment {@code > 0;} output alignment requirement; must be a
* power of 2
* @param writeSize {@code >= -1;} the size of this instance when written,
* in bytes, or {@code -1} if not immediately known
*/
public OffsettedItem(int alignment, int writeSize) {
Section.validateAlignment(alignment);
if (writeSize < -1) {
throw new IllegalArgumentException("writeSize < -1");
}
this.alignment = alignment;
this.writeSize = writeSize;
this.addedTo = null;
this.offset = -1;
}
/**
* {@inheritDoc}
*
* Comparisons for this class are defined to be type-major (if the
* types don't match then the objects are not equal), with
* {@link #compareTo0} deciding same-type comparisons.
*/
@Override
public final boolean equals(Object other) {
if (this == other) {
return true;
}
OffsettedItem otherItem = (OffsettedItem) other;
ItemType thisType = itemType();
ItemType otherType = otherItem.itemType();
if (thisType != otherType) {
return false;
}
return (compareTo0(otherItem) == 0);
}
/**
* {@inheritDoc}
*
* Comparisons for this class are defined to be class-major (if the
* classes don't match then the objects are not equal), with
* {@link #compareTo0} deciding same-class comparisons.
*/
public final int compareTo(OffsettedItem other) {
if (this == other) {
return 0;
}
ItemType thisType = itemType();
ItemType otherType = other.itemType();
if (thisType != otherType) {
return thisType.compareTo(otherType);
}
return compareTo0(other);
}
/**
* Sets the write size of this item. This may only be called once
* per instance, and only if the size was unknown upon instance
* creation.
*
* @param writeSize {@code > 0;} the write size, in bytes
*/
public final void setWriteSize(int writeSize) {
if (writeSize < 0) {
throw new IllegalArgumentException("writeSize < 0");
}
if (this.writeSize >= 0) {
throw new UnsupportedOperationException("writeSize already set");
}
this.writeSize = writeSize;
}
/** {@inheritDoc}
*
* @throws UnsupportedOperationException thrown if the write size
* is not yet known
*/
@Override
public final int writeSize() {
if (writeSize < 0) {
throw new UnsupportedOperationException("writeSize is unknown");
}
return writeSize;
}
/** {@inheritDoc} */
@Override
public final void writeTo(DexFile file, AnnotatedOutput out) {
out.alignTo(alignment);
try {
if (writeSize < 0) {
throw new UnsupportedOperationException(
"writeSize is unknown");
}
out.assertCursor(getAbsoluteOffset());
} catch (RuntimeException ex) {
throw ExceptionWithContext.withContext(ex,
"...while writing " + this);
}
writeTo0(file, out);
}
/**
* Gets the relative item offset. The offset is from the start of
* the section which the instance was written to.
*
* @return {@code >= 0;} the offset
* @throws RuntimeException thrown if the offset is not yet known
*/
public final int getRelativeOffset() {
if (offset < 0) {
throw new RuntimeException("offset not yet known");
}
return offset;
}
/**
* Gets the absolute item offset. The offset is from the start of
* the file which the instance was written to.
*
* @return {@code >= 0;} the offset
* @throws RuntimeException thrown if the offset is not yet known
*/
public final int getAbsoluteOffset() {
if (offset < 0) {
throw new RuntimeException("offset not yet known");
}
return addedTo.getAbsoluteOffset(offset);
}
/**
* Indicates that this item has been added to the given section at
* the given offset. It is only valid to call this method once per
* instance.
*
* @param addedTo {@code non-null;} the section this instance has
* been added to
* @param offset {@code >= 0;} the desired offset from the start of the
* section where this instance was placed
* @return {@code >= 0;} the offset that this instance should be placed at
* in order to meet its alignment constraint
*/
public final int place(Section addedTo, int offset) {
if (addedTo == null) {
throw new NullPointerException("addedTo == null");
}
if (offset < 0) {
throw new IllegalArgumentException("offset < 0");
}
if (this.addedTo != null) {
throw new RuntimeException("already written");
}
int mask = alignment - 1;
offset = (offset + mask) & ~mask;
this.addedTo = addedTo;
this.offset = offset;
place0(addedTo, offset);
return offset;
}
/**
* Gets the alignment requirement of this instance. An instance should
* only be written when so aligned.
*
* @return {@code > 0;} the alignment requirement; must be a power of 2
*/
public final int getAlignment() {
return alignment;
}
/**
* Gets the absolute offset of this item as a string, suitable for
* including in annotations.
*
* @return {@code non-null;} the offset string
*/
public final String offsetString() {
return '[' + Integer.toHexString(getAbsoluteOffset()) + ']';
}
/**
* Gets a short human-readable string representing this instance.
*
* @return {@code non-null;} the human form
*/
public abstract String toHuman();
/**
* Compares this instance to another which is guaranteed to be of
* the same class. The default implementation of this method is to
* throw an exception (unsupported operation). If a particular
* class needs to actually sort, then it should override this
* method.
*
* @param other {@code non-null;} instance to compare to
* @return {@code -1}, {@code 0}, or {@code 1}, depending
* on the sort order of this instance and the other
*/
protected int compareTo0(OffsettedItem other) {
throw new UnsupportedOperationException("unsupported");
}
/**
* Does additional work required when placing an instance. The
* default implementation of this method is a no-op. If a
* particular class needs to do something special, then it should
* override this method. In particular, if this instance did not
* know its write size up-front, then this method is responsible
* for setting it.
*
* @param addedTo {@code non-null;} the section this instance has been added to
* @param offset {@code >= 0;} the offset from the start of the
* section where this instance was placed
*/
protected void place0(Section addedTo, int offset) {
// This space intentionally left blank.
}
/**
* Performs the actual write of the contents of this instance to
* the given data section. This is called by {@link #writeTo},
* which will have taken care of ensuring alignment.
*
* @param file {@code non-null;} the file to use for reference
* @param out {@code non-null;} where to write to
*/
protected abstract void writeTo0(DexFile file, AnnotatedOutput out);
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy