Author: toad
Date: 2005-11-11 17:46:41 +0000 (Fri, 11 Nov 2005)
New Revision: 7526

Modified:
   trunk/freenet/src/freenet/client/BlockFetcher.java
   trunk/freenet/src/freenet/client/BlockInserter.java
   trunk/freenet/src/freenet/client/FECCodec.java
   trunk/freenet/src/freenet/client/InsertSegment.java
   trunk/freenet/src/freenet/client/RetryTracker.java
   trunk/freenet/src/freenet/client/SplitInserter.java
   trunk/freenet/src/freenet/client/StandardOnionFECCodec.java
   trunk/freenet/src/freenet/client/StdSplitfileBlock.java
   trunk/freenet/src/freenet/keys/ClientCHKBlock.java
   trunk/freenet/src/freenet/node/TextModeClientInterface.java
   trunk/freenet/src/freenet/node/Version.java
   trunk/freenet/src/freenet/support/Fields.java
   trunk/freenet/src/org/spaceroots/mantissa/random/MersenneTwister.java
Log:
162:
Insertion of splitfiles of more than one segment is working.
FEC encoding is at least partially working.

Modified: trunk/freenet/src/freenet/client/BlockFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/BlockFetcher.java  2005-11-11 15:55:56 UTC 
(rev 7525)
+++ trunk/freenet/src/freenet/client/BlockFetcher.java  2005-11-11 17:46:41 UTC 
(rev 7526)
@@ -16,7 +16,7 @@
        boolean actuallyFetched;

        public BlockFetcher(Segment segment, RetryTracker tracker, FreenetURI 
freenetURI, int index, boolean dontEnterImplicitArchives) {
-               super(tracker, index);
+               super(tracker, index, null);
                this.segment = segment;
                uri = freenetURI;
                completedTries = 0;

Modified: trunk/freenet/src/freenet/client/BlockInserter.java
===================================================================
--- trunk/freenet/src/freenet/client/BlockInserter.java 2005-11-11 15:55:56 UTC 
(rev 7525)
+++ trunk/freenet/src/freenet/client/BlockInserter.java 2005-11-11 17:46:41 UTC 
(rev 7526)
@@ -23,9 +23,7 @@
         * @param num The block number in the splitfile.
         */
        public BlockInserter(Bucket bucket, int num, RetryTracker tracker, 
InserterContext ctx, boolean getCHKOnly) {
-               super(tracker, num);
-               this.data = bucket;
-               if(bucket == null) throw new NullPointerException();
+               super(tracker, num, bucket);
                succeeded = false;
                this.ctx = ctx;
                block = new InsertBlock(bucket, null, FreenetURI.EMPTY_CHK_URI);
@@ -33,8 +31,7 @@
        }

        public synchronized void setData(Bucket data) {
-               if(this.data != null) throw new 
IllegalArgumentException("Cannot set data when already have data");
-               this.data = data;
+               if(this.fetchedData != null) throw new 
IllegalArgumentException("Cannot set data when already have data");
        }

        public void kill() {

Modified: trunk/freenet/src/freenet/client/FECCodec.java
===================================================================
--- trunk/freenet/src/freenet/client/FECCodec.java      2005-11-11 15:55:56 UTC 
(rev 7525)
+++ trunk/freenet/src/freenet/client/FECCodec.java      2005-11-11 17:46:41 UTC 
(rev 7526)
@@ -49,8 +49,7 @@
                if(splitfileType == Metadata.SPLITFILE_NONREDUNDANT)
                        return null;
                if(splitfileType == Metadata.SPLITFILE_ONION_STANDARD) {
-                       int checkBlocks = dataBlocks;
-                       checkBlocks += (dataBlocks>>1);
+                       int checkBlocks = (dataBlocks>>1);
                        if((dataBlocks & 1) == 1) checkBlocks++;
                        return StandardOnionFECCodec.getInstance(dataBlocks, 
checkBlocks);
                }
@@ -61,6 +60,9 @@
         * Decode all missing *data* blocks.
         * Requires that the total number of available blocks is equal to or 
greater than the length of
         * the data blocks array. (i.e. it is > k).
+        * Note that the last data bucket may be returned padded.
+        * This is one reason why it is important to set the data length,
+        * and truncate to it, when using FEC codes.
         * @param dataBlockStatus The data blocks.
         * @param checkBlockStatus The check blocks.
         * @param blockLength The block length in bytes.

Modified: trunk/freenet/src/freenet/client/InsertSegment.java
===================================================================
--- trunk/freenet/src/freenet/client/InsertSegment.java 2005-11-11 15:55:56 UTC 
(rev 7525)
+++ trunk/freenet/src/freenet/client/InsertSegment.java 2005-11-11 17:46:41 UTC 
(rev 7526)
@@ -4,6 +4,7 @@

 import freenet.keys.FreenetURI;
 import freenet.support.BucketFactory;
+import freenet.support.Logger;

 /**
  * Segment of a splitfile, for insertion purposes.
@@ -17,14 +18,20 @@
        /** Check blocks. Will be created by encode(...). */
        final SplitfileBlock[] checkBlocks;
        final boolean getCHKOnly;
+       // just for debugging
+       final int segNo;

-       public InsertSegment(short splitfileAlgo, SplitfileBlock[] 
origDataBlocks, int blockLength, BucketFactory bf, boolean getCHKOnly) {
+       public InsertSegment(short splitfileAlgo, SplitfileBlock[] 
origDataBlocks, int blockLength, BucketFactory bf, boolean getCHKOnly, int 
segNo) {
                this.origDataBlocks = origDataBlocks;
                codec = FECCodec.getCodec(splitfileAlgo, origDataBlocks.length);
                checkBlocks = new SplitfileBlock[codec.countCheckBlocks()];
                this.blockLength = blockLength;
                this.bf = bf;
                this.getCHKOnly = getCHKOnly;
+               this.segNo = segNo;
+               // FIXME: remove debugging code
+               for(int i=0;i<origDataBlocks.length;i++)
+                       if(origDataBlocks[i].getData() == null) throw new 
NullPointerException("Block "+i+" of "+origDataBlocks.length+" data blocks of 
seg "+segNo+" is null");
        }

        /**
@@ -46,6 +53,7 @@
         * @throws IOException If the encode fails due to a bucket error.
         */
        public int encode(int offset, RetryTracker tracker, InserterContext 
ctx) throws IOException {
+               Logger.minor(this, "Encoding "+segNo+": 
"+origDataBlocks.length+" into "+checkBlocks.length);
                if(codec == null) return 0; // no FEC
                for(int i=0;i<checkBlocks.length;i++)
                        checkBlocks[i] = new BlockInserter(null, offset + i, 
tracker, ctx, getCHKOnly);

Modified: trunk/freenet/src/freenet/client/RetryTracker.java
===================================================================
--- trunk/freenet/src/freenet/client/RetryTracker.java  2005-11-11 15:55:56 UTC 
(rev 7525)
+++ trunk/freenet/src/freenet/client/RetryTracker.java  2005-11-11 17:46:41 UTC 
(rev 7526)
@@ -2,6 +2,7 @@

 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Vector;

 import freenet.crypt.RandomSource;
@@ -67,6 +68,7 @@
         * even if there are threads running and blocks queued. */
        final int targetSuccesses;
        final boolean killOnFatalError;
+       private boolean killed;
        private boolean finishOnEmpty;
        private final RetryTrackerCallback callback;

@@ -159,6 +161,7 @@
         * Add a block at retry level zero.
         */
        public synchronized void addBlock(SplitfileBlock block) {
+               if(killed) return;
                Level l = makeLevel(0);
                l.add(block);
                maybeStart(true);
@@ -170,6 +173,7 @@
         * we have run out of retries.
         */
        public synchronized void nonfatalError(SplitfileBlock block, int 
reasonCode) {
+               if(killed) return;
                nonfatalErrors.inc(reasonCode);
                runningBlocks.remove(block);
                int levelNumber = block.getRetryCount();
@@ -190,6 +194,7 @@
         * @param reasonCode A client-specific code indicating the type of 
failure.
         */
        public synchronized void fatalError(SplitfileBlock block, int 
reasonCode) {
+               if(killed) return;
                fatalErrors.inc(reasonCode);
                runningBlocks.remove(block);
                failedBlocksFatalErrors.add(block);
@@ -201,6 +206,7 @@
         * Otherwise if we are finished, call the callback's finish method.
         */
        public synchronized void maybeStart(boolean cantCallFinished) {
+               if(killed) return;
                Logger.minor(this, "succeeded: "+succeededBlocks.size()+", 
target: "+targetSuccesses+
                                ", running: "+runningBlocks.size()+", levels: 
"+levels.size()+", finishOnEmpty: "+finishOnEmpty);
                if(runningBlocks.size() == 1)
@@ -232,6 +238,7 @@
        }

        public synchronized void success(SplitfileBlock block) {
+               if(killed) return;
                runningBlocks.remove(block);
                succeededBlocks.add(block);
                maybeStart(false);
@@ -242,6 +249,7 @@
         * lowest priority currently available. Move it into the running list.
         */
        public synchronized SplitfileBlock getBlock() {
+               if(killed) return null;
                Level l = (Level) levels.get(new Integer(curMinLevel));
                if(l == null) {
                        if(!levels.isEmpty()) {
@@ -325,4 +333,14 @@
        public FailureCodeTracker getAccumulatedNonFatalErrorCodes() {
                return nonfatalErrors;
        }
+
+       public synchronized void kill() {
+               killed = true;
+               levels.clear();
+               for(Iterator i=runningBlocks.iterator();i.hasNext();) {
+                       SplitfileBlock sb = (SplitfileBlock) i.next();
+                       sb.kill();
+               }
+               runningBlocks.clear();
+       }
 }

Modified: trunk/freenet/src/freenet/client/SplitInserter.java
===================================================================
--- trunk/freenet/src/freenet/client/SplitInserter.java 2005-11-11 15:55:56 UTC 
(rev 7525)
+++ trunk/freenet/src/freenet/client/SplitInserter.java 2005-11-11 17:46:41 UTC 
(rev 7526)
@@ -7,6 +7,7 @@
 import freenet.keys.NodeCHK;
 import freenet.support.Bucket;
 import freenet.support.BucketTools;
+import freenet.support.Logger;
 import freenet.support.compress.Compressor;

 /**
@@ -27,7 +28,6 @@
        SplitfileBlock[] origDataBlocks;
        InsertSegment encodingSegment;
        InsertSegment[] segments;
-       final Vector unstartedSegments = new Vector();
        private boolean finishedInserting = false;
        private boolean getCHKOnly;
        private int succeeded;
@@ -66,18 +66,25 @@
         * @throws InserterException If we are not able to insert the splitfile.
         */
        public FreenetURI run() throws InserterException {
-               startInsertingDataBlocks();
-               splitIntoSegments(segmentSize);
-               // Backwards, because the last is the shortest
                try {
-                       for(int i=segments.length-1;i>=0;i--) {
-                               countCheckBlocks += encodeSegment(i, 
origDataBlocks.length + checkSegmentSize * i);
+                       startInsertingDataBlocks();
+                       splitIntoSegments(segmentSize);
+                       // Backwards, because the last is the shortest
+                       try {
+                               for(int i=segments.length-1;i>=0;i--) {
+                                       countCheckBlocks += encodeSegment(i, 
origDataBlocks.length + checkSegmentSize * i);
+                                       Logger.minor(this, "Encoded segment 
"+i+" of "+segments.length);
+                               }
+                       } catch (IOException e) {
+                               throw new 
InserterException(InserterException.BUCKET_ERROR, e);
                        }
-               } catch (IOException e) {
-                       throw new 
InserterException(InserterException.BUCKET_ERROR);
+                       // Wait for the insertion thread to finish
+                       return waitForCompletion();
+               } catch (Throwable t) {
+                       Logger.error(this, "Caught "+t, t);
+                       tracker.kill();
+                       throw new 
InserterException(InserterException.INTERNAL_ERROR, t.toString());
                }
-               // Wait for the insertion thread to finish
-               return waitForCompletion();
        }

        private FreenetURI waitForCompletion() throws InserterException {
@@ -190,6 +197,8 @@
                origDataBlocks = new SplitfileBlock[dataBuckets.length];
                for(int i=0;i<origDataBlocks.length;i++) {
                        origDataBlocks[i] = new BlockInserter(dataBuckets[i], 
i, tracker, ctx, getCHKOnly);
+                       if(origDataBlocks[i].getData() == null)
+                               throw new NullPointerException("Block "+i+" of 
"+dataBuckets.length+" is null");
                }
        }

@@ -204,21 +213,24 @@
                // First split the data up
                if(dataBlocks < segmentSize || segmentSize == -1) {
                        // Single segment
-                       InsertSegment onlySeg = new 
InsertSegment(splitfileAlgorithm, origDataBlocks, blockSize, ctx.bf, 
getCHKOnly);
+                       InsertSegment onlySeg = new 
InsertSegment(splitfileAlgorithm, origDataBlocks, blockSize, ctx.bf, 
getCHKOnly, 0);
                        segs.add(onlySeg);
                } else {
                        int j = 0;
+                       int segNo = 0;
                        for(int i=segmentSize;;i+=segmentSize) {
                                if(i > dataBlocks) i = dataBlocks;
                                SplitfileBlock[] seg = new SplitfileBlock[i-j];
                                System.arraycopy(origDataBlocks, j, seg, 0, 
i-j);
-                               unstartedSegments.add(seg);
                                j = i;
-                               segs.add(new InsertSegment(splitfileAlgorithm, 
seg, blockSize, ctx.bf, getCHKOnly));
+                               for(int x=0;x<seg.length;x++)
+                                       if(seg[x].getData() == null) throw new 
NullPointerException("In splitIntoSegs: "+x+" is null of "+seg.length+" of 
"+segNo);
+                               segs.add(new InsertSegment(splitfileAlgorithm, 
seg, blockSize, ctx.bf, getCHKOnly, segNo));
                                if(i == dataBlocks) break;
+                               segNo++;
                        }
                }
-               segments = (InsertSegment[]) unstartedSegments.toArray(new 
InsertSegment[unstartedSegments.size()]);
+               segments = (InsertSegment[]) segs.toArray(new 
InsertSegment[segs.size()]);
        }

        public void finished(SplitfileBlock[] succeeded, SplitfileBlock[] 
failed, SplitfileBlock[] fatalErrors) {

Modified: trunk/freenet/src/freenet/client/StandardOnionFECCodec.java
===================================================================
--- trunk/freenet/src/freenet/client/StandardOnionFECCodec.java 2005-11-11 
15:55:56 UTC (rev 7525)
+++ trunk/freenet/src/freenet/client/StandardOnionFECCodec.java 2005-11-11 
17:46:41 UTC (rev 7526)
@@ -4,12 +4,16 @@
 import java.io.IOException;
 import java.io.OutputStream;

+import org.spaceroots.mantissa.random.MersenneTwister;
+
 import com.onionnetworks.fec.DefaultFECCodeFactory;
 import com.onionnetworks.fec.FECCode;
+import com.onionnetworks.fec.PureCode;
 import com.onionnetworks.util.Buffer;

 import freenet.support.Bucket;
 import freenet.support.BucketFactory;
+import freenet.support.BucketTools;
 import freenet.support.LRUHashtable;
 import freenet.support.Logger;

@@ -74,11 +78,13 @@
                this.k = k;
                this.n = n;
                code = DefaultFECCodeFactory.getDefault().createFECCode(k,n);
+               // revert to below if above causes JVM crashes
+               //code = new PureCode(k,n);
        }

        private static Object runningDecodesSync = new Object();
        private static int runningDecodes;
-       
+
        public void decode(SplitfileBlock[] dataBlockStatus, SplitfileBlock[] 
checkBlockStatus, int blockLength, BucketFactory bf) throws IOException {
                // Ensure that there are only K simultaneous running decodes.
                synchronized(runningDecodesSync) {
@@ -120,6 +126,14 @@

                for(int i=0;i<dataBlockStatus.length;i++) {
                        buckets[i] = dataBlockStatus[i].getData();
+                       long sz = buckets[i].size();
+                       if(sz < blockLength) {
+                               if(i != dataBlockStatus.length-1)
+                                       throw new IllegalArgumentException("All 
buckets except the last must be the full size");
+                               if(sz < blockLength)
+                                       buckets[i] = pad(buckets[i], 
blockLength, bf, (int) sz);
+                               else throw new IllegalArgumentException("Too 
big: "+sz+" bigger than "+blockLength);
+                       }
                        if(buckets[i] == null) {
                                buckets[i] = bf.makeBucket(blockLength);
                                writers[i] = buckets[i].getOutputStream();
@@ -174,6 +188,7 @@
                        if(readers[i] != null) readers[i].close();
                }
                // Set new buckets only after have a successful decode.
+               // Note that the last data bucket will be overwritten padded.
                for(int i=0;i<dataBlockStatus.length;i++) {
                        dataBlockStatus[i].setData(buckets[i]);
                }
@@ -207,6 +222,7 @@
         * Do the actual encode.
         */
        private void realEncode(SplitfileBlock[] dataBlockStatus, 
SplitfileBlock[] checkBlockStatus, int blockLength, BucketFactory bf) throws 
IOException {
+               System.err.println("************* Encoding 
"+dataBlockStatus.length+" -> "+checkBlockStatus.length+"... *************");
                Logger.minor(this, "Doing encode: "+dataBlockStatus.length+" 
data blocks, "+checkBlockStatus.length+" check blocks, block length 
"+blockLength+" with "+this);
                if(dataBlockStatus.length + checkBlockStatus.length != n)
                        throw new IllegalArgumentException();
@@ -229,18 +245,25 @@

                for(int i=0;i<dataBlockStatus.length;i++) {
                        buckets[i] = dataBlockStatus[i].getData();
+                       long sz = buckets[i].size();
+                       if(sz < blockLength) {
+                               if(i != dataBlockStatus.length-1)
+                                       throw new IllegalArgumentException("All 
buckets except the last must be the full size");
+                               if(sz < blockLength)
+                                       buckets[i] = pad(buckets[i], 
blockLength, bf, (int) sz);
+                               else throw new IllegalArgumentException("Too 
big: "+sz+" bigger than "+blockLength);
+                       }
                        readers[i] = new 
DataInputStream(buckets[i].getInputStream());
                }
+               
                for(int i=0;i<checkBlockStatus.length;i++) {
                        buckets[i+k] = checkBlockStatus[i].getData();
                        if(buckets[i+k] == null) {
                                buckets[i+k] = bf.makeBucket(blockLength);
-                               writers[i+k] = buckets[i+k].getOutputStream();
-                               readers[i+k] = null;
+                               writers[i] = buckets[i+k].getOutputStream();
                                toEncode[numberToEncode++] = i+k;
                        } else {
-                               writers[i+k] = null;
-                               readers[i+k] = new 
DataInputStream(buckets[i+k].getInputStream());
+                               writers[i] = null;
                        }
                }

@@ -248,7 +271,7 @@
                        // Do the (striped) decode
                        for(int 
offset=0;offset<blockLength;offset+=STRIPE_SIZE) {
                                // Read the data in first
-                               for(int i=0;i<n;i++) {
+                               for(int i=0;i<k;i++) {
                                        readers[i].readFully(realBuffer, 
i*STRIPE_SIZE, STRIPE_SIZE);
                                }
                                // Do the encode
@@ -257,8 +280,8 @@
                                // packets now contains an array of decoded 
blocks, in order
                                // Write the data out
                                for(int i=k;i<n;i++) {
-                                       if(writers[i] != null)
-                                               writers[i].write(realBuffer, 
i*STRIPE_SIZE, STRIPE_SIZE);
+                                       if(writers[i-k] != null)
+                                               writers[i-k].write(realBuffer, 
i*STRIPE_SIZE, STRIPE_SIZE);
                                }
                        }
                }
@@ -270,8 +293,29 @@
                for(int i=0;i<checkBlockStatus.length;i++) {
                        checkBlockStatus[i].setData(buckets[i+k]);
                }
+               System.err.println("************* Encoded 
"+dataBlockStatus.length+" -> "+checkBlockStatus.length+"... *************");
        }

+       private Bucket pad(Bucket oldData, int blockLength, BucketFactory bf, 
int l) throws IOException {
+               // FIXME move somewhere else?
+               byte[] hash = BucketTools.hash(oldData);
+               Bucket b = bf.makeBucket(blockLength);
+               MersenneTwister mt = new MersenneTwister(hash);
+               OutputStream os = b.getOutputStream();
+               BucketTools.copyTo(oldData, os, l);
+               byte[] buf = new byte[4096];
+               for(int x=l;x<blockLength;) {
+                       int remaining = blockLength - x;
+                       int thisCycle = Math.min(remaining, buf.length);
+                       mt.nextBytes(buf); // FIXME??
+                       os.write(buf, 0, thisCycle);
+               }
+               os.close();
+               if(b.size() != blockLength)
+                       throw new IllegalStateException();
+               return b;
+       }
+
        public int countCheckBlocks() {
                return n-k;
        }

Modified: trunk/freenet/src/freenet/client/StdSplitfileBlock.java
===================================================================
--- trunk/freenet/src/freenet/client/StdSplitfileBlock.java     2005-11-11 
15:55:56 UTC (rev 7525)
+++ trunk/freenet/src/freenet/client/StdSplitfileBlock.java     2005-11-11 
17:46:41 UTC (rev 7526)
@@ -9,12 +9,12 @@
        protected final RetryTracker tracker;
        /** Splitfile index - [0,k[ is the data blocks, [k,n[ is the check 
blocks */
        protected final int index;
-       protected Bucket data;

-       public StdSplitfileBlock(RetryTracker tracker2, int index2) {
+       public StdSplitfileBlock(RetryTracker tracker2, int index2, Bucket 
data) {
                if(tracker2 == null) throw new NullPointerException();
                this.tracker = tracker2;
                this.index = index2;
+               this.fetchedData = data;
        }

        public int getNumber() {

Modified: trunk/freenet/src/freenet/keys/ClientCHKBlock.java
===================================================================
--- trunk/freenet/src/freenet/keys/ClientCHKBlock.java  2005-11-11 15:55:56 UTC 
(rev 7525)
+++ trunk/freenet/src/freenet/keys/ClientCHKBlock.java  2005-11-11 17:46:41 UTC 
(rev 7526)
@@ -156,16 +156,7 @@
             if(finalData.length != 0)
                md256.update(finalData);
             byte[] digest = md256.digest();
-            // Turn digest into a seed array for the MT
-            int[] seed = new int[8]; // 32/4=8
-            for(int i=0;i<8;i++) {
-                int x = digest[i*4] & 0xff;
-                x = (x << 8) + (digest[i*4+1] & 0xff);
-                x = (x << 8) + (digest[i*4+2] & 0xff);
-                x = (x << 8) + (digest[i*4+3] & 0xff);
-                seed[i] = x;
-            }
-            MersenneTwister mt = new MersenneTwister(seed);
+            MersenneTwister mt = new MersenneTwister(digest);
             data = new byte[32768];
             System.arraycopy(finalData, 0, data, 0, finalData.length);
             byte[] randomBytes = new byte[32768-finalData.length];

Modified: trunk/freenet/src/freenet/node/TextModeClientInterface.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterface.java 2005-11-11 
15:55:56 UTC (rev 7525)
+++ trunk/freenet/src/freenet/node/TextModeClientInterface.java 2005-11-11 
17:46:41 UTC (rev 7526)
@@ -253,9 +253,9 @@
             } catch (FileNotFoundException e1) {
                 System.out.println("File not found");
             } catch (InserterException e) {
-               System.out.println(e.getMessage());
+               System.out.println("Finished insert but: "+e.getMessage());
             } catch (Throwable t) {
-                System.out.println("Threw: "+t);
+                System.out.println("Insert threw: "+t);
                 t.printStackTrace();
             }
         } else if(uline.startsWith("STATUS")) {

Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2005-11-11 15:55:56 UTC (rev 
7525)
+++ trunk/freenet/src/freenet/node/Version.java 2005-11-11 17:46:41 UTC (rev 
7526)
@@ -20,10 +20,10 @@
        public static final String protocolVersion = "1.0";

        /** The build number of the current revision */
-       public static final int buildNumber = 161;
+       public static final int buildNumber = 162;

        /** Oldest build of Fred we will talk to */
-       public static final int lastGoodBuild = 159;
+       public static final int lastGoodBuild = 162;

        /** The highest reported build of fred */
        public static int highestSeenBuild = buildNumber;

Modified: trunk/freenet/src/freenet/support/Fields.java
===================================================================
--- trunk/freenet/src/freenet/support/Fields.java       2005-11-11 15:55:56 UTC 
(rev 7525)
+++ trunk/freenet/src/freenet/support/Fields.java       2005-11-11 17:46:41 UTC 
(rev 7526)
@@ -488,6 +488,19 @@
         return x;
     }

+    /**
+     * Convert an array of bytes to a single int.
+     */
+       public static int bytesToInt(byte[] buf, int offset) {
+        if(buf.length < 4) throw new IllegalArgumentException();
+        int x = 0;
+        for(int j=3;j>=0;j--) {
+            int y = (buf[j+offset] & 0xff);
+            x = (x << 8) + y;
+        }
+        return x;
+       }
+       
     public static byte[] longToBytes(long x) {
         byte[] buf = new byte[8];
         for(int j=0;j<8;j++) {
@@ -496,4 +509,5 @@
         }
         return buf;
     }
+
 }

Modified: trunk/freenet/src/org/spaceroots/mantissa/random/MersenneTwister.java
===================================================================
--- trunk/freenet/src/org/spaceroots/mantissa/random/MersenneTwister.java       
2005-11-11 15:55:56 UTC (rev 7525)
+++ trunk/freenet/src/org/spaceroots/mantissa/random/MersenneTwister.java       
2005-11-11 17:46:41 UTC (rev 7526)
@@ -2,6 +2,8 @@

 import java.util.Random;

+import freenet.support.Fields;
+
 /** This class implements a powerful pseudo-random number generator
  * developed by Makoto Matsumoto and Takuji Nishimura during
  * 1996-1997.
@@ -97,6 +99,12 @@
     setSeed(seed);
   }

+  /** Seed from byte[] */
+  public MersenneTwister(byte[] seed) {
+       mt = new int[N];
+       setSeed(seed);
+  }
+  
   /** Creates a new random number generator using a single long seed.
    * @param seed the initial seed (64 bits integer)
    */
@@ -122,6 +130,17 @@
     }
   }

+  /**
+   * Seed from byte[].
+   */
+  public void setSeed(byte[] seed) {
+         int[] seeds = new int[seed.length/4];
+         for(int i=0;i<seeds.length;i+=4) {
+                 seeds[i] = Fields.bytesToInt(seed, i);
+         }
+         setSeed(seeds);
+  }
+  
   /** Reinitialize the generator as if just built with the given int array 
seed.
    * <p>The state of the generator is exactly the same as a new
    * generator built with the same seed.</p>


Reply via email to