com.android.dx.dex.file.Section 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.dx.util.AnnotatedOutput;
import java.util.Collection;
/**
* A section of a {@code .dex} file. Each section consists of a list
* of items of some sort or other.
*/
public abstract class Section {
/** {@code null-ok;} name of this part, for annotation purposes */
private final String name;
/** {@code non-null;} file that this instance is part of */
private final DexFile file;
/** {@code > 0;} alignment requirement for the final output;
* must be a power of 2 */
private final int alignment;
/** {@code >= -1;} offset from the start of the file to this part, or
* {@code -1} if not yet known */
private int fileOffset;
/** whether {@link #prepare} has been called successfully on this
* instance */
private boolean prepared;
/**
* Validates an alignment.
*
* @param alignment the alignment
* @throws IllegalArgumentException thrown if {@code alignment}
* isn't a positive power of 2
*/
public static void validateAlignment(int alignment) {
if ((alignment <= 0) ||
(alignment & (alignment - 1)) != 0) {
throw new IllegalArgumentException("invalid alignment");
}
}
/**
* Constructs an instance. The file offset is initially unknown.
*
* @param name {@code null-ok;} the name of this instance, for annotation
* purposes
* @param file {@code non-null;} file that this instance is part of
* @param alignment {@code > 0;} alignment requirement for the final output;
* must be a power of 2
*/
public Section(String name, DexFile file, int alignment) {
if (file == null) {
throw new NullPointerException("file == null");
}
validateAlignment(alignment);
this.name = name;
this.file = file;
this.alignment = alignment;
this.fileOffset = -1;
this.prepared = false;
}
/**
* Gets the file that this instance is part of.
*
* @return {@code non-null;} the file
*/
public final DexFile getFile() {
return file;
}
/**
* Gets the alignment for this instance's final output.
*
* @return {@code > 0;} the alignment
*/
public final int getAlignment() {
return alignment;
}
/**
* Gets the offset from the start of the file to this part. This
* throws an exception if the offset has not yet been set.
*
* @return {@code >= 0;} the file offset
*/
public final int getFileOffset() {
if (fileOffset < 0) {
throw new RuntimeException("fileOffset not set");
}
return fileOffset;
}
/**
* Sets the file offset. It is only valid to call this method once
* once per instance.
*
* @param fileOffset {@code >= 0;} the desired offset from the start of the
* file where this for this instance
* @return {@code >= 0;} the offset that this instance should be placed at
* in order to meet its alignment constraint
*/
public final int setFileOffset(int fileOffset) {
if (fileOffset < 0) {
throw new IllegalArgumentException("fileOffset < 0");
}
if (this.fileOffset >= 0) {
throw new RuntimeException("fileOffset already set");
}
int mask = alignment - 1;
fileOffset = (fileOffset + mask) & ~mask;
this.fileOffset = fileOffset;
return fileOffset;
}
/**
* Writes this instance to the given raw data object.
*
* @param out {@code non-null;} where to write to
*/
public final void writeTo(AnnotatedOutput out) {
throwIfNotPrepared();
align(out);
int cursor = out.getCursor();
if (fileOffset < 0) {
fileOffset = cursor;
} else if (fileOffset != cursor) {
throw new RuntimeException("alignment mismatch: for " + this +
", at " + cursor +
", but expected " + fileOffset);
}
if (out.annotates()) {
if (name != null) {
out.annotate(0, "\n" + name + ":");
} else if (cursor != 0) {
out.annotate(0, "\n");
}
}
writeTo0(out);
}
/**
* Returns the absolute file offset, given an offset from the
* start of this instance's output. This is only valid to call
* once this instance has been assigned a file offset (via {@link
* #setFileOffset}).
*
* @param relative {@code >= 0;} the relative offset
* @return {@code >= 0;} the corresponding absolute file offset
*/
public final int getAbsoluteOffset(int relative) {
if (relative < 0) {
throw new IllegalArgumentException("relative < 0");
}
if (fileOffset < 0) {
throw new RuntimeException("fileOffset not yet set");
}
return fileOffset + relative;
}
/**
* Returns the absolute file offset of the given item which must
* be contained in this section. This is only valid to call
* once this instance has been assigned a file offset (via {@link
* #setFileOffset}).
*
* Note: Subclasses must implement this as appropriate for
* their contents.
*
* @param item {@code non-null;} the item in question
* @return {@code >= 0;} the item's absolute file offset
*/
public abstract int getAbsoluteItemOffset(Item item);
/**
* Prepares this instance for writing. This performs any necessary
* prerequisites, including particularly adding stuff to other
* sections. This method may only be called once per instance;
* subsequent calls will throw an exception.
*/
public final void prepare() {
throwIfPrepared();
prepare0();
prepared = true;
}
/**
* Gets the collection of all the items in this section.
* It is not valid to attempt to change the returned list.
*
* @return {@code non-null;} the items
*/
public abstract Collection extends Item> items();
/**
* Does the main work of {@link #prepare}.
*/
protected abstract void prepare0();
/**
* Gets the size of this instance when output, in bytes.
*
* @return {@code >= 0;} the size of this instance, in bytes
*/
public abstract int writeSize();
/**
* Throws an exception if {@link #prepare} has not been
* called on this instance.
*/
protected final void throwIfNotPrepared() {
if (!prepared) {
throw new RuntimeException("not prepared");
}
}
/**
* Throws an exception if {@link #prepare} has already been called
* on this instance.
*/
protected final void throwIfPrepared() {
if (prepared) {
throw new RuntimeException("already prepared");
}
}
/**
* Aligns the output of the given data to the alignment of this instance.
*
* @param out {@code non-null;} the output to align
*/
protected final void align(AnnotatedOutput out) {
out.alignTo(alignment);
}
/**
* Writes this instance to the given raw data object. This gets
* called by {@link #writeTo} after aligning the cursor of
* {@code out} and verifying that either the assigned file
* offset matches the actual cursor {@code out} or that the
* file offset was not previously assigned, in which case it gets
* assigned to {@code out}'s cursor.
*
* @param out {@code non-null;} where to write to
*/
protected abstract void writeTo0(AnnotatedOutput out);
/**
* Returns the name of this section, for annotation purposes.
*
* @return {@code null-ok;} name of this part, for annotation purposes
*/
protected final String getName() {
return name;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy