diff -r 73bc69617d3d core.startup/src/org/netbeans/core/startup/layers/BinaryFS.java --- a/core.startup/src/org/netbeans/core/startup/layers/BinaryFS.java Thu Jul 21 06:34:00 2011 +0400 +++ b/core.startup/src/org/netbeans/core/startup/layers/BinaryFS.java Thu Jul 21 16:21:53 2011 +0200 @@ -71,6 +71,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.NoSuchElementException; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; @@ -157,7 +158,7 @@ urls = new ArrayList(); List _modifications = new ArrayList(); while (buff.position() < stop) { - urls.add(getString(buff)); + urls.add(getString(buff).intern()); _modifications.add(null); } modifications = Collections.synchronizedList(_modifications); @@ -240,10 +241,17 @@ } static String getString(ByteBuffer buffer) throws IOException { + return getString(buffer, false); + } + static String getString(ByteBuffer buffer, boolean skip) throws IOException { int len = buffer.getInt(); + if (skip) { + buffer.position(buffer.position() + len); + return null; + } byte[] arr = new byte[len]; buffer.get(arr); - return new String(arr, "UTF-8"); //.intern(); + return new String(arr, "UTF-8"); } @@ -267,7 +275,6 @@ // fetched fields private boolean initialized = false; - private Map attrs = Collections.emptyMap(); public BFSBase(String name, FileObject parent, int offset) { this.name = name; @@ -286,7 +293,7 @@ private final boolean attributeEquals(BFSBase base) { initialize(); base.initialize(); - return attrs.equals(base.attrs); + return seekAttrs(null).equals(base.seekAttrs(null)); } @Override @@ -377,13 +384,27 @@ @Override public Object getAttribute(String attrName) { initialize(); + + String clazz = null; + String raw = null; + List seekFor = new ArrayList(); + seekFor.add(attrName); + if (attrName.startsWith("class:")) { + seekFor.add(clazz = attrName.substring(6)); + } + if (attrName.startsWith("raw:")) { + seekFor.add(null); + seekFor.add(raw = attrName.substring(4)); + } + Map attrs = seekAttrs(seekFor); + AttrImpl attr = attrs.get(attrName); - if (attr == null && attrName.startsWith("class:")) { // NOI18N - attr = attrs.get(attrName.substring(6)); + if (attr == null && clazz != null) { + attr = attrs.get(clazz); return attr == null ? null : attr.getType(this); } - if (attr == null && attrName.startsWith("raw:")) { // NOI18N - attr = attrs.get(attrName.substring(4)); + if (attr == null && raw != null) { + attr = attrs.get(raw); try { if (attr != null && attr.index == 10) { return attr.methodValue(attr.value, this, attrName).getMethod(); @@ -421,12 +442,84 @@ } /** Get all file attribute names for this file. */ + @Override public Enumeration getAttributes() { initialize(); - if (attrs == null) { - return Enumerations.empty(); + return new AttrEnum(); + } + + private Map seekAttrs(List seekFor) { + AttrEnum en = new AttrEnum(); + if (seekFor != null) { + final int size = seekFor.size(); + Map ret = null; + while (en.hasMoreElements()) { + String n = en.nextElement(); + for (int i = 0; i < size; i++) { + String seek = seekFor.get(i); + if (seek != null && seek.equals(n)) { + if (size == 1) { + return Collections.singletonMap(seek, en.lastAttribute()); + } + if (ret == null) { + ret = new HashMap(); + } + ret.put(seek, en.lastAttribute()); + } + } + } + return ret != null ? ret : Collections.emptyMap(); + } else { + Map ret = new HashMap(); + while (en.hasMoreElements()) { + String n = en.nextElement(); + ret.put(n, en.lastAttribute()); + } + return ret; } - return Collections.enumeration(attrs.keySet()); + } + + private final class AttrEnum implements Enumeration { + private final int attrCount; + private final ByteBuffer sub; + private int pos; + private byte lastType; + private String lastValue; + + public AttrEnum() { + sub = (ByteBuffer) content.duplicate().order(ByteOrder.LITTLE_ENDIAN).position(offset); + if (!isRoot()) { + while (sub.getInt() >= 0) { + // skip URL list + } + } + attrCount = sub.getInt(); + } + + @Override + public boolean hasMoreElements() { + return pos < attrCount; + } + + @Override + public String nextElement() { + if (pos++ == attrCount) { + throw new NoSuchElementException(); + } + String attrName = null; + try { + attrName = getString(sub, false); // String attrName + lastType = sub.get(); // byte attrType + lastValue = getString(sub, false); // String attrValue + } catch (IOException iOException) { + LOG.log(Level.WARNING, "Can't read attribute", iOException); // NOI18N + } + return attrName; + } + + public AttrImpl lastAttribute() { + return new AttrImpl(lastType, lastValue); + } } /** @@ -446,17 +539,14 @@ } int attrCount = sub.getInt(); - if (attrCount > 0) attrs = new HashMap(attrCount*4/3+1); for (int i=0; i< attrCount; i++) { // do read attribute - // attribute names are highly duplicated, intern! - String attrName = getString(sub).intern(); // String attrName - byte type = sub.get(); // byte attrType + getString(sub, true); // String attrName + sub.get(); // byte attrType // values have high redundancy as well, // like "true", "JSeparator", paths to orig files from // shadow, ... - String value = getString(sub).intern(); // String attrValue - attrs.put(attrName, new AttrImpl(type, value)); + getString(sub, true); // String attrValue } doInitialize(sub);