Another manifest parser from Karl; looks a little faster. (FELIX-2721)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1052398 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java b/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
index 18d4bc4..6a7eb79 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
@@ -18,16 +18,14 @@
*/
package org.apache.felix.framework.cache;
-import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
-import java.util.HashMap;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import org.apache.felix.framework.Logger;
@@ -105,12 +103,11 @@
public Map getManifestHeader() throws Exception
{
- // Get the embedded resource.
- Map headers = getMainAttributes(m_zipFile);
- // Use an empty map if there is no manifest.
- headers = (headers == null) ? new HashMap() : headers;
// Create a case insensitive map of manifest attributes.
- return new StringMap(headers, false);
+ Map headers = new StringMap(false);
+ // Read and parse headers.
+ getMainAttributes(headers, m_zipFile);
+ return headers;
}
public synchronized Content getContent() throws Exception
@@ -195,133 +192,101 @@
}
}
- private static int readLine(InputStream is, byte[] buf) throws IOException
+ private static final ThreadLocal m_defaultBuffer = new ThreadLocal();
+ private static final int DEFAULT_BUFFER = 1024 * 64;
+
+ private static void getMainAttributes(Map result, ZipFileX zipFile) throws Exception
{
- for (int i = 0; i < buf.length; i++)
+ ZipEntry entry = zipFile.getEntry("META-INF/MANIFEST.MF");
+ SoftReference ref = (SoftReference) m_defaultBuffer.get();
+ byte[] bytes = null;
+ if (ref != null)
{
- int b = is.read();
- if (b < 0)
- {
- return (i == 0) ? -1 : i;
- }
- else
- {
- buf[i] = (byte) b;
- if (buf[i] == '\n')
- {
- return i + 1;
- }
- }
+ bytes = (byte[]) ref.get();
}
- return 0;
- }
+ int size = (int) entry.getSize();
+ if (bytes == null)
+ {
+ bytes = new byte[size > DEFAULT_BUFFER ? size : DEFAULT_BUFFER];
+ m_defaultBuffer.set(new SoftReference(bytes));
+ }
+ else if (size > bytes.length)
+ {
+ bytes = new byte[size];
+ m_defaultBuffer.set(new SoftReference(bytes));
+ }
- private static Map<String, String> getMainAttributes(ZipFileX zipFile) throws IOException
- {
- Map<String, String> mainAttrs = new HashMap<String, String>();
- Map<String, byte[]> tmpMap = new HashMap<String, byte[]>();
-
- byte[] buf = new byte[512];
- ZipEntry ze = zipFile.getEntry("META-INF/MANIFEST.MF");
- InputStream is = new BufferedInputStream(zipFile.getInputStream(ze));
- String lastName = null;
+ InputStream is = null;
try
{
- for (int len = readLine(is, buf); len != -1; len = readLine(is, buf))
+ is = zipFile.getInputStream(entry);
+ int i = is.read(bytes);
+ while (i < size)
{
- // Make sure line ends with a line feed.
- if (buf[len - 1] != '\n')
- {
- throw new IOException(
- "Manifest error: Line either too long or no line feed - "
- + new String(buf, 0, 0, len));
- }
-
- // Ignore line feed.
- len--;
-
- // If line ends with carriage return, ignore it.
- if ((len > 0) && (buf[len - 1] == '\r'))
- {
- len--;
- }
-
- // If line is empty, then we've reached the end
- // of the main attributes group.
- if (len == 0)
- {
- break;
- }
-
- // Check if this is a continuation line. If so, read the
- // entire line and add it to the previous line value.
- if (buf[0] == ' ')
- {
- if (lastName == null)
- {
- throw new IOException(
- "Manifest syntax: Invalid line continuation - "
- + new String(buf, 0, 0, len));
- }
- byte[] lastValue = tmpMap.get(lastName);
- byte[] tmp = new byte[lastValue.length + len - 1];
- System.arraycopy(lastValue, 0, tmp, 0, lastValue.length);
- System.arraycopy(buf, 1, tmp, lastValue.length, len - 1);
- tmpMap.put(lastName, tmp);
- }
- // Otherwise, try to find the attribute name and its value.
- else
- {
- for (int i = 0; i < len; i++)
- {
- // If we are at the end, then this must be an error.
- if (i == (len - 1))
- {
- throw new IOException(
- "Manifest syntax: Invalid attribute name - "
- + new String(buf, 0, 0, len));
- }
- // We found the end of the attribute name
- else if (buf[i] == ':')
- {
- // Make sure the header has a space separator.
- if (buf[i + 1] != ' ')
- {
- throw new IOException(
- "Manifest syntax: Header space separator missing - "
- + new String(buf, 0, 0, len));
- }
- // Convert attribute name to a string.
- lastName = new String(buf, 0, 0, i);
- byte[] tmp = new byte[len - i - 2];
- System.arraycopy(buf, i + 2, tmp, 0, len - i - 2);
- byte[] old = tmpMap.put(lastName, tmp);
- if (old != null)
- {
- throw new IllegalArgumentException(
- "Manifest syntax: Duplicate header - "
- + new String(buf, 0, 0, len));
- }
- break;
- }
- }
- }
+ i += is.read(bytes, i, bytes.length - i);
}
-
- for (Entry<String, byte[]> entry : tmpMap.entrySet())
- {
- byte[] value = entry.getValue();
- mainAttrs.put(
- entry.getKey(),
- new String(value, 0, value.length, "UTF8"));
- }
-
}
finally
{
is.close();
}
- return mainAttrs;
+ String key = null;
+ int last = 0;
+ int current = 0;
+ for (int i = 0; i < size; i++)
+ {
+ if (bytes[i] == '\r')
+ {
+ if ((i + 1 < size) && (bytes[i + 1] == '\n'))
+ {
+ continue;
+ }
+ }
+ if (bytes[i] == '\n')
+ {
+ if ((i + 1 < size) && (bytes[i + 1] == ' '))
+ {
+ i++;
+ continue;
+ }
+ }
+ if ((key == null) && (bytes[i] == ':'))
+ {
+ key = new String(bytes, last, (current - last), "UTF-8");
+ if ((i + 1 < size) && (bytes[i + 1] == ' '))
+ {
+ last = current + 1;
+ continue;
+ }
+ else
+ {
+ throw new Exception(
+ "Manifest error: Missing space separator - " + key);
+ }
+ }
+ if (bytes[i] == '\n')
+ {
+ if ((last == current) && (key == null))
+ {
+ break;
+ }
+ String value = new String(bytes, last, (current - last), "UTF-8");
+ if (key == null)
+ {
+ throw new Exception("Manifst error: Missing attribute name - " + value);
+ }
+ else if (result.put(key, value) != null)
+ {
+ throw new Exception("Manifst error: Duplicate attribute name - " + key);
+ }
+ last = current;
+ key = null;
+ }
+ else
+ {
+ bytes[current++] = bytes[i];
+ }
+ }
}
}
\ No newline at end of file