]> source.dussan.org Git - poi.git/commitdiff
SST Rich Text Fix.
authorGlen Stampoultzis <glens@apache.org>
Wed, 29 May 2002 14:14:17 +0000 (14:14 +0000)
committerGlen Stampoultzis <glens@apache.org>
Wed, 29 May 2002 14:14:17 +0000 (14:14 +0000)
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/branches/REL_1_5_BRANCH@352656 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/RecordProcessor.java
src/java/org/apache/poi/hssf/record/SSTRecord.java
src/java/org/apache/poi/hssf/record/SSTSerializer.java
src/java/org/apache/poi/hssf/record/UnicodeString.java
src/testcases/org/apache/poi/hssf/data/duprich1.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/data/duprich2.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/record/TestSSTRecord.java

index 06eb3646ce6c1f097443bb16ec23b7c6097454a8..13bfc3a188bdd0182cf04b400ffff1dbdb4a885e 100644 (file)
@@ -1,8 +1,68 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ *    "Apache POI" must not be used to endorse or promote products
+ *    derived from this software without prior written permission. For
+ *    written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache POI", nor may "Apache" appear in their name, without
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
 package org.apache.poi.hssf.record;
 
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndian;
 
+/**
+ * Process a single record.  That is, an SST record or a continue record.
+ * Refactored from code originally in SSTRecord.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
 class RecordProcessor
 {
     private byte[] data;
index 07054a577766a4dfabf7f00cf9c31ecf5bdfe59d..582020a0276c67b49299312be8fe5926e7e59f88 100644 (file)
@@ -58,7 +58,6 @@ import org.apache.poi.util.BinaryTree;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
 
-import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
@@ -259,7 +258,8 @@ public class SSTRecord
             rval = field_3_strings.size();
             field_2_num_unique_strings++;
             integer = new Integer( rval );
-            field_3_strings.put( integer, ucs );
+            addToStringTable( integer, ucs );
+//            field_3_strings.put( integer, ucs );
         }
         return rval;
     }
@@ -324,11 +324,10 @@ public class SSTRecord
 
     public String getString( final int id )
     {
-        return ( (UnicodeString) field_3_strings.get( new Integer( id ) ) )
-                .getString();
+        return ( (UnicodeString) field_3_strings.get( new Integer( id ) ) ).getString();
     }
 
-    public boolean getString16bit( final int id )
+    public boolean isString16bit( final int id )
     {
         UnicodeString unicodeString = ( (UnicodeString) field_3_strings.get( new Integer( id ) ) );
         return ( ( unicodeString.getOptionFlags() & 0x01 ) == 1 );
@@ -456,7 +455,8 @@ public class SSTRecord
                                 _unfinished_string );
                 Integer integer = new Integer( field_3_strings.size() );
 
-                field_3_strings.put( integer, string );
+//                field_3_strings.put( integer, string );
+                addToStringTable( integer, string );
                 manufactureStrings( record,
                         _total_length_bytes
                         - LittleEndianConsts
@@ -725,35 +725,27 @@ public class SSTRecord
     private void setupStringParameters( final byte[] data, final int index,
                                         final int char_count )
     {
-        byte flag = data[index + LittleEndianConsts.SHORT_SIZE];
+        byte optionFlag = data[index + LittleEndianConsts.SHORT_SIZE];
 
-        _wide_char = ( flag & 1 ) == 1;
-        boolean extended = ( flag & 4 ) == 4;
-        boolean formatted_run = ( flag & 8 ) == 8;
+        _wide_char = ( optionFlag & 1 ) == 1;
+        boolean extended = ( optionFlag & 4 ) == 4;
+        boolean rich_text = ( optionFlag & 8 ) == 8;
 
-        _total_length_bytes = STRING_MINIMAL_OVERHEAD
-                + calculateByteCount( char_count );
+        _total_length_bytes = STRING_MINIMAL_OVERHEAD + calculateByteCount( char_count );
         _string_data_offset = STRING_MINIMAL_OVERHEAD;
-        if ( formatted_run )
+        if ( rich_text )
         {
-            short run_count = LittleEndian.getShort( data,
-                    index
-                    + _string_data_offset );
+            short run_count = LittleEndian.getShort( data, index + _string_data_offset );
 
             _string_data_offset += LittleEndianConsts.SHORT_SIZE;
-            _total_length_bytes += LittleEndianConsts.SHORT_SIZE
-                    + ( LittleEndianConsts.INT_SIZE
-                    * run_count );
+            _total_length_bytes += LittleEndianConsts.SHORT_SIZE + ( LittleEndianConsts.INT_SIZE * run_count );
         }
         if ( extended )
         {
-            int extension_length = LittleEndian.getInt( data,
-                    index
-                    + _string_data_offset );
+            int extension_length = LittleEndian.getInt( data, index + _string_data_offset );
 
             _string_data_offset += LittleEndianConsts.INT_SIZE;
-            _total_length_bytes += LittleEndianConsts.INT_SIZE
-                    + extension_length;
+            _total_length_bytes += LittleEndianConsts.INT_SIZE + extension_length;
         }
     }
 
@@ -771,6 +763,7 @@ public class SSTRecord
         LittleEndian.putShort( bstring, offset, char_count );
         offset += LittleEndianConsts.SHORT_SIZE;
         bstring[offset] = str_data[offset];
+        System.out.println( "_string_data_offset = " + _string_data_offset );
         System.arraycopy( str_data, _string_data_offset, bstring,
                 STRING_MINIMAL_OVERHEAD,
                 bstring.length - STRING_MINIMAL_OVERHEAD );
@@ -785,27 +778,32 @@ public class SSTRecord
         else
         {
             Integer integer = new Integer( field_3_strings.size() );
+            addToStringTable( integer, string );
+        }
+    }
+
+    /**
+     * Okay, we are doing some major cheating here. Because we can't handle rich text strings properly
+     * we end up getting duplicate strings.  To get around this I'm doing do things: 1. Converting rich
+     * text to normal text and 2. If there's a duplicate I'm adding a space onto the end.  Sneaky perhaps
+     * but it gets the job done until we can handle this a little better.
+     */
+    private void addToStringTable( Integer integer, UnicodeString string )
+    {
+        if (string.isRichText())
+            string.setOptionFlags( (byte)(string.getOptionFlags() & (~8) ) );
 
-            // This retry loop is a nasty hack that lets us get around the issue of duplicate
-            // strings in the SST record.  There should never be duplicates but because we don't
-            // handle rich text records correctly this may occur.  Also some Excel alternatives
-            // do not seem correctly add strings to this table.
-            //
-            // The hack bit is that we add spaces to the end of the string until don't get an
-            // illegal argument exception when adding.  One day we will have to deal with this
-            // more gracefully.
-            boolean added = false;
-            while ( !added )
+        boolean added = false;
+        while (added == false)
+        {
+            try
             {
-                try
-                {
-                    field_3_strings.put( integer, string );
-                    added = true;
-                }
-                catch ( IllegalArgumentException duplicateValue )
-                {
-                    string.setString( string.getString() + " " );
-                }
+                field_3_strings.put( integer, string );
+                added = true;
+            }
+            catch( Exception ignore )
+            {
+                string.setString( string.getString() + " " );
             }
         }
     }
index 5ee3af09876f922fe862baa692cb96da180fd3b5..5802279145acfcfd40337503a81bec1eb117d5ac 100644 (file)
@@ -1,3 +1,57 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ *    "Apache POI" must not be used to endorse or promote products
+ *    derived from this software without prior written permission. For
+ *    written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache POI", nor may "Apache" appear in their name, without
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
 package org.apache.poi.hssf.record;
 
 import org.apache.poi.util.BinaryTree;
@@ -6,6 +60,12 @@ import org.apache.poi.util.LittleEndianConsts;
 import java.util.List;
 import java.util.ArrayList;
 
+/**
+ * This class handles serialization of SST records.  It utilizes the record processor
+ * class write individual records. This has been refactored from the SSTRecord class.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
 class SSTSerializer
 {
 
index c303a42e3c56b2f71efd846bc92cd484fb2d7f2a..2d68815255f8403bf6435c90a616026037aa8eec 100644 (file)
@@ -66,6 +66,7 @@ import org.apache.poi.util.StringUtil;
  * REFERENCE:  PG 264 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
  * @author  Andrew C. Oliver
  * @author Marc Johnson (mjohnson at apache dot org)
+ * @author Glen Stampoultzis (glens at apache.org)
  * @version 2.0-pre
  */
 
@@ -77,12 +78,28 @@ public class UnicodeString
     private short             field_1_charCount;     // = 0;
     private byte              field_2_optionflags;   // = 0;
     private String            field_3_string;        // = null;
+    private final int RICH_TEXT_BIT = 8;
+
+    public UnicodeString()
+    {
+    }
+
 
     public int hashCode()
     {
-        return field_1_charCount;
+        int stringHash = 0;
+        if (field_3_string != null)
+            stringHash = field_3_string.hashCode();
+        return field_1_charCount + stringHash;
     }
 
+    /**
+     * Our handling of equals is inconsistent with compareTo.  The trouble is because we don't truely understand
+     * rich text fields yet it's difficult to make a sound comparison.
+     *
+     * @param o     The object to compare.
+     * @return      true if the object is actually equal.
+     */
     public boolean equals(Object o)
     {
         if ((o == null) || (o.getClass() != this.getClass()))
@@ -96,10 +113,6 @@ public class UnicodeString
                 && field_3_string.equals(other.field_3_string));
     }
 
-    public UnicodeString()
-    {
-    }
-
     /**
      * construct a unicode string record and fill its fields, ID is ignored
      * @param id - ignored
@@ -278,20 +291,10 @@ public class UnicodeString
 
     public int serialize(int offset, byte [] data)
     {
-        int charsize = 1;
-
-        // Note: I suspect this may not be right
-        if ((getOptionFlags() & 0x01) == 1)
-        {
-            charsize = 2;
-        }
-
-        // byte[] retval = new byte[ 3 + (getString().length() * charsize) ];
         LittleEndian.putShort(data, 0 + offset, getCharCount());
         data[ 2 + offset ] = getOptionFlags();
 
-//        System.out.println("Unicode: We've got "+retval[2]+" for our option flag");
-        if ((getOptionFlags() & 0x01) == 0)
+        if (!isUncompressedUnicode())
         {
             StringUtil.putCompressedUnicode(getString(), data, 0x3 + offset);
         }
@@ -303,14 +306,14 @@ public class UnicodeString
         return getRecordSize();
     }
 
-    public int getRecordSize()
+    private boolean isUncompressedUnicode()
     {
-        int charsize = 1;
+        return (getOptionFlags() & 0x01) == 1;
+    }
 
-        if ((getOptionFlags() & 0x01) == 1)
-        {
-            charsize = 2;
-        }
+    public int getRecordSize()
+    {
+        int charsize = isUncompressedUnicode() ? 2 : 1;
         return 3 + (getString().length() * charsize);
     }
 
@@ -339,11 +342,16 @@ public class UnicodeString
         return this.getString().compareTo(str.getString());
     }
 
+    public boolean isRichText()
+    {
+        return (getOptionFlags() & RICH_TEXT_BIT) != 0;
+    }
+
     int maxBrokenLength(final int proposedBrokenLength)
     {
         int rval = proposedBrokenLength;
 
-        if ((field_2_optionflags & 1) == 1)
+        if (isUncompressedUnicode())
         {
             int proposedStringLength = proposedBrokenLength - 3;
 
@@ -356,12 +364,4 @@ public class UnicodeString
         return rval;
     }
 
-//    public boolean equals(Object obj) {
-//        if (!(obj instanceof UnicodeString)) return false;
-//        
-//        UnicodeString str = (UnicodeString)obj;
-//        
-//        
-//       return this.getString().equals(str.getString());
-//    }    
 }
diff --git a/src/testcases/org/apache/poi/hssf/data/duprich1.xls b/src/testcases/org/apache/poi/hssf/data/duprich1.xls
new file mode 100644 (file)
index 0000000..3fddbed
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/duprich1.xls differ
diff --git a/src/testcases/org/apache/poi/hssf/data/duprich2.xls b/src/testcases/org/apache/poi/hssf/data/duprich2.xls
new file mode 100644 (file)
index 0000000..57af63b
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/duprich2.xls differ
index 56e6fec7645f9ab385a66eeaa9831f0cf74f4a91..58d8bcd5a3f64c1240deb92ee63d2760e691cb33 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
  * The Apache Software License, Version 1.1
  *
 
 package org.apache.poi.hssf.record;
 
-import org.apache.poi.util.*;
-
-import junit.framework.*;
+import junit.framework.TestCase;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.hssf.model.Workbook;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
 
 import java.io.*;
-
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
 
 /**
  * @author Marc Johnson (mjohnson at apache dot org)
  */
 
 public class TestSSTRecord
-    extends TestCase
+        extends TestCase
 {
-    private String              _test_file_path;
+    private String _test_file_path;
     private static final String _test_file_path_property =
-        "HSSF.testdata.path";
+            "HSSF.testdata.path";
 
     /**
      * Creates new TestSSTRecord
@@ -80,10 +84,10 @@ public class TestSSTRecord
      * @param name
      */
 
-    public TestSSTRecord(String name)
+    public TestSSTRecord( String name )
     {
-        super(name);
-        _test_file_path = System.getProperty(_test_file_path_property);
+        super( name );
+        _test_file_path = System.getProperty( _test_file_path_property );
     }
 
     /**
@@ -93,118 +97,118 @@ public class TestSSTRecord
      */
 
     public void testProcessContinueRecord()
-        throws IOException
+            throws IOException
     {
-        byte[] testdata = readTestData("BigSSTRecord");
-        byte[] input    = new byte[ testdata.length - 4 ];
-
-        System.arraycopy(testdata, 4, input, 0, input.length);
-        SSTRecord record         =
-            new SSTRecord(LittleEndian.getShort(testdata, 0),
-                          LittleEndian.getShort(testdata, 2), input);
-        byte[]    continueRecord = readTestData("BigSSTRecordCR");
-
-        input = new byte[ continueRecord.length - 4 ];
-        System.arraycopy(continueRecord, 4, input, 0, input.length);
-        record.processContinueRecord(input);
-        assertEquals(1464, record.getNumStrings());
-        assertEquals(688, record.getNumUniqueStrings());
-        assertEquals(688, record.countStrings());
+        byte[] testdata = readTestData( "BigSSTRecord" );
+        byte[] input = new byte[testdata.length - 4];
+
+        System.arraycopy( testdata, 4, input, 0, input.length );
+        SSTRecord record =
+                new SSTRecord( LittleEndian.getShort( testdata, 0 ),
+                        LittleEndian.getShort( testdata, 2 ), input );
+        byte[] continueRecord = readTestData( "BigSSTRecordCR" );
+
+        input = new byte[continueRecord.length - 4];
+        System.arraycopy( continueRecord, 4, input, 0, input.length );
+        record.processContinueRecord( input );
+        assertEquals( 1464, record.getNumStrings() );
+        assertEquals( 688, record.getNumUniqueStrings() );
+        assertEquals( 688, record.countStrings() );
         byte[] ser_output = record.serialize();
-        int    offset     = 0;
-        short  type       = LittleEndian.getShort(ser_output, offset);
+        int offset = 0;
+        short type = LittleEndian.getShort( ser_output, offset );
 
         offset += LittleEndianConsts.SHORT_SIZE;
-        short length = LittleEndian.getShort(ser_output, offset);
+        short length = LittleEndian.getShort( ser_output, offset );
 
         offset += LittleEndianConsts.SHORT_SIZE;
-        byte[] recordData = new byte[ length ];
+        byte[] recordData = new byte[length];
 
-        System.arraycopy(ser_output, offset, recordData, 0, length);
+        System.arraycopy( ser_output, offset, recordData, 0, length );
         offset += length;
-        SSTRecord testRecord = new SSTRecord(type, length, recordData);
+        SSTRecord testRecord = new SSTRecord( type, length, recordData );
 
-        assertEquals(ContinueRecord.sid,
-                     LittleEndian.getShort(ser_output, offset));
+        assertEquals( ContinueRecord.sid,
+                LittleEndian.getShort( ser_output, offset ) );
         offset += LittleEndianConsts.SHORT_SIZE;
-        length = LittleEndian.getShort(ser_output, offset);
+        length = LittleEndian.getShort( ser_output, offset );
         offset += LittleEndianConsts.SHORT_SIZE;
-        byte[] cr = new byte[ length ];
+        byte[] cr = new byte[length];
 
-        System.arraycopy(ser_output, offset, cr, 0, length);
+        System.arraycopy( ser_output, offset, cr, 0, length );
         offset += length;
-        assertEquals(offset, ser_output.length);
-        testRecord.processContinueRecord(cr);
-        assertEquals(record, testRecord);
+        assertEquals( offset, ser_output.length );
+        testRecord.processContinueRecord( cr );
+        assertEquals( record, testRecord );
 
         // testing based on new bug report
-        testdata = readTestData("BigSSTRecord2");
-        input    = new byte[ testdata.length - 4 ];
-        System.arraycopy(testdata, 4, input, 0, input.length);
-        record = new SSTRecord(LittleEndian.getShort(testdata, 0),
-                               LittleEndian.getShort(testdata, 2), input);
-        byte[] continueRecord1 = readTestData("BigSSTRecord2CR1");
-
-        input = new byte[ continueRecord1.length - 4 ];
-        System.arraycopy(continueRecord1, 4, input, 0, input.length);
-        record.processContinueRecord(input);
-        byte[] continueRecord2 = readTestData("BigSSTRecord2CR2");
-
-        input = new byte[ continueRecord2.length - 4 ];
-        System.arraycopy(continueRecord2, 4, input, 0, input.length);
-        record.processContinueRecord(input);
-        byte[] continueRecord3 = readTestData("BigSSTRecord2CR3");
-
-        input = new byte[ continueRecord3.length - 4 ];
-        System.arraycopy(continueRecord3, 4, input, 0, input.length);
-        record.processContinueRecord(input);
-        byte[] continueRecord4 = readTestData("BigSSTRecord2CR4");
-
-        input = new byte[ continueRecord4.length - 4 ];
-        System.arraycopy(continueRecord4, 4, input, 0, input.length);
-        record.processContinueRecord(input);
-        byte[] continueRecord5 = readTestData("BigSSTRecord2CR5");
-
-        input = new byte[ continueRecord5.length - 4 ];
-        System.arraycopy(continueRecord5, 4, input, 0, input.length);
-        record.processContinueRecord(input);
-        byte[] continueRecord6 = readTestData("BigSSTRecord2CR6");
-
-        input = new byte[ continueRecord6.length - 4 ];
-        System.arraycopy(continueRecord6, 4, input, 0, input.length);
-        record.processContinueRecord(input);
-        byte[] continueRecord7 = readTestData("BigSSTRecord2CR7");
-
-        input = new byte[ continueRecord7.length - 4 ];
-        System.arraycopy(continueRecord7, 4, input, 0, input.length);
-        record.processContinueRecord(input);
-        assertEquals(158642, record.getNumStrings());
-        assertEquals(5249, record.getNumUniqueStrings());
-        assertEquals(5249, record.countStrings());
+        testdata = readTestData( "BigSSTRecord2" );
+        input = new byte[testdata.length - 4];
+        System.arraycopy( testdata, 4, input, 0, input.length );
+        record = new SSTRecord( LittleEndian.getShort( testdata, 0 ),
+                LittleEndian.getShort( testdata, 2 ), input );
+        byte[] continueRecord1 = readTestData( "BigSSTRecord2CR1" );
+
+        input = new byte[continueRecord1.length - 4];
+        System.arraycopy( continueRecord1, 4, input, 0, input.length );
+        record.processContinueRecord( input );
+        byte[] continueRecord2 = readTestData( "BigSSTRecord2CR2" );
+
+        input = new byte[continueRecord2.length - 4];
+        System.arraycopy( continueRecord2, 4, input, 0, input.length );
+        record.processContinueRecord( input );
+        byte[] continueRecord3 = readTestData( "BigSSTRecord2CR3" );
+
+        input = new byte[continueRecord3.length - 4];
+        System.arraycopy( continueRecord3, 4, input, 0, input.length );
+        record.processContinueRecord( input );
+        byte[] continueRecord4 = readTestData( "BigSSTRecord2CR4" );
+
+        input = new byte[continueRecord4.length - 4];
+        System.arraycopy( continueRecord4, 4, input, 0, input.length );
+        record.processContinueRecord( input );
+        byte[] continueRecord5 = readTestData( "BigSSTRecord2CR5" );
+
+        input = new byte[continueRecord5.length - 4];
+        System.arraycopy( continueRecord5, 4, input, 0, input.length );
+        record.processContinueRecord( input );
+        byte[] continueRecord6 = readTestData( "BigSSTRecord2CR6" );
+
+        input = new byte[continueRecord6.length - 4];
+        System.arraycopy( continueRecord6, 4, input, 0, input.length );
+        record.processContinueRecord( input );
+        byte[] continueRecord7 = readTestData( "BigSSTRecord2CR7" );
+
+        input = new byte[continueRecord7.length - 4];
+        System.arraycopy( continueRecord7, 4, input, 0, input.length );
+        record.processContinueRecord( input );
+        assertEquals( 158642, record.getNumStrings() );
+        assertEquals( 5249, record.getNumUniqueStrings() );
+        assertEquals( 5249, record.countStrings() );
         ser_output = record.serialize();
-        offset     = 0;
-        type       = LittleEndian.getShort(ser_output, offset);
-        offset     += LittleEndianConsts.SHORT_SIZE;
-        length     = LittleEndian.getShort(ser_output, offset);
-        offset     += LittleEndianConsts.SHORT_SIZE;
-        recordData = new byte[ length ];
-        System.arraycopy(ser_output, offset, recordData, 0, length);
-        offset     += length;
-        testRecord = new SSTRecord(type, length, recordData);
-        for (int count = 0; count < 7; count++)
+        offset = 0;
+        type = LittleEndian.getShort( ser_output, offset );
+        offset += LittleEndianConsts.SHORT_SIZE;
+        length = LittleEndian.getShort( ser_output, offset );
+        offset += LittleEndianConsts.SHORT_SIZE;
+        recordData = new byte[length];
+        System.arraycopy( ser_output, offset, recordData, 0, length );
+        offset += length;
+        testRecord = new SSTRecord( type, length, recordData );
+        for ( int count = 0; count < 7; count++ )
         {
-            assertEquals(ContinueRecord.sid,
-                         LittleEndian.getShort(ser_output, offset));
+            assertEquals( ContinueRecord.sid,
+                    LittleEndian.getShort( ser_output, offset ) );
             offset += LittleEndianConsts.SHORT_SIZE;
-            length = LittleEndian.getShort(ser_output, offset);
+            length = LittleEndian.getShort( ser_output, offset );
             offset += LittleEndianConsts.SHORT_SIZE;
-            cr     = new byte[ length ];
-            System.arraycopy(ser_output, offset, cr, 0, length);
-            testRecord.processContinueRecord(cr);
+            cr = new byte[length];
+            System.arraycopy( ser_output, offset, cr, 0, length );
+            testRecord.processContinueRecord( cr );
             offset += length;
         }
-        assertEquals(offset, ser_output.length);
-        assertEquals(record, testRecord);
+        assertEquals( offset, ser_output.length );
+        assertEquals( record, testRecord );
     }
 
     /**
@@ -214,23 +218,23 @@ public class TestSSTRecord
      */
 
     public void testHugeStrings()
-        throws IOException
+            throws IOException
     {
-        SSTRecord record       = new SSTRecord();
-        byte[][]  bstrings     =
-        {
-            new byte[ 9000 ], new byte[ 7433 ], new byte[ 9002 ],
-            new byte[ 16998 ]
-        };
-        String[]  strings      = new String[ bstrings.length ];
-        int       total_length = 0;
-
-        for (int k = 0; k < bstrings.length; k++)
+        SSTRecord record = new SSTRecord();
+        byte[][] bstrings =
+                {
+                    new byte[9000], new byte[7433], new byte[9002],
+                    new byte[16998]
+                };
+        String[] strings = new String[bstrings.length];
+        int total_length = 0;
+
+        for ( int k = 0; k < bstrings.length; k++ )
         {
-            Arrays.fill(bstrings[ k ], ( byte ) ('a' + k));
-            strings[ k ] = new String(bstrings[ k ]);
-            record.addString(strings[ k ]);
-            total_length += 3 + bstrings[ k ].length;
+            Arrays.fill( bstrings[k], (byte) ( 'a' + k ) );
+            strings[k] = new String( bstrings[k] );
+            record.addString( strings[k] );
+            total_length += 3 + bstrings[k].length;
         }
 
         // add overhead of SST record
@@ -240,88 +244,88 @@ public class TestSSTRecord
         total_length += 4;
 
         // add overhead of six records
-        total_length += (6 * 4);
-        byte[] content = new byte[ record.getRecordSize() ];
+        total_length += ( 6 * 4 );
+        byte[] content = new byte[record.getRecordSize()];
 
-        record.serialize(0, content);
-        assertEquals(total_length, content.length);
-        for (int index = 0; index != content.length; )
+        record.serialize( 0, content );
+        assertEquals( total_length, content.length );
+        for ( int index = 0; index != content.length; )
         {
-            short record_type = LittleEndian.getShort(content, index);
+            short record_type = LittleEndian.getShort( content, index );
 
             index += LittleEndianConsts.SHORT_SIZE;
-            short record_length = LittleEndian.getShort(content, index);
+            short record_length = LittleEndian.getShort( content, index );
 
             index += LittleEndianConsts.SHORT_SIZE;
-            byte[] data = new byte[ record_length ];
+            byte[] data = new byte[record_length];
 
-            System.arraycopy(content, index, data, 0, record_length);
+            System.arraycopy( content, index, data, 0, record_length );
             index += record_length;
-            if (record_type == SSTRecord.sid)
+            if ( record_type == SSTRecord.sid )
             {
-                record = new SSTRecord(record_type, record_length, data);
+                record = new SSTRecord( record_type, record_length, data );
             }
             else
             {
-                record.processContinueRecord(data);
+                record.processContinueRecord( data );
             }
         }
-        assertEquals(strings.length, record.getNumStrings());
-        assertEquals(strings.length, record.getNumUniqueStrings());
-        assertEquals(strings.length, record.countStrings());
-        for (int k = 0; k < strings.length; k++)
+        assertEquals( strings.length, record.getNumStrings() );
+        assertEquals( strings.length, record.getNumUniqueStrings() );
+        assertEquals( strings.length, record.countStrings() );
+        for ( int k = 0; k < strings.length; k++ )
         {
-            assertEquals(strings[ k ], record.getString(k));
+            assertEquals( strings[k], record.getString( k ) );
         }
-        record        = new SSTRecord();
-        bstrings[ 1 ] = new byte[ bstrings[ 1 ].length - 1 ];
-        for (int k = 0; k < bstrings.length; k++)
+        record = new SSTRecord();
+        bstrings[1] = new byte[bstrings[1].length - 1];
+        for ( int k = 0; k < bstrings.length; k++ )
         {
-            if ((bstrings[ k ].length % 2) == 1)
+            if ( ( bstrings[k].length % 2 ) == 1 )
             {
-                Arrays.fill(bstrings[ k ], ( byte ) ('a' + k));
-                strings[ k ] = new String(bstrings[ k ]);
+                Arrays.fill( bstrings[k], (byte) ( 'a' + k ) );
+                strings[k] = new String( bstrings[k] );
             }
             else
             {
-                char[] data = new char[ bstrings[ k ].length / 2 ];
+                char[] data = new char[bstrings[k].length / 2];
 
-                Arrays.fill(data, ( char ) ('\u2122' + k));
-                strings[ k ] = new String(data);
+                Arrays.fill( data, (char) ( '\u2122' + k ) );
+                strings[k] = new String( data );
             }
-            record.addString(strings[ k ]);
+            record.addString( strings[k] );
         }
-        content = new byte[ record.getRecordSize() ];
-        record.serialize(0, content);
+        content = new byte[record.getRecordSize()];
+        record.serialize( 0, content );
         total_length--;
-        assertEquals(total_length, content.length);
-        for (int index = 0; index != content.length; )
+        assertEquals( total_length, content.length );
+        for ( int index = 0; index != content.length; )
         {
-            short record_type = LittleEndian.getShort(content, index);
+            short record_type = LittleEndian.getShort( content, index );
 
             index += LittleEndianConsts.SHORT_SIZE;
-            short record_length = LittleEndian.getShort(content, index);
+            short record_length = LittleEndian.getShort( content, index );
 
             index += LittleEndianConsts.SHORT_SIZE;
-            byte[] data = new byte[ record_length ];
+            byte[] data = new byte[record_length];
 
-            System.arraycopy(content, index, data, 0, record_length);
+            System.arraycopy( content, index, data, 0, record_length );
             index += record_length;
-            if (record_type == SSTRecord.sid)
+            if ( record_type == SSTRecord.sid )
             {
-                record = new SSTRecord(record_type, record_length, data);
+                record = new SSTRecord( record_type, record_length, data );
             }
             else
             {
-                record.processContinueRecord(data);
+                record.processContinueRecord( data );
             }
         }
-        assertEquals(strings.length, record.getNumStrings());
-        assertEquals(strings.length, record.getNumUniqueStrings());
-        assertEquals(strings.length, record.countStrings());
-        for (int k = 0; k < strings.length; k++)
+        assertEquals( strings.length, record.getNumStrings() );
+        assertEquals( strings.length, record.getNumUniqueStrings() );
+        assertEquals( strings.length, record.countStrings() );
+        for ( int k = 0; k < strings.length; k++ )
         {
-            assertEquals(strings[ k ], record.getString(k));
+            assertEquals( strings[k], record.getString( k ) );
         }
     }
 
@@ -332,7 +336,7 @@ public class TestSSTRecord
      */
 
     public void testSSTRecordBug()
-        throws IOException
+            throws IOException
     {
 
         // create an SSTRecord and write a certain pattern of strings
@@ -342,22 +346,22 @@ public class TestSSTRecord
         // the record will start with two integers, then this string
         // ... that will eat up 16 of the 8224 bytes that the record
         // can hold
-        record.addString("Hello");
+        record.addString( "Hello" );
 
         // now we have an additional 8208 bytes, which is an exact
         // multiple of 16 bytes
         long testvalue = 1000000000000L;
 
-        for (int k = 0; k < 2000; k++)
+        for ( int k = 0; k < 2000; k++ )
         {
-            record.addString(String.valueOf(testvalue++));
+            record.addString( String.valueOf( testvalue++ ) );
         }
-        byte[] content = new byte[ record.getRecordSize() ];
+        byte[] content = new byte[record.getRecordSize()];
 
-        record.serialize(0, content);
-        assertEquals(( byte ) 13, content[ 4 + 8228 ]);
-        assertEquals(( byte ) 13, content[ 4 + 8228 * 2 ]);
-        assertEquals(( byte ) 13, content[ 4 + 8228 * 3 ]);
+        record.serialize( 0, content );
+        assertEquals( (byte) 13, content[4 + 8228] );
+        assertEquals( (byte) 13, content[4 + 8228 * 2] );
+        assertEquals( (byte) 13, content[4 + 8228 * 3] );
     }
 
     /**
@@ -367,43 +371,43 @@ public class TestSSTRecord
     public void testSimpleAddString()
     {
         SSTRecord record = new SSTRecord();
-        String    s1     = "Hello world";
+        String s1 = "Hello world";
 
         // \u2122 is the encoding of the trademark symbol ...
-        String    s2     = "Hello world\u2122";
-
-        assertEquals(0, record.addString(s1));
-        assertEquals(s1, record.getString(0));
-        assertEquals(1, record.countStrings());
-        assertEquals(1, record.getNumStrings());
-        assertEquals(1, record.getNumUniqueStrings());
-        assertEquals(0, record.addString(s1));
-        assertEquals(s1, record.getString(0));
-        assertEquals(1, record.countStrings());
-        assertEquals(2, record.getNumStrings());
-        assertEquals(1, record.getNumUniqueStrings());
-        assertEquals(1, record.addString(s2));
-        assertEquals(s2, record.getString(1));
-        assertEquals(2, record.countStrings());
-        assertEquals(3, record.getNumStrings());
-        assertEquals(2, record.getNumUniqueStrings());
+        String s2 = "Hello world\u2122";
+
+        assertEquals( 0, record.addString( s1 ) );
+        assertEquals( s1, record.getString( 0 ) );
+        assertEquals( 1, record.countStrings() );
+        assertEquals( 1, record.getNumStrings() );
+        assertEquals( 1, record.getNumUniqueStrings() );
+        assertEquals( 0, record.addString( s1 ) );
+        assertEquals( s1, record.getString( 0 ) );
+        assertEquals( 1, record.countStrings() );
+        assertEquals( 2, record.getNumStrings() );
+        assertEquals( 1, record.getNumUniqueStrings() );
+        assertEquals( 1, record.addString( s2 ) );
+        assertEquals( s2, record.getString( 1 ) );
+        assertEquals( 2, record.countStrings() );
+        assertEquals( 3, record.getNumStrings() );
+        assertEquals( 2, record.getNumUniqueStrings() );
         Iterator iter = record.getStrings();
 
-        while (iter.hasNext())
+        while ( iter.hasNext() )
         {
-            UnicodeString ucs = ( UnicodeString ) iter.next();
+            UnicodeString ucs = (UnicodeString) iter.next();
 
-            if (ucs.getString().equals(s1))
+            if ( ucs.getString().equals( s1 ) )
             {
-                assertEquals(( byte ) 0, ucs.getOptionFlags());
+                assertEquals( (byte) 0, ucs.getOptionFlags() );
             }
-            else if (ucs.getString().equals(s2))
+            else if ( ucs.getString().equals( s2 ) )
             {
-                assertEquals(( byte ) 1, ucs.getOptionFlags());
+                assertEquals( (byte) 1, ucs.getOptionFlags() );
             }
             else
             {
-                fail("cannot match string: " + ucs.getString());
+                fail( "cannot match string: " + ucs.getString() );
             }
         }
     }
@@ -415,25 +419,25 @@ public class TestSSTRecord
      */
 
     public void testReaderConstructor()
-        throws IOException
+            throws IOException
     {
-        byte[] testdata = readTestData("BigSSTRecord");
-        byte[] input    = new byte[ testdata.length - 4 ];
-
-        System.arraycopy(testdata, 4, input, 0, input.length);
-        SSTRecord record = new SSTRecord(LittleEndian.getShort(testdata, 0),
-                                         LittleEndian.getShort(testdata, 2),
-                                         input);
-
-        assertEquals(1464, record.getNumStrings());
-        assertEquals(688, record.getNumUniqueStrings());
-        assertEquals(492, record.countStrings());
-        assertEquals(1, record.getExpectedChars());
-        assertEquals("Consolidated B-24J Liberator The Dragon & His Tai",
-                     record.getUnfinishedString());
-        assertEquals(52, record.getTotalLength());
-        assertEquals(3, record.getStringDataOffset());
-        assertTrue(!record.isWideChar());
+        byte[] testdata = readTestData( "BigSSTRecord" );
+        byte[] input = new byte[testdata.length - 4];
+
+        System.arraycopy( testdata, 4, input, 0, input.length );
+        SSTRecord record = new SSTRecord( LittleEndian.getShort( testdata, 0 ),
+                LittleEndian.getShort( testdata, 2 ),
+                input );
+
+        assertEquals( 1464, record.getNumStrings() );
+        assertEquals( 688, record.getNumUniqueStrings() );
+        assertEquals( 492, record.countStrings() );
+        assertEquals( 1, record.getExpectedChars() );
+        assertEquals( "Consolidated B-24J Liberator The Dragon & His Tai",
+                record.getUnfinishedString() );
+        assertEquals( 52, record.getTotalLength() );
+        assertEquals( 3, record.getStringDataOffset() );
+        assertTrue( !record.isWideChar() );
     }
 
     /**
@@ -444,26 +448,26 @@ public class TestSSTRecord
     {
         SSTRecord record = new SSTRecord();
 
-        assertEquals(0, record.getNumStrings());
-        assertEquals(0, record.getNumUniqueStrings());
-        assertEquals(0, record.countStrings());
-        assertEquals(0, record.getExpectedChars());
-        assertEquals("", record.getUnfinishedString());
-        assertEquals(0, record.getTotalLength());
-        assertEquals(0, record.getStringDataOffset());
-        assertTrue(!record.isWideChar());
-        byte[] output   = record.serialize();
+        assertEquals( 0, record.getNumStrings() );
+        assertEquals( 0, record.getNumUniqueStrings() );
+        assertEquals( 0, record.countStrings() );
+        assertEquals( 0, record.getExpectedChars() );
+        assertEquals( "", record.getUnfinishedString() );
+        assertEquals( 0, record.getTotalLength() );
+        assertEquals( 0, record.getStringDataOffset() );
+        assertTrue( !record.isWideChar() );
+        byte[] output = record.serialize();
         byte[] expected =
+                {
+                    (byte) record.getSid(), (byte) ( record.getSid() >> 8 ),
+                    (byte) 8, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+                    (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0
+                };
+
+        assertEquals( expected.length, output.length );
+        for ( int k = 0; k < expected.length; k++ )
         {
-            ( byte ) record.getSid(), ( byte ) (record.getSid() >> 8),
-            ( byte ) 8, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0,
-            ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0, ( byte ) 0
-        };
-
-        assertEquals(expected.length, output.length);
-        for (int k = 0; k < expected.length; k++)
-        {
-            assertEquals(String.valueOf(k), expected[ k ], output[ k ]);
+            assertEquals( String.valueOf( k ), expected[k], output[k] );
         }
     }
 
@@ -473,87 +477,87 @@ public class TestSSTRecord
      * @param ignored_args
      */
 
-    public static void main(String [] ignored_args)
+    public static void main( String[] ignored_args )
     {
-        System.out.println("Testing hssf.record.SSTRecord functionality");
-        junit.textui.TestRunner.run(TestSSTRecord.class);
+        System.out.println( "Testing hssf.record.SSTRecord functionality" );
+        junit.textui.TestRunner.run( TestSSTRecord.class );
     }
 
-    private byte [] readTestData(String filename)
-        throws IOException
+    private byte[] readTestData( String filename )
+            throws IOException
     {
-        File            file           = new File(_test_file_path
-                                                  + File.separator
-                                                  + filename);
-        FileInputStream stream         = new FileInputStream(file);
-        int             characterCount = 0;
-        byte            b              = ( byte ) 0;
-        List            bytes          = new ArrayList();
-        boolean         done           = false;
-
-        while (!done)
+        File file = new File( _test_file_path
+                + File.separator
+                + filename );
+        FileInputStream stream = new FileInputStream( file );
+        int characterCount = 0;
+        byte b = (byte) 0;
+        List bytes = new ArrayList();
+        boolean done = false;
+
+        while ( !done )
         {
             int count = stream.read();
 
-            switch (count)
+            switch ( count )
             {
 
-                case '0' :
-                case '1' :
-                case '2' :
-                case '3' :
-                case '4' :
-                case '5' :
-                case '6' :
-                case '7' :
-                case '8' :
-                case '9' :
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
                     b <<= 4;
-                    b += ( byte ) (count - '0');
+                    b += (byte) ( count - '0' );
                     characterCount++;
-                    if (characterCount == 2)
+                    if ( characterCount == 2 )
                     {
-                        bytes.add(new Byte(b));
+                        bytes.add( new Byte( b ) );
                         characterCount = 0;
-                        b              = ( byte ) 0;
+                        b = (byte) 0;
                     }
                     break;
 
-                case 'A' :
-                case 'B' :
-                case 'C' :
-                case 'D' :
-                case 'E' :
-                case 'F' :
+                case 'A':
+                case 'B':
+                case 'C':
+                case 'D':
+                case 'E':
+                case 'F':
                     b <<= 4;
-                    b += ( byte ) (count + 10 - 'A');
+                    b += (byte) ( count + 10 - 'A' );
                     characterCount++;
-                    if (characterCount == 2)
+                    if ( characterCount == 2 )
                     {
-                        bytes.add(new Byte(b));
+                        bytes.add( new Byte( b ) );
                         characterCount = 0;
-                        b              = ( byte ) 0;
+                        b = (byte) 0;
                     }
                     break;
 
-                case 'a' :
-                case 'b' :
-                case 'c' :
-                case 'd' :
-                case 'e' :
-                case 'f' :
+                case 'a':
+                case 'b':
+                case 'c':
+                case 'd':
+                case 'e':
+                case 'f':
                     b <<= 4;
-                    b += ( byte ) (count + 10 - 'a');
+                    b += (byte) ( count + 10 - 'a' );
                     characterCount++;
-                    if (characterCount == 2)
+                    if ( characterCount == 2 )
                     {
-                        bytes.add(new Byte(b));
+                        bytes.add( new Byte( b ) );
                         characterCount = 0;
-                        b              = ( byte ) 0;
+                        b = (byte) 0;
                     }
                     break;
 
-                case -1 :
+                case -1:
                     done = true;
                     break;
 
@@ -562,13 +566,55 @@ public class TestSSTRecord
             }
         }
         stream.close();
-        Byte[] polished = ( Byte [] ) bytes.toArray(new Byte[ 0 ]);
-        byte[] rval     = new byte[ polished.length ];
+        Byte[] polished = (Byte[]) bytes.toArray( new Byte[0] );
+        byte[] rval = new byte[polished.length];
 
-        for (int j = 0; j < polished.length; j++)
+        for ( int j = 0; j < polished.length; j++ )
         {
-            rval[ j ] = polished[ j ].byteValue();
+            rval[j] = polished[j].byteValue();
         }
         return rval;
     }
+
+    /**
+     * Tests that workbooks with rich text that duplicates a non rich text cell can be read and written.
+     */
+    public void testReadWriteDuplicatedRichText1()
+            throws Exception
+    {
+        File file = new File( _test_file_path + File.separator + "duprich1.xls" );
+        InputStream stream = new FileInputStream(file);
+        HSSFWorkbook wb = new HSSFWorkbook(stream);
+        stream.close();
+        HSSFSheet sheet = wb.getSheetAt(1);
+        assertEquals("01/05 (Wed) ", sheet.getRow(0).getCell((short)8).getStringCellValue());
+        assertEquals("01/05 (Wed)", sheet.getRow(1).getCell((short)8).getStringCellValue());
+
+        file = File.createTempFile("testout", "xls");
+        FileOutputStream outStream = new FileOutputStream(file);
+        wb.write(outStream);
+        outStream.close();
+        file.delete();
+
+        // test the second file.
+        file = new File( _test_file_path + File.separator + "duprich2.xls" );
+        stream = new FileInputStream(file);
+        wb = new HSSFWorkbook(stream);
+        stream.close();
+        sheet = wb.getSheetAt(0);
+        int row = 0;
+        assertEquals("Testing ", sheet.getRow(row++).getCell((short)0).getStringCellValue());
+        assertEquals("rich", sheet.getRow(row++).getCell((short)0).getStringCellValue());
+        assertEquals("text", sheet.getRow(row++).getCell((short)0).getStringCellValue());
+        assertEquals("strings", sheet.getRow(row++).getCell((short)0).getStringCellValue());
+        assertEquals("Testing  ", sheet.getRow(row++).getCell((short)0).getStringCellValue());
+        assertEquals("Testing", sheet.getRow(row++).getCell((short)0).getStringCellValue());
+
+//        file = new File("/tryme.xls");
+        file = File.createTempFile("testout", ".xls");
+        outStream = new FileOutputStream(file);
+        wb.write(outStream);
+        outStream.close();
+        file.delete();
+    }
 }