| Index: third_party/jmake/src/org/pantsbuild/jmake/BinaryProjectDatabaseWriter.java
|
| diff --git a/third_party/jmake/src/org/pantsbuild/jmake/BinaryProjectDatabaseWriter.java b/third_party/jmake/src/org/pantsbuild/jmake/BinaryProjectDatabaseWriter.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fafaa39815390366f052268c37a67a7f062abc9f
|
| --- /dev/null
|
| +++ b/third_party/jmake/src/org/pantsbuild/jmake/BinaryProjectDatabaseWriter.java
|
| @@ -0,0 +1,363 @@
|
| +/* Copyright (c) 2002-2008 Sun Microsystems, Inc. All rights reserved
|
| + *
|
| + * This program is distributed under the terms of
|
| + * the GNU General Public License Version 2. See the LICENSE file
|
| + * at the top of the source tree.
|
| + */
|
| +package org.pantsbuild.jmake;
|
| +
|
| +import java.io.File;
|
| +import java.io.FileOutputStream;
|
| +import java.io.IOException;
|
| +import java.util.Map;
|
| +
|
| +/**
|
| + * This class implements writing into a byte array representing a project database
|
| + *
|
| + * @author Misha Dmitriev
|
| + * 2 March 2005
|
| + */
|
| +public class BinaryProjectDatabaseWriter extends BinaryFileWriter {
|
| +
|
| + private Map<String, PCDEntry> pcd = null;
|
| + private int nOfEntries;
|
| + private byte[] stringBuf;
|
| + private int curStringBufPos, stringBufInc, curStringBufWatermark, stringCount;
|
| + private StringHashTable stringHashTable = null;
|
| +
|
| + public void writeProjectDatabaseToFile(File outfile, Map<String, PCDEntry> pcd) {
|
| + try {
|
| + byte[] buf = new BinaryProjectDatabaseWriter().writeProjectDatabase(pcd);
|
| + FileOutputStream out = new FileOutputStream(outfile);
|
| + out.write(buf);
|
| + out.close();
|
| + } catch (IOException e) {
|
| + throw new PrivateException(e);
|
| + }
|
| + }
|
| +
|
| + public byte[] writeProjectDatabase(Map<String, PCDEntry> pcd) {
|
| + this.pcd = pcd;
|
| + nOfEntries = pcd.size();
|
| +
|
| + // So far the constant here is chosen rather arbitrarily
|
| + initBuf(nOfEntries * 1000);
|
| +
|
| + stringBuf = new byte[nOfEntries * 300];
|
| + stringBufInc = stringBuf.length / 5;
|
| + curStringBufWatermark = stringBuf.length - 20;
|
| + stringHashTable = new StringHashTable(stringBuf.length / 8);
|
| +
|
| + for (PCDEntry entry : pcd.values()) {
|
| + writePCDEntry(entry);
|
| + }
|
| +
|
| + // Now we have the string buffer and the main buffer. Write the end result
|
| + byte[] mainBuf = buf;
|
| + int mainBufSize = curBufPos;
|
| + int preambleSize = Utils.MAGIC.length + 8;
|
| + int stringBufSize = curStringBufPos;
|
| + int pdbSize = stringBufSize + mainBufSize + 8; // 8 is for nOfEntries and string table size
|
| + initBuf(preambleSize + pdbSize);
|
| + setBufferIncreaseMode(false);
|
| +
|
| + writePreamble(pdbSize);
|
| + writeStringTable(stringBufSize);
|
| + System.arraycopy(mainBuf, 0, buf, curBufPos, mainBufSize);
|
| + return buf;
|
| + }
|
| +
|
| + private void writePreamble(int pdbSize) {
|
| + System.arraycopy(Utils.MAGIC, 0, buf, 0, Utils.MAGIC.length);
|
| + curBufPos += Utils.MAGIC.length;
|
| +
|
| + writeInt(Utils.PDB_FORMAT_CODE_LATEST); // Version number
|
| + writeInt(pdbSize);
|
| + writeInt(pcd.size());
|
| + }
|
| +
|
| + private void writeStringTable(int stringBufSize) {
|
| + writeInt(stringCount);
|
| + System.arraycopy(stringBuf, 0, buf, curBufPos, stringBufSize);
|
| + curBufPos += stringBufSize;
|
| + }
|
| +
|
| + private void writePCDEntry(PCDEntry entry) {
|
| + writeStringRef(entry.className);
|
| + writeStringRef(entry.javaFileFullPath);
|
| + writeLong(entry.oldClassFileLastModified);
|
| + writeLong(entry.oldClassFileFingerprint);
|
| + writeClassInfo(entry.oldClassInfo);
|
| + }
|
| +
|
| + private void writeClassInfo(ClassInfo ci) {
|
| + int i, j, len;
|
| +
|
| + writeStringRef(ci.name);
|
| + writeInt(ci.javacTargetRelease);
|
| +
|
| + len = ci.cpoolRefsToClasses != null ? ci.cpoolRefsToClasses.length : 0;
|
| + writeChar(len);
|
| + if (len > 0) {
|
| + String cpoolRefsToClasses[] = ci.cpoolRefsToClasses;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(cpoolRefsToClasses[i]);
|
| + }
|
| + boolean isRefClassArray[] = ci.isRefClassArray;
|
| + for (i = 0; i < len; i++) {
|
| + byte b = isRefClassArray[i] ? (byte) 1 : (byte) 0;
|
| + writeByte(b);
|
| + }
|
| + }
|
| +
|
| + len = ci.cpoolRefsToFieldClasses != null ? ci.cpoolRefsToFieldClasses.length
|
| + : 0;
|
| + writeChar(len);
|
| + if (len > 0) {
|
| + String cpoolRefsToFieldClasses[] = ci.cpoolRefsToFieldClasses;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(cpoolRefsToFieldClasses[i]);
|
| + }
|
| + String cpoolRefsToFieldNames[] = ci.cpoolRefsToFieldNames;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(cpoolRefsToFieldNames[i]);
|
| + }
|
| + String cpoolRefsToFieldSignatures[] = ci.cpoolRefsToFieldSignatures;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(cpoolRefsToFieldSignatures[i]);
|
| + }
|
| + }
|
| +
|
| + len = ci.cpoolRefsToMethodClasses != null ? ci.cpoolRefsToMethodClasses.length
|
| + : 0;
|
| + writeChar(len);
|
| + if (len > 0) {
|
| + String cpoolRefsToMethodClasses[] = ci.cpoolRefsToMethodClasses;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(cpoolRefsToMethodClasses[i]);
|
| + }
|
| + String cpoolRefsToMethodNames[] = ci.cpoolRefsToMethodNames;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(cpoolRefsToMethodNames[i]);
|
| + }
|
| + String cpoolRefsToMethodSignatures[] =
|
| + ci.cpoolRefsToMethodSignatures;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(cpoolRefsToMethodSignatures[i]);
|
| + }
|
| + }
|
| +
|
| + writeChar(ci.accessFlags);
|
| + byte b = ci.isNonMemberNestedClass ? (byte) 1 : (byte) 0;
|
| + writeByte(b);
|
| + if (!"java/lang/Object".equals(ci.name)) {
|
| + writeStringRef(ci.superName);
|
| + }
|
| +
|
| + len = ci.interfaces != null ? ci.interfaces.length : 0;
|
| + writeChar(len);
|
| + if (len > 0) {
|
| + String interfaces[] = ci.interfaces;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(interfaces[i]);
|
| + }
|
| + }
|
| +
|
| + len = ci.fieldNames != null ? ci.fieldNames.length : 0;
|
| + writeChar(len);
|
| + if (len > 0) {
|
| + String fieldNames[] = ci.fieldNames;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(fieldNames[i]);
|
| + }
|
| + String fieldSignatures[] = ci.fieldSignatures;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(fieldSignatures[i]);
|
| + }
|
| + char fieldAccessFlags[] = ci.fieldAccessFlags;
|
| + for (i = 0; i < len; i++) {
|
| + writeChar(fieldAccessFlags[i]);
|
| + }
|
| + }
|
| +
|
| + len = ci.primitiveConstantInitValues != null ? ci.primitiveConstantInitValues.length
|
| + : 0;
|
| + writeChar(len);
|
| + if (len > 0) {
|
| + Object primitiveConstantInitValues[] =
|
| + ci.primitiveConstantInitValues;
|
| + for (i = 0; i < len; i++) {
|
| + Object pc = primitiveConstantInitValues[i];
|
| + if (pc != null) {
|
| + if (pc instanceof String) {
|
| + writeByte((byte)1);
|
| + writeStringRef((String) pc);
|
| + } else if (pc instanceof Integer) {
|
| + writeByte((byte)2);
|
| + writeInt(((Integer) pc).intValue());
|
| + } else if (pc instanceof Long) {
|
| + writeByte((byte)3);
|
| + writeLong(((Long) pc).longValue());
|
| + } else if (pc instanceof Float) {
|
| + writeByte((byte)4);
|
| + writeFloat(((Float) pc).floatValue());
|
| + } else if (pc instanceof Double) {
|
| + writeByte((byte)5);
|
| + writeDouble(((Double) pc).doubleValue());
|
| + }
|
| + } else {
|
| + writeByte((byte)0);
|
| + }
|
| + }
|
| + }
|
| +
|
| + len = ci.methodNames != null ? ci.methodNames.length : 0;
|
| + writeChar(len);
|
| + if (len > 0) {
|
| + String methodNames[] = ci.methodNames;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(methodNames[i]);
|
| + }
|
| + String methodSignatures[] = ci.methodSignatures;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(methodSignatures[i]);
|
| + }
|
| + char methodAccessFlags[] = ci.methodAccessFlags;
|
| + for (i = 0; i < len; i++) {
|
| + writeChar(methodAccessFlags[i]);
|
| + }
|
| + }
|
| +
|
| + len = ci.checkedExceptions != null ? ci.checkedExceptions.length : 0;
|
| + writeChar(len);
|
| + if (len > 0) {
|
| + String checkedExceptions[][] = ci.checkedExceptions;
|
| + for (i = 0; i < len; i++) {
|
| + int lenl = checkedExceptions[i] != null ? checkedExceptions[i].length
|
| + : 0;
|
| + writeChar(lenl);
|
| + if (lenl > 0) {
|
| + for (j = 0; j < lenl; j++) {
|
| + writeStringRef(checkedExceptions[i][j]);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + len = ci.nestedClasses != null ? ci.nestedClasses.length : 0;
|
| + writeChar(len);
|
| + if (len > 0) {
|
| + String nestedClasses[] = ci.nestedClasses;
|
| + for (i = 0; i < len; i++) {
|
| + writeStringRef(nestedClasses[i]);
|
| + }
|
| + }
|
| + }
|
| +
|
| + private void writeString(String s) {
|
| + byte sb[] = s.getBytes();
|
| + int len = sb.length;
|
| + if (curStringBufPos + len > curStringBufWatermark) {
|
| + // May need to adapt stringBufInc
|
| + if (len >= stringBufInc) {
|
| + stringBufInc = (stringBufInc + len) * 2;
|
| + } else {
|
| + stringBufInc = (stringBufInc * 5) / 4; // Still increase a little - observations show that otherwise we usually get here 20 more times
|
| + }
|
| + byte newStringBuf[] = new byte[stringBuf.length + stringBufInc];
|
| + System.arraycopy(stringBuf, 0, newStringBuf, 0, curStringBufPos);
|
| + stringBuf = newStringBuf;
|
| + curStringBufWatermark = stringBuf.length - 20;
|
| + }
|
| + stringBuf[curStringBufPos++] = (byte) ((len >> 8) & 255);
|
| + stringBuf[curStringBufPos++] = (byte) (len & 255);
|
| + System.arraycopy(sb, 0, stringBuf, curStringBufPos, len);
|
| + curStringBufPos += len;
|
| + }
|
| +
|
| + private void writeStringRef(String s) {
|
| + int stringRef = stringHashTable.get(s);
|
| + if (stringRef == -1) {
|
| + stringHashTable.add(s, stringCount);
|
| + stringRef = stringCount;
|
| + writeString(s);
|
| + stringCount++;
|
| + }
|
| + writeInt(stringRef);
|
| + }
|
| +
|
| + /** Maps Strings to integer numbers (their positions in String table) */
|
| + static class StringHashTable {
|
| +
|
| + String keys[];
|
| + int values[];
|
| + int size, nOfElements, watermark;
|
| +
|
| + StringHashTable(int size) {
|
| + size = makeLikePrimeNumber(size);
|
| + this.size = size;
|
| + keys = new String[size];
|
| + values = new int[size];
|
| + nOfElements = 0;
|
| + watermark = size * 3 / 4;
|
| + }
|
| +
|
| + final int get(String key) {
|
| + int pos = (key.hashCode() & 0x7FFFFFFF) % size;
|
| +
|
| + while (keys[pos] != null && !keys[pos].equals(key)) {
|
| + pos = (pos + 3) % size; // Relies on the fact that size % 3 != 0
|
| + }
|
| + if (key.equals(keys[pos])) {
|
| + return values[pos];
|
| + } else {
|
| + return -1;
|
| + }
|
| + }
|
| +
|
| + final void add(String key, int value) {
|
| + if (nOfElements > watermark) {
|
| + rehash();
|
| + }
|
| +
|
| + int pos = (key.hashCode() & 0x7FFFFFFF) % size;
|
| + while (keys[pos] != null) {
|
| + pos = (pos + 3) % size; // Relies on the fact that size % 3 != 0
|
| + }
|
| + keys[pos] = key;
|
| + values[pos] = value;
|
| + nOfElements++;
|
| + }
|
| +
|
| + private final void rehash() {
|
| + String oldKeys[] = keys;
|
| + int oldValues[] = values;
|
| + int oldSize = size;
|
| + size = makeLikePrimeNumber(size * 3 / 2);
|
| + keys = new String[size];
|
| + values = new int[size];
|
| + nOfElements = 0;
|
| + watermark = size * 3 / 4;
|
| +
|
| + for (int i = 0; i < oldSize; i++) {
|
| + if (oldKeys[i] != null) {
|
| + add(oldKeys[i], oldValues[i]);
|
| + }
|
| + }
|
| + }
|
| +
|
| + private final int makeLikePrimeNumber(int no) {
|
| + no = (no / 2) * 2 + 1; // Make it an odd number
|
| + // Find the nearest "approximately prime" number
|
| + boolean prime = false;
|
| + do {
|
| + no += 2;
|
| + prime =
|
| + (no % 3 != 0 && no % 5 != 0 && no % 7 != 0 && no % 11 != 0 &&
|
| + no % 13 != 0 && no % 17 != 0 && no % 19 != 0 && no % 23 != 0 &&
|
| + no % 29 != 0 && no % 31 != 0 && no % 37 != 0 && no % 41 != 0);
|
| + } while (!prime);
|
| + return no;
|
| + }
|
| + }
|
| +}
|
|
|