]> source.dussan.org Git - poi.git/commitdiff
Improved support for chunks and chunk streams, plus tests
authorNick Burch <nick@apache.org>
Tue, 19 Jun 2007 22:41:33 +0000 (22:41 +0000)
committerNick Burch <nick@apache.org>
Tue, 19 Jun 2007 22:41:33 +0000 (22:41 +0000)
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@548870 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java
src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java
src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV11.java
src/scratchpad/src/org/apache/poi/hdgf/dev/VSDDumper.java
src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java
src/scratchpad/src/org/apache/poi/hdgf/streams/CompressedStreamStore.java
src/scratchpad/src/org/apache/poi/hdgf/streams/PointerContainingStream.java
src/scratchpad/src/org/apache/poi/hdgf/streams/Stream.java
src/scratchpad/src/org/apache/poi/hdgf/streams/StreamStore.java
src/scratchpad/testcases/org/apache/poi/hdgf/chunks/TestChunks.java [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hdgf/streams/TestStreamComplex.java

index 94bc65a67f5e0c75d90cea2775e0c17efbcec96d..eedba08888eadb06042320ff654d4178224b1e4d 100644 (file)
@@ -38,6 +38,21 @@ public class Chunk {
                this.contents = contents;
        }
        
+       public byte[] _getContents() {
+               return contents;
+       }
+       public ChunkHeader getHeader() {
+               return header;
+       }
+       /** Gets the separator between this chunk and the next, if it exists */
+       public ChunkSeparator getSeparator() {
+               return separator;
+       }
+       /** Gets the trailer for this chunk, if it exists */
+       public ChunkTrailer getTrailer() {
+               return trailer;
+       }
+
        /**
         * Returns the size of the chunk, including any
         *  headers, trailers and separators.
index 166a5e006e1116057be27e41e7b59c1fcf3f9d9c..f7e6cf9126096e12ce6851db74a450f504f7def3 100644 (file)
@@ -40,19 +40,48 @@ public class ChunkFactory {
                // Create the header
                ChunkHeader header = 
                        ChunkHeader.createChunkHeader(version, data, offset);
+               int endOfDataPos = offset + header.getLength() + header.getSizeInBytes();
                
+               // Check we have enough data, and tweak the header size
+               //  as required
+               if(endOfDataPos > data.length) {
+                       System.err.println("Header called for " + header.getLength() +" bytes, but that would take us passed the end of the data!");
+                       
+                       endOfDataPos = data.length;
+                       header.length = data.length - offset - header.getSizeInBytes();
+                       
+                       if(header.hasTrailer()) {
+                               header.length -= 8;
+                               endOfDataPos  -= 8;
+                       }
+                       if(header.hasSeparator()) {
+                               header.length -= 4;
+                               endOfDataPos  -= 4;
+                       }
+               }
+               
+
                // Create the trailer and separator, if required
                ChunkTrailer trailer = null;
                ChunkSeparator separator = null;
                if(header.hasTrailer()) {
-                       trailer = new ChunkTrailer(
-                                       data, header.getLength() + header.getSizeInBytes());
-                       if(header.hasSeparator()) {
+                       if(endOfDataPos <= data.length-8) {
+                               trailer = new ChunkTrailer(
+                                       data, endOfDataPos);
+                               endOfDataPos += 8;
+                       } else {
+                               System.err.println("Header claims a length to " + endOfDataPos + " there's then no space for the trailer in the data (" + data.length + ")");
+                       }
+               }
+               if(header.hasSeparator()) {
+                       if(endOfDataPos <= data.length-4) {
                                separator = new ChunkSeparator(
-                                       data, header.getLength() + header.getSizeInBytes() + 8);
+                                               data, endOfDataPos);
+                       } else {
+                               System.err.println("Header claims a length to " + endOfDataPos + " there's then no space for the separator in the data (" + data.length + ")");
                        }
                }
-               
+
                // Now, create the chunk
                byte[] contents = new byte[header.getLength()];
                System.arraycopy(data, offset+header.getSizeInBytes(), contents, 0, contents.length);
index a81a20f56f12b0c5975925134cd8ede56630797f..51eca5649c7be7429fe95b27015067a8b6cf563a 100644 (file)
@@ -29,7 +29,7 @@ public class ChunkHeaderV11 extends ChunkHeaderV6 {
 
                if(unknown2 == 2 && unknown3 == 0x55) { return true; }
                if(unknown2 == 2 && unknown3 == 0x54 && type == 0xaa) { return true; }
-               if(unknown2 == 3 && unknown3 == 0x50 && type == 0xaa) { return true; }
+               if(unknown2 == 3 && unknown3 != 0x50) { return true; }
                if(type == 0x69) { return true; }
                
                return false;
index 2aee90854e74a1e6897686cde9961000acfe5f65..364963f291c8fbfac1bec7205b64680794d7a486 100644 (file)
@@ -67,6 +67,16 @@ public class VSDDumper {
                System.out.println(ind + "  Compressed is\t" + ptr.destinationCompressed());
                System.out.println(ind + "  Stream is\t" + stream.getClass().getCanonicalName());
                
+               byte[] db = stream._getStore()._getContents();
+               String ds = "";
+               if(db.length >= 8) {
+                       for(int i=0; i<8; i++) {
+                               if(i>0) ds += ", ";
+                               ds += db[i];
+                       }
+               }
+               System.out.println(ind + "  First few bytes are\t" + ds);
+               
                if(stream instanceof PointerContainingStream) {
                        PointerContainingStream pcs = (PointerContainingStream)stream;
                        System.out.println(ind + "  Has " + 
index dcb2310787e987f94efd1f4b128fc3e9ac167b9c..75b6beefd1a04ea732c9b4c960ecb4af1bb86617 100644 (file)
@@ -30,6 +30,9 @@ public class ChunkStream extends Stream {
        protected ChunkStream(Pointer pointer, StreamStore store, ChunkFactory chunkFactory) {
                super(pointer, store);
                this.chunkFactory = chunkFactory;
+               
+               // For compressed stores, we require all of the data
+               store.copyBlockHeaderToContents();
        }
        
        public Chunk[] getChunks() { return chunks; }
index df93d9d5e52f47096ee1797e7750c33341292359..8b15596243cdc10397e9f5a0baacdb4f26b6812f 100644 (file)
@@ -25,7 +25,7 @@ import org.apache.poi.hdgf.LZW4HDGF;
  * A StreamStore where the data on-disk is compressed,
  *  using the crazy Visio LZW
  */
-class CompressedStreamStore extends StreamStore {
+public class CompressedStreamStore extends StreamStore {
        /** The raw, compressed contents */
        private byte[] compressedContents;
        /** 
@@ -33,6 +33,7 @@ class CompressedStreamStore extends StreamStore {
         *  real contents in the de-compressed data
         */
        private byte[] blockHeader = new byte[4];
+       private boolean blockHeaderInContents = false;
        
        protected byte[] _getCompressedContents() { return compressedContents; }
        protected byte[] _getBlockHeader() { return blockHeader; }
@@ -54,6 +55,19 @@ class CompressedStreamStore extends StreamStore {
                super(decompressedData[1], 0, decompressedData[1].length);
                blockHeader = decompressedData[0];
        }
+       
+       /**
+        * Some kinds of streams expect their 4 byte header to be
+        *  on the front of the contents.
+        * They can call this to have it sorted.
+        */
+       protected void copyBlockHeaderToContents() {
+               if(blockHeaderInContents) return;
+               
+               prependContentsWith(blockHeader);
+               blockHeaderInContents = true;
+       }
+       
 
        /**
         * Decompresses the given data, returning it as header + contents
index 949cc58f8d979385b723e768463a0b8b3b35f8c4..761eb181f926ec321f0d6fe08d3f816608502bc3 100644 (file)
@@ -89,7 +89,7 @@ public class PointerContainingStream extends Stream {
                        // Process chunk streams into their chunks
                        if(childStreams[i] instanceof ChunkStream) {
                                ChunkStream child = (ChunkStream)childStreams[i];
-//                             child.findChunks();
+                               child.findChunks();
                        }
                        
                        // Recurse into pointer containing streams
index e0deec5ec39c0a4472554af32b1a87f6a02df9fb..0d26686e213401baa606a614694bb23c12b52e74 100644 (file)
@@ -35,6 +35,7 @@ public abstract class Stream {
        
        public Pointer getPointer() { return pointer; }
        protected StreamStore getStore() { return store; }
+       public StreamStore _getStore() { return store; }
        public int _getContentsLength() { return store.getContents().length; }
        
        /**
index 68b2e519e84e4cedc731f80d870932fd4426b395..41532d8b0d1df9c936d7e9bc2f8e38b6c384b112 100644 (file)
@@ -21,7 +21,7 @@ package org.apache.poi.hdgf.streams;
  *  handles de-compressing it as required.
  * In future, may also handle writing it back out again
  */
-class StreamStore {
+public class StreamStore {
        private byte[] contents;
        
        /**
@@ -32,5 +32,14 @@ class StreamStore {
                System.arraycopy(data, offset, contents, 0, length);
        }
        
+       protected void prependContentsWith(byte[] b) {
+               byte[] newContents = new byte[contents.length + b.length];
+               System.arraycopy(b, 0, newContents, 0, b.length);
+               System.arraycopy(contents, 0, newContents, b.length, contents.length);
+               contents = newContents;
+       }
+       protected void copyBlockHeaderToContents() {}
+       
        protected byte[] getContents() { return contents; }
+       public byte[] _getContents() { return contents; }
 }
\ No newline at end of file
diff --git a/src/scratchpad/testcases/org/apache/poi/hdgf/chunks/TestChunks.java b/src/scratchpad/testcases/org/apache/poi/hdgf/chunks/TestChunks.java
new file mode 100644 (file)
index 0000000..412d58e
--- /dev/null
@@ -0,0 +1,160 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.hdgf.chunks;
+
+import junit.framework.TestCase;
+
+public class TestChunks extends TestCase {
+public static final byte[] data_a = new byte[] { 70, 0, 0, 0,
+       -1, -1, -1, -1, 2, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 
+       0, 0, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 
+       0, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 
+       0, 36, 0, 0, 0, 1, 0, 84, 24, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 
+       0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       -124, 0, 0, 0, 2, 0, 85, 73, 0, 0, 0, 0, 0, 0, -56, 63, 73, 0, 0, 0, 
+       0, 0, 0, -64, 63, 63, 0, 0, 0, 0, 0, 0, -64, 63, 63, 0, 0, 0, 0, 0, 0, 
+       -64, -65, 73, 0, 0, 0, 0, 0, 0, -16, 63, 73, 0, 0, 0, 0, 0, 0, -16, 63, 
+       4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -16, 63, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       1, -1, 3, 0, 0, 32, 0, 0, 0, 0, 0, -73, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 
+       79, 0, 0, 0, 2, 0, 85, 32, 32, 64, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 
+       0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 
+       8, 8, 65, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 
+       0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 1, -13, 15, 0, 0, 0, 0, 
+       -56, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 2, 0, 85, 63, 0, 0, 
+       0, 0, 0, 0, -48, 63, 63, 0, 0, 0, 0, 0, 0, -48, 63, 63, 0, 0, 0, 0, 0, 
+       0, -48, 63, 63, 0, 0, 0, 0, 0, 0, -48, 63, 0, 0, 0, 0, 0, 0, -16, 63, 
+       0, 0, 0, 0, 0, 0, -16, 63, 1, 0, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 
+       0, 1, -1, 15, 7, 0, 0, 0, 0, 101, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 28, 
+       0, 0, 0, 1, 0, 84, 24, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       -125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 2, 0, 85, 5, 0, 0, 
+       0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+public static final byte[] data_b = new byte[] { 70, 0, 0, 0,
+       -1, -1, -1, -1, 3, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 
+       0, 0, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0,      0, 0, 0, -1, -1, -1, -1,
+       0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0,
+       0, 2, 0, 0, 0, 32, 0, 0, 0, 1, 0, 84, 24, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 1, 0, 0, 0, 0, 0, 0, 0, -110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -124, 
+       0, 0, 0, 2, 0, 85, 63, 0, 0, 0, 0, 0, 0, 33, 64, 63, 0, 0, 0, 0, 0, 0, 
+       38, 64, 63, 0, 0, 0, 0, 0, 0, -64, 63, 63, 0, 0, 0, 0, 0, 0, -64, -65, 
+       73, 0, 0, 0, 0, 0, 0, -16, 63, 73, 0, 0, 0, 0, 0, 0, -16, 63, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -16, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 3, 
+       0, 4, 32, 0, 0, 0, 0, 0, -56, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 
+       0, 2, 0, 85, 63, 0, 0, 0, 0, 0, 0, -48, 63, 63, 0, 0, 0, 0, 0, 0, -48, 
+       63, 63, 0, 0, 0, 0, 0, 0, -48, 63, 63, 0, 0, 0, 0, 0, 0, -48, 63, 0, 0, 
+       0, 0, 0, 0, -16, 63, 0, 0, 0, 0, 0, 0, -16, 63, 1, 0, 1, 0, 0, 1, 1, 0, 
+       7, 0, 0, 0, 0, 0, 0, 0, 1, -1, 15, 7, 0, 0, 0, 0, 101, 0, 0, 0, 1, 0, 0, 
+       0, 1, 0, 0, 0, 28, 0, 0, 0, 1, 0, 84, 24, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, -125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 2, 0, 
+       85, 5, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, -55, 0, 0, 0, 2, 0, 0, 0, 
+       0, 0, 0, 0, -122, 0, 0, 0, 1, 0, 80, 1, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 
+       0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+       0, 0, 0
+};
+
+       public void testChunkHeaderA() throws Exception {
+               ChunkFactory cf = new ChunkFactory(11);
+               ChunkHeader h = 
+                       ChunkHeader.createChunkHeader(11, data_a, 0);
+               
+               assertTrue(h instanceof ChunkHeaderV11);
+               ChunkHeaderV11 header = (ChunkHeaderV11)h;
+               
+               assertEquals(70, header.getType());
+               assertEquals(-1, header.getId());
+               assertEquals(2, header.getUnknown1());
+               assertEquals(68, header.getLength());
+               assertEquals(0, header.getUnknown2());
+               assertEquals(0, header.getUnknown3());
+               
+               assertTrue(header.hasTrailer());
+               assertTrue(header.hasSeparator());
+       }
+       public void testChunkHeaderB() throws Exception {
+               ChunkFactory cf = new ChunkFactory(11);
+               ChunkHeader h = 
+                       ChunkHeader.createChunkHeader(11, data_b, 0);
+               
+               assertTrue(h instanceof ChunkHeaderV11);
+               ChunkHeaderV11 header = (ChunkHeaderV11)h;
+               
+               assertEquals(70, header.getType());
+               assertEquals(-1, header.getId());
+               assertEquals(3, header.getUnknown1());
+               assertEquals(68, header.getLength());
+               assertEquals(0, header.getUnknown2());
+               assertEquals(0, header.getUnknown3());
+               
+               assertTrue(header.hasTrailer());
+               assertTrue(header.hasSeparator());
+       }
+       
+       public void testOneChunk() throws Exception {
+               ChunkFactory cf = new ChunkFactory(11);
+               cf.createChunk(data_a, 0);
+               cf.createChunk(data_b, 0);
+               
+               Chunk chunk = cf.createChunk(data_a, 0);
+               assertNotNull(chunk.getHeader());
+               assertNotNull(chunk.getTrailer());
+               assertNotNull(chunk.getSeparator());
+               
+               // Should be 19 + length + 8 + 4 big
+               assertEquals(68, chunk.getHeader().getLength());
+               assertEquals(68+19+8+4, chunk.getOnDiskSize());
+       }
+       
+       public void testManyChunks() throws Exception {
+               ChunkFactory cf = new ChunkFactory(11);
+               Chunk chunk;
+               int offset = 0;
+               
+               chunk = cf.createChunk(data_a, offset);
+               assertNotNull(chunk.getHeader());
+               assertNotNull(chunk.getTrailer());
+               assertNotNull(chunk.getSeparator());
+               offset += chunk.getOnDiskSize();
+               
+               chunk = cf.createChunk(data_a, offset);
+               assertNotNull(chunk.getHeader());
+               assertNotNull(chunk.getTrailer());
+               assertNotNull(chunk.getSeparator());
+               offset += chunk.getOnDiskSize();
+               
+               chunk = cf.createChunk(data_a, offset);
+               assertNotNull(chunk.getHeader());
+               assertNull(chunk.getTrailer());
+               assertNull(chunk.getSeparator());
+               offset += chunk.getOnDiskSize();
+       }
+}
index 38b2c92d66315a88927195c1291a4caa843958a3..c2d03f0c8992afc9e9d6a85ac2850a1de46c137c 100644 (file)
@@ -73,7 +73,23 @@ public class TestStreamComplex extends StreamTest {
        }
        
        public void testChunks() {
+               Pointer trailerPtr = ptrFactory.createPointer(contents, trailerPointerAt);
+               TrailerStream ts = (TrailerStream)
+                       Stream.createStream(trailerPtr, contents, chunkFactory, ptrFactory);
+               
+               // Should be 7th one
+               Pointer chunkPtr = ts.getChildPointers()[5];
+               assertFalse(chunkPtr.destinationHasStrings());
+               assertTrue(chunkPtr.destinationHasChunks());
+               assertFalse(chunkPtr.destinationHasPointers());
+               
+               Stream stream = Stream.createStream(chunkPtr, contents, chunkFactory, ptrFactory);
+               assertNotNull(stream);
+               assertTrue(stream instanceof ChunkStream);
                
+               // Now find the chunks within it
+               ChunkStream cs = (ChunkStream)stream;
+               cs.findChunks();
        }
        
        public void testStrings() {