Author: toad
Date: 2005-10-28 20:51:43 +0000 (Fri, 28 Oct 2005)
New Revision: 7463
Modified:
trunk/freenet/src/freenet/client/ArchiveManager.java
trunk/freenet/src/freenet/client/Metadata.java
trunk/freenet/src/freenet/keys/ClientCHK.java
trunk/freenet/src/freenet/keys/FreenetURI.java
Log:
It compiles.
But more work to do to get something useful.
Modified: trunk/freenet/src/freenet/client/ArchiveManager.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveManager.java 2005-10-28
19:24:06 UTC (rev 7462)
+++ trunk/freenet/src/freenet/client/ArchiveManager.java 2005-10-28
20:51:43 UTC (rev 7463)
@@ -1,5 +1,6 @@
package freenet.client;
+import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -238,9 +239,13 @@
}
Metadata metadata = new Metadata(dir);
TempStoreElement element = makeTempStoreBucket(-1);
- OutputStream os = element.bucket.getOutputStream();
- metadata.writeTo(os);
- os.close();
+ try {
+ OutputStream os = element.bucket.getOutputStream();
+ metadata.writeTo(new DataOutputStream(os));
+ os.close();
+ } catch (IOException e) {
+ throw new ArchiveFailureException("Failed to create
metadata: "+e, e);
+ }
addStoreElement(ctx, key, ".metadata", element);
}
Modified: trunk/freenet/src/freenet/client/Metadata.java
===================================================================
--- trunk/freenet/src/freenet/client/Metadata.java 2005-10-28 19:24:06 UTC
(rev 7462)
+++ trunk/freenet/src/freenet/client/Metadata.java 2005-10-28 20:51:43 UTC
(rev 7463)
@@ -3,7 +3,9 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -125,8 +127,8 @@
int len = l & 0xff; // positive
byte[] toRead = new byte[len];
dis.readFully(toRead);
- // MIME types are all ISO-8859-1, right?
- mimeType = new String(toRead);
+ // Use UTF-8 for everything, for simplicity
+ mimeType = new String(toRead, "UTF-8");
}
}
@@ -143,6 +145,7 @@
dis.readFully(buf);
Logger.normal(this, "Ignoring type "+type+"
extra-client-metadata field of "+length+" bytes");
}
+ extraMetadata = false; // can't parse, can't write
}
clientMetadata = new ClientMetadata(mimeType);
@@ -199,11 +202,11 @@
// Don't validate, just keep the data; parse later
for(int i=0;i<manifestEntryCount;i++) {
- int nameLength = (dis.readByte() & 0xff);
+ short nameLength = dis.readShort();
byte[] buf = new byte[nameLength];
dis.readFully(buf);
String name = new String(buf, "UTF-8");
- int len = dis.readInt();
+ short len = dis.readShort();
if(len < 0)
throw new
MetadataParseException("Invalid manifest entry size: "+len);
if(len > length)
@@ -215,9 +218,9 @@
}
if(documentType == ZIP_INTERNAL_REDIRECT) {
- int len = (dis.readByte() & 0xff);
+ int len = dis.readShort();
byte[] buf = new byte[len];
- nameInArchive = new String(buf);
+ nameInArchive = new String(buf, "UTF-8");
}
}
@@ -257,35 +260,65 @@
if(docType == ZIP_INTERNAL_REDIRECT) {
documentType = docType;
// Determine MIME type
- mimeType = DefaultMIMETypes.guessMIMEType(arg);
+ setMIMEType(DefaultMIMETypes.guessMIMEType(arg));
clientMetadata = new ClientMetadata(mimeType);
nameInArchive = arg;
} else
throw new IllegalArgumentException();
}
+ private void setMIMEType(String type) {
+ short s = DefaultMIMETypes.byName(type);
+ if(s >= 0) {
+ compressedMIME = true;
+ compressedMIMEValue = s;
+ } else {
+ compressedMIME = false;
+ }
+ mimeType = type;
+ }
+
private byte[] writeToByteArray() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- writeTo(baos);
+ DataOutputStream dos = new DataOutputStream(baos);
+ try {
+ writeTo(dos);
+ } catch (IOException e) {
+ throw new Error("Could not write to byte array: "+e, e);
+ }
return baos.toByteArray();
}
/**
* Read a key using the current settings.
* @throws IOException
+ * @throws MalformedURLException If the key could not be read due to an
error in parsing the key.
+ * REDFLAG: May want to recover from these in future, hence the short
length.
*/
private FreenetURI readKey(DataInputStream dis) throws IOException {
// Read URL
if(fullKeys) {
- int length = dis.readShort();
- byte[] buf = new byte[length];
- dis.readFully(buf);
- return FreenetURI.fromFullBinaryKey(buf);
+ return FreenetURI.readFullBinaryKeyWithLength(dis);
} else {
return ClientCHK.readRawBinaryKey(dis).getURI();
}
}
+ /**
+ * Write a key using the current settings.
+ * @throws IOException
+ * @throws MalformedURLException If an error in the key itself
prevented it from being written.
+ */
+ private void writeKey(DataOutputStream dos, FreenetURI freenetURI)
throws IOException {
+ if(fullKeys) {
+ freenetURI.writeFullBinaryKeyWithLength(dos);
+ } else {
+ ClientKey key = ClientKey.getBaseKey(freenetURI);
+ if(key instanceof ClientCHK) {
+ ((ClientCHK)key).writeRawBinaryKey(dos);
+ } else throw new IllegalArgumentException("Full keys
must be enabled to write non-CHKs");
+ }
+ }
// Actual parsed data
// document type
@@ -301,8 +334,8 @@
boolean splitfile;
/** Is a DBR */
boolean dbr;
- /** No MIME type */
- boolean noMIME;
+ /** No MIME type; on by default as not all doctypes have MIME */
+ boolean noMIME = true;
/** Compressed MIME type */
boolean compressedMIME;
/** Has extra client-metadata */
@@ -329,7 +362,7 @@
/** Compressed splitfile codec */
short compressionCodec;
- static final short COMPRESS_GZIP = 0;
+ static final short COMPRESS_GZIP = 0; // for future use
static final short COMPRESS_BZIP2 = 1; // FIXME for future use
/** The length of the splitfile */
@@ -464,4 +497,99 @@
public void setSimpleRedirect() {
documentType = SIMPLE_REDIRECT;
}
+
+ /** Write the metadata as binary.
+ * @throws IOException */
+ public void writeTo(DataOutputStream dos) throws IOException {
+ dos.writeLong(FREENET_METADATA_MAGIC);
+ dos.writeShort(0); // version
+ dos.writeByte(documentType);
+ if(documentType == SIMPLE_REDIRECT || documentType ==
MULTI_LEVEL_METADATA
+ || documentType == ZIP_MANIFEST) {
+ short flags = 0;
+ if(splitfile) flags |= FLAGS_SPLITFILE;
+ if(dbr) flags |= FLAGS_DBR;
+ if(noMIME) flags |= FLAGS_NO_MIME;
+ if(compressedMIME) flags |= FLAGS_COMPRESSED_MIME;
+ if(extraMetadata) flags |= FLAGS_EXTRA_METADATA;
+ if(fullKeys) flags |= FLAGS_FULL_KEYS;
+ if(splitUseLengths) flags |= FLAGS_SPLIT_USE_LENGTHS;
+ if(compressed) flags |= FLAGS_COMPRESSED;
+ }
+
+ if(documentType == ZIP_MANIFEST) {
+ dos.writeShort(archiveType);
+ }
+
+ if(splitfile) {
+ dos.writeLong(dataLength);
+ }
+
+ if(compressed) {
+ dos.writeShort(compressionCodec);
+ dos.writeLong(decompressedLength);
+ }
+
+ if(!noMIME) {
+ if(compressedMIME) {
+ int x = compressedMIMEValue;
+ if(hasCompressedMIMEParams) x |= 32768;
+ dos.writeShort((short)x);
+ if(hasCompressedMIMEParams)
+ dos.writeShort(compressedMIMEParams);
+ } else {
+ byte[] data = mimeType.getBytes("UTF-8");
+ if(data.length > 255) throw new Error("MIME
type too long: "+data.length+" bytes: "+mimeType);
+ dos.writeByte((byte)data.length);
+ dos.write(data);
+ }
+ }
+
+ if(dbr)
+ throw new UnsupportedOperationException("No DBR support
yet");
+
+ if(extraMetadata)
+ throw new UnsupportedOperationException("No extra
metadata support yet");
+
+ if((!splitfile) && documentType == SIMPLE_REDIRECT ||
documentType == ZIP_MANIFEST) {
+ writeKey(dos, simpleRedirectKey);
+ } else if(splitfile) {
+ dos.writeShort(splitfileAlgorithm);
+ if(splitfileParams != null) {
+ dos.writeInt(splitfileParams.length);
+ dos.write(splitfileParams);
+ } else
+ dos.writeInt(0);
+
+ dos.writeInt(splitfileBlocks);
+ dos.writeInt(splitfileCheckBlocks);
+ for(int i=0;i<splitfileBlocks;i++)
+ writeKey(dos, splitfileDataKeys[i]);
+ for(int i=0;i<splitfileCheckBlocks;i++)
+ writeKey(dos, splitfileCheckKeys[i]);
+ }
+
+ if(documentType == SIMPLE_MANIFEST) {
+ dos.writeInt(manifestEntryCount);
+ for(Iterator
i=manifestEntries.keySet().iterator();i.hasNext();) {
+ String name = (String) i.next();
+ byte[] nameData = name.getBytes("UTF-8");
+ if(nameData.length > Short.MAX_VALUE) throw new
IllegalArgumentException("Manifest name too long");
+ dos.writeShort(nameData.length);
+ dos.write(nameData);
+ byte[] data = (byte[])
manifestEntries.get(name);
+ if(data.length > Short.MAX_VALUE) throw new
IllegalArgumentException("Manifest data too long");
+ dos.writeShort(data.length);
+ dos.write(data);
+ }
+ }
+
+ if(documentType == ZIP_INTERNAL_REDIRECT) {
+ byte[] data = nameInArchive.getBytes("UTF-8");
+ if(data.length > Short.MAX_VALUE) throw new
IllegalArgumentException("Zip internal redirect name too long");
+ dos.writeShort(data.length);
+ dos.write(data);
+ }
+ }
+
}
Modified: trunk/freenet/src/freenet/keys/ClientCHK.java
===================================================================
--- trunk/freenet/src/freenet/keys/ClientCHK.java 2005-10-28 19:24:06 UTC
(rev 7462)
+++ trunk/freenet/src/freenet/keys/ClientCHK.java 2005-10-28 20:51:43 UTC
(rev 7463)
@@ -1,6 +1,7 @@
package freenet.keys;
import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
@@ -72,6 +73,19 @@
dis.readFully(cryptoKey);
}
+ /**
+ * Write an ultra-compact representation.
+ * @throws IOException If a write failed.
+ */
+ public void writeRawBinaryKey(DataOutputStream dos) throws IOException {
+ byte[] extra = new byte[EXTRA_LENGTH];
+ extra[0] = (byte) (cryptoAlgorithm >> 8);
+ extra[1] = (byte) cryptoAlgorithm;
+ extra[2] = (byte) ((compressed ? 1 : 0) + (controlDocument ? 2
: 0));
+ dos.write(extra);
+ dos.write(routingKey);
+ dos.write(cryptoKey);
+ }
byte[] routingKey;
byte[] cryptoKey;
Modified: trunk/freenet/src/freenet/keys/FreenetURI.java
===================================================================
--- trunk/freenet/src/freenet/keys/FreenetURI.java 2005-10-28 19:24:06 UTC
(rev 7462)
+++ trunk/freenet/src/freenet/keys/FreenetURI.java 2005-10-28 20:51:43 UTC
(rev 7463)
@@ -1,7 +1,9 @@
package freenet.keys;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.LinkedList;
@@ -401,13 +403,20 @@
static final byte CHK = 1;
static final byte SSK = 2;
+ public static FreenetURI readFullBinaryKeyWithLength(DataInputStream
dis) throws IOException {
+ int len = dis.readShort() & 0xffff;
+ byte[] buf = new byte[len];
+ dis.readFully(buf);
+ return fromFullBinaryKey(buf);
+ }
+
public static FreenetURI fromFullBinaryKey(byte[] buf) throws
IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
DataInputStream dis = new DataInputStream(bais);
- return fromFullBinaryKey(dis);
+ return readFullBinaryKey(dis);
}
- public static FreenetURI fromFullBinaryKey(DataInputStream dis) throws
IOException {
+ public static FreenetURI readFullBinaryKey(DataInputStream dis) throws
IOException {
int x = 0;
byte type = dis.readByte();
String keyType;
@@ -438,4 +447,55 @@
for(int i=0;i<metaStrings.length;i++) metaStrings[i] =
dis.readUTF();
return new FreenetURI(keyType, docName, metaStrings,
routingKey, cryptoKey, extra);
}
+
+ /**
+ * Write a binary representation of this URI, with a short length, so
it can be passed over if necessary.
+ * @param dos The stream to write to.
+ * @throws MalformedURLException If the key could not be written
because of inconsistencies or other
+ * problems in the key itself.
+ * @throws IOException If an error occurred while writing the key.
+ */
+ public void writeFullBinaryKeyWithLength(DataOutputStream dos) throws
IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream ndos = new DataOutputStream(baos);
+ writeFullBinaryKey(ndos);
+ ndos.close();
+ byte[] data = baos.toByteArray();
+ if(data.length > 0xffff)
+ throw new MalformedURLException("Full key too long:
"+data.length+" - "+this);
+ dos.writeShort((short)data.length);
+ dos.write(data);
+ }
+
+ /**
+ * Write a binary representation of this URI.
+ * @param dos The stream to write to.
+ * @throws MalformedURLException If the key could not be written
because of inconsistencies or other
+ * problems in the key itself.
+ * @throws IOException If an error occurred while writing the key.
+ */
+ private void writeFullBinaryKey(DataOutputStream dos) throws
IOException {
+ if(keyType.equals("CHK")) {
+ dos.writeByte(CHK);
+ } else if(keyType.equals("SSK")) {
+ dos.writeByte(SSK);
+ } else
+ throw new MalformedURLException("Cannot write key of
type "+keyType+" - do not know how");
+ if(routingKey.length != 32)
+ throw new MalformedURLException("Routing key must be of
length 32");
+ if(cryptoKey.length != 32)
+ throw new MalformedURLException("Crypto key must be of
length 32");
+ if(keyType.equals("CHK") && extra.length !=
ClientCHK.EXTRA_LENGTH)
+ throw new MalformedURLException("Wrong number of extra
bytes for CHK");
+ if(keyType.equals("SSK"))
+ throw new UnsupportedOperationException("SSK support
not yet implemented");
+ dos.write(extra);
+ dos.writeUTF(docName);
+ if(metaStr != null) {
+ dos.writeInt(metaStr.length);
+ for(int i=0;i<metaStr.length;i++)
+ dos.writeUTF(metaStr[i]);
+ } else
+ dos.writeInt(0);
+ }
}