blob: 07e418b1a764cbbec848a4e8025fa26b9da244ab [file] [log] [blame]
/*
* Copyright (C) 2013 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.jill.backend.jayce;
import com.android.jill.utils.enums.DispatchKindIdHelper;
import com.android.jill.utils.enums.FieldRefKindIdHelper;
import com.android.jill.utils.enums.MethodKindIdHelper;
import com.android.jill.utils.enums.ReceiverKindIdHelper;
import com.android.jill.utils.enums.RetentionPolicyIdHelper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* Jayce writer.
*/
public class JayceWriter {
protected final Stack<JayceOutputStream> writers = new Stack<JayceOutputStream>();
private final Stack<ByteArrayOutputStream> outputStreams = new Stack<ByteArrayOutputStream>();
private final Stack<Integer> nodeCounters = new Stack<Integer>();
@Nonnull
private final List<String> currentCatchBlockList = new ArrayList<String>();
public JayceWriter(@Nonnull OutputStream out) {
writers.push(new JayceOutputStream(out));
nodeCounters.push(Integer.valueOf(0));
}
public void writeBoolean(boolean value) throws IOException {
writers.peek().writeBoolean(value);
}
private void writeIntInternal(int value) throws IOException {
writers.peek().writeInt(value);
}
public void writeInt(int value) throws IOException {
writeIntInternal(value);
writeSpace();
}
public void writeTrimmedInt(int value) throws IOException {
writeIntInternal(value);
}
private void writeLongInternal(long value) throws IOException {
writers.peek().writeLong(value);
}
public void writeLong(long value) throws IOException {
writeLongInternal(value);
writeSpace();
}
public void writeByte(byte value) throws IOException {
writers.peek().writeByte(value);
writeSpace();
}
public void writeShort(short value) throws IOException {
writers.peek().writeShort(value);
writeSpace();
}
public void writeChar(char value) throws IOException {
writers.peek().writeChar(value);
writeSpace();
}
public void writeFloat(float value) throws IOException {
writeIntInternal(Float.floatToRawIntBits(value));
writeSpace();
}
public void writeDouble(double value) throws IOException {
writeLongInternal(Double.doubleToRawLongBits(value));
writeSpace();
}
public void writeKeyword(@Nonnull Token token) throws IOException {
writers.peek().writeByte(token.ordinal());
nodeCounters.push(Integer.valueOf(nodeCounters.pop().intValue() + 1));
}
public void writeToken(@Nonnull Token token) throws IOException {
writers.peek().writeByte(token.ordinal());
}
@SuppressWarnings("unused")
public void writeOpen() throws IOException {
nodeCounters.push(Integer.valueOf(0));
}
public void writeClose() throws IOException {
writeToken(Token.RPARENTHESIS);
nodeCounters.pop();
}
public void writeOpenNodeList() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
outputStreams.push(baos);
writers.push(new JayceOutputStream(baos));
nodeCounters.push(Integer.valueOf(0));
}
public void writeCloseNodeList() throws IOException {
JayceOutputStream w = writers.pop();
w.flush();
ByteArrayOutputStream baos = outputStreams.pop();
writeIntInternal(nodeCounters.pop().intValue());
writers.peek().write(baos.toByteArray());
w.close();
writeToken(Token.RPARENTHESIS);
}
public void writeRetentionPolicyEnum(@Nonnull Enum<?> enumValue) throws IOException {
writeByte(RetentionPolicyIdHelper.getId(enumValue));
}
public void writeFieldRefKindEnum(@Nonnull Enum<?> enumValue) throws IOException {
writeByte(FieldRefKindIdHelper.getId(enumValue));
}
public void writeMethodKindEnum(@Nonnull Enum<?> enumValue) throws IOException {
writeByte(MethodKindIdHelper.getId(enumValue));
}
public void writeReceiverKindEnum(@Nonnull Enum<?> enumValue) throws IOException {
writeByte(ReceiverKindIdHelper.getId(enumValue));
}
public void writeDispatchKindEnum(@Nonnull Enum<?> enumValue) throws IOException {
writeByte(DispatchKindIdHelper.getId(enumValue));
}
public void writeIds(@Nonnull List<String> list) throws IOException {
writeOpen();
writeIntInternal(list.size());
for (String id : list) {
writeId(id);
}
writeClose();
}
public void writeCatchBlockIds(@Nonnull Set<String> list) throws IOException {
List<String> removedIds = new ArrayList<String>(currentCatchBlockList.size());
List<String> addedIds = new ArrayList<String>(list.size());
for (String s : currentCatchBlockList) {
removedIds.add(s);
}
for (String s : list) {
addedIds.add(s);
}
// intersection(current, list)
currentCatchBlockList.retainAll(list);
// current \ intersection(current, list)
removedIds.removeAll(currentCatchBlockList);
// list \ intersection(current, list)
addedIds.removeAll(currentCatchBlockList);
int addedIdsSize = addedIds.size();
int removedIdsSize = removedIds.size();
if (addedIdsSize > 0) {
writeOpenAddCatchBlockIds();
writeTrimmedInt(addedIdsSize);
for (int i = 0; i < addedIdsSize; i++) {
writeString(addedIds.get(i));
}
writeCloseCatchBlockIds();
}
if (removedIdsSize > 0) {
writeOpenRemoveCatchBlockIds();
writeTrimmedInt(removedIdsSize);
for (int i = 0; i < removedIdsSize; i++) {
writeString(removedIds.get(i));
}
writeCloseCatchBlockIds();
}
currentCatchBlockList.addAll(addedIds);
}
public void clearCatchBlockIds() {
currentCatchBlockList.clear();
}
public boolean isCurrentCatchBlockListEmpty() {
return currentCatchBlockList.isEmpty();
}
public void writeId(@CheckForNull String id) throws IOException {
writeStringInternal(id);
}
private void writeStringInternal(@CheckForNull String string) throws IOException {
writers.peek().writeUTF(string);
}
public void writeString(@CheckForNull String string) throws IOException {
writeStringInternal(string);
}
public void writeNull() throws IOException {
writeToken(Token.NULL);
writeSpace();
nodeCounters.push(Integer.valueOf(nodeCounters.pop().intValue() + 1));
}
@SuppressWarnings("unused")
protected void writeSpace() throws IOException{
}
public void writeFileName(@CheckForNull String fileName) throws IOException {
writeOpenFileName();
writeStringInternal(fileName);
writeCloseFileName();
}
private void writeOpenFileName() throws IOException {
writeToken(Token.SHARP);
}
@SuppressWarnings("unused")
private void writeCloseFileName() throws IOException{
}
public void writeCurrentLineInfo(int lineNumber)
throws IOException {
writeOpenLineInfo();
writeIntInternal(lineNumber);
writeCloseLineInfo();
}
private void writeOpenLineInfo() throws IOException {
writeToken(Token.LBRACKET);
}
@SuppressWarnings("unused")
private void writeCloseLineInfo() throws IOException{
}
private void writeOpenAddCatchBlockIds() throws IOException {
writeToken(Token.LCURLY_ADD);
}
private void writeOpenRemoveCatchBlockIds() throws IOException {
writeToken(Token.LCURLY_REMOVE);
}
@SuppressWarnings("unused")
private void writeCloseCatchBlockIds() throws IOException{
}
public void flush() throws IOException {
writers.peek().flush();
}
}