You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by jo...@apache.org on 2008/10/24 02:58:50 UTC

svn commit: r707519 - in /poi/trunk/src: java/org/apache/poi/hssf/model/ java/org/apache/poi/hssf/record/ java/org/apache/poi/hssf/usermodel/ java/org/apache/poi/util/ testcases/org/apache/poi/hssf/record/ testcases/org/apache/poi/util/

Author: josh
Date: Thu Oct 23 17:58:49 2008
New Revision: 707519

URL: http://svn.apache.org/viewvc?rev=707519&view=rev
Log:
Fix for unicode string bug in StyleRecord.  Improvements to WriteAccessRecord.

Added:
    poi/trunk/src/testcases/org/apache/poi/hssf/record/TestStyleRecord.java
Modified:
    poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java
    poi/trunk/src/java/org/apache/poi/hssf/record/StyleRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/WriteAccessRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
    poi/trunk/src/java/org/apache/poi/util/StringUtil.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java
    poi/trunk/src/testcases/org/apache/poi/util/TestStringUtil.java

Modified: poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java?rev=707519&r1=707518&r2=707519&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/model/Workbook.java Thu Oct 23 17:58:49 2008
@@ -788,7 +788,7 @@
             if(r instanceof ExtendedFormatRecord) {
             } else if(r instanceof StyleRecord) {
                 StyleRecord sr = (StyleRecord)r;
-                if(sr.getIndex() == xfIndex) {
+                if(sr.getXFIndex() == xfIndex) {
                     return sr;
                 }
             } else {
@@ -806,7 +806,7 @@
         // Style records always follow after 
         //  the ExtendedFormat records
         StyleRecord newSR = new StyleRecord();
-        newSR.setIndex((short)xfIndex);
+        newSR.setXFIndex(xfIndex);
         
         // Find the spot
         int addAt = -1;
@@ -1782,45 +1782,44 @@
      * @see org.apache.poi.hssf.record.StyleRecord
      * @see org.apache.poi.hssf.record.Record
      */
-
     protected Record createStyle(int id) {   // we'll need multiple editions
         StyleRecord retval = new StyleRecord();
 
         switch (id) {
 
             case 0 :
-                retval.setIndex(( short ) 0xffff8010);
-                retval.setBuiltin(( byte ) 3);
+                retval.setXFIndex(0x010);
+                retval.setBuiltinStyle(3);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 1 :
-                retval.setIndex(( short ) 0xffff8011);
-                retval.setBuiltin(( byte ) 6);
+                retval.setXFIndex(0x011);
+                retval.setBuiltinStyle(6);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 2 :
-                retval.setIndex(( short ) 0xffff8012);
-                retval.setBuiltin(( byte ) 4);
+                retval.setXFIndex(0x012);
+                retval.setBuiltinStyle(4);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 3 :
-                retval.setIndex(( short ) 0xffff8013);
-                retval.setBuiltin(( byte ) 7);
+                retval.setXFIndex(0x013);
+                retval.setBuiltinStyle(7);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 4 :
-                retval.setIndex(( short ) 0xffff8000);
-                retval.setBuiltin(( byte ) 0);
+                retval.setXFIndex(0x000);
+                retval.setBuiltinStyle(0);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 5 :
-                retval.setIndex(( short ) 0xffff8014);
-                retval.setBuiltin(( byte ) 5);
+                retval.setXFIndex(0x014);
+                retval.setBuiltinStyle(5);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
         }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/StyleRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/StyleRecord.java?rev=707519&r1=707518&r2=707519&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/StyleRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/StyleRecord.java Thu Oct 23 17:58:49 2008
@@ -19,332 +19,181 @@
 
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.StringUtil;
 
 /**
- * Title:        Style Record<P>
+ * Title:        Style Record (0x0293)<p/>
  * Description:  Describes a builtin to the gui or user defined style<P>
  * REFERENCE:  PG 390 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
  * @author Andrew C. Oliver (acoliver at apache dot org)
  * @author aviks : string fixes for UserDefined Style
- * @version 2.0-pre
  */
 public final class StyleRecord extends Record {
-    public final static short sid = 0x0293;
+	public final static short sid = 0x0293;
 
-    private static final BitField fHighByte = BitFieldFactory.getInstance(0x01);
+	private static final BitField is16BitUnicodeFlag = BitFieldFactory.getInstance(0x01);
 
-    public final static short STYLE_USER_DEFINED = 0;
-    public final static short STYLE_BUILT_IN     = 1;
+	private static final BitField styleIndexMask = BitFieldFactory.getInstance(0x0FFF);
+	private static final BitField isBuiltinFlag  = BitFieldFactory.getInstance(0x8000);
 
-    // shared by both user defined and builtin styles
-    private short             field_1_xf_index;   // TODO: bitfield candidate
-
-    // only for built in styles
-    private byte              field_2_builtin_style;
-    private byte              field_3_outline_style_level;
-
-    // only for user defined styles
-    private short              field_2_name_length; //OO doc says 16 bit length, so we believe
-    private byte               field_3_string_options;
-    private String             field_4_name;
-
-    public StyleRecord()
-    {
-    }
-
-    public StyleRecord(RecordInputStream in)
-    {
-        field_1_xf_index = in.readShort();
-        if (getType() == STYLE_BUILT_IN)
-        {
-            field_2_builtin_style       = in.readByte();
-            field_3_outline_style_level = in.readByte();
-        }
-        else if (getType() == STYLE_USER_DEFINED)
-        {
-            field_2_name_length = in.readShort();
-            
-            // Some files from Crystal Reports lack
-            //  the remaining fields, which is naughty
-            if(in.remaining() > 0) {
-	            field_3_string_options = in.readByte();
-	            
-	            byte[] string = in.readRemainder();
-	            if (fHighByte.isSet(field_3_string_options)) {
-	                field_4_name= StringUtil.getFromUnicodeBE(string, 0, field_2_name_length);
-	            } else {
-	                field_4_name=StringUtil.getFromCompressedUnicode(string, 0, field_2_name_length);
-	            }
-            }
-        }
-
-        // todo sanity check exception to make sure we're one or the other
-    }
-
-    /**
-     * set the entire index field (including the type) (see bit setters that reference this method)
-     *  @param index  bitmask
-     */
-
-    public void setIndex(short index)
-    {
-        field_1_xf_index = index;
-    }
-
-    // bitfields for field 1
-
-    /**
-     * set the type of the style (builtin or user-defined)
-     * @see #STYLE_USER_DEFINED
-     * @see #STYLE_BUILT_IN
-     * @param type of style (userdefined/builtin)
-     * @see #setIndex(short)
-     */
-
-    public void setType(short type)
-    {
-        field_1_xf_index = setField(field_1_xf_index, type, 0x8000, 15);
-    }
-
-    /**
-     * set the actual index of the style extended format record
-     * @see #setIndex(short)
-     * @param index of the xf record
-     */
-
-    public void setXFIndex(short index)
-    {
-        field_1_xf_index = setField(field_1_xf_index, index, 0x1FFF, 0);
-    }
-
-    // end bitfields
-    // only for user defined records
-
-    /**
-     * if this is a user defined record set the length of the style name
-     * @param length of the style's name
-     * @see #setName(String)
-     */
-
-    public void setNameLength(byte length)
-    {
-        field_2_name_length = length;
-    }
-
-    /**
-     * set the style's name
-     * @param name of the style
-     * @see #setNameLength(byte)
-     */
-
-    public void setName(String name)
-    {
-        field_4_name = name;
-        
-        // Fix up the length
-        field_2_name_length = (short)name.length();
-        //TODO set name string options
-    }
-
-    // end user defined
-    // only for buildin records
-
-    /**
-     * if this is a builtin style set teh number of the built in style
-     * @param  builtin style number (0-7)
-     *
-     */
-
-    public void setBuiltin(byte builtin)
-    {
-        field_2_builtin_style = builtin;
-    }
-
-    /**
-     * set the row or column level of the style (if builtin 1||2)
-     */
-
-    public void setOutlineStyleLevel(byte level)
-    {
-        field_3_outline_style_level = level;
-    }
-
-    // end builtin records
-    // field 1
-
-    /**
-     * get the entire index field (including the type) (see bit getters that reference this method)
-     *  @return bitmask
-     */
-
-    public short getIndex()
-    {
-        return field_1_xf_index;
-    }
-
-    // bitfields for field 1
-
-    /**
-     * get the type of the style (builtin or user-defined)
-     * @see #STYLE_USER_DEFINED
-     * @see #STYLE_BUILT_IN
-     * @return type of style (userdefined/builtin)
-     * @see #getIndex()
-     */
-
-    public short getType()
-    {
-        return ( short ) ((field_1_xf_index & 0x8000) >> 15);
-    }
-
-    /**
-     * get the actual index of the style extended format record
-     * @see #getIndex()
-     * @return index of the xf record
-     */
-
-    public short getXFIndex()
-    {
-        return ( short ) (field_1_xf_index & 0x1FFF);
-    }
-
-    // end bitfields
-    // only for user defined records
-
-    /**
-     * if this is a user defined record get the length of the style name
-     * @return length of the style's name
-     * @see #getName()
-     */
-
-    public short getNameLength()
-    {
-        return field_2_name_length;
-    }
-
-    /**
-     * get the style's name
-     * @return name of the style
-     * @see #getNameLength()
-     */
-
-    public String getName()
-    {
-        return field_4_name;
-    }
-
-    // end user defined
-    // only for buildin records
-
-    /**
-     * if this is a builtin style get the number of the built in style
-     * @return  builtin style number (0-7)
-     *
-     */
-
-    public byte getBuiltin()
-    {
-        return field_2_builtin_style;
-    }
-
-    /**
-     * get the row or column level of the style (if builtin 1||2)
-     */
-
-    public byte getOutlineStyleLevel()
-    {
-        return field_3_outline_style_level;
-    }
-
-    // end builtin records
-    public String toString()
-    {
-        StringBuffer buffer = new StringBuffer();
-
-        buffer.append("[STYLE]\n");
-        buffer.append("    .xf_index_raw    = ")
-            .append(Integer.toHexString(getIndex())).append("\n");
-        buffer.append("        .type        = ")
-            .append(Integer.toHexString(getType())).append("\n");
-        buffer.append("        .xf_index    = ")
-            .append(Integer.toHexString(getXFIndex())).append("\n");
-        if (getType() == STYLE_BUILT_IN)
-        {
-            buffer.append("    .builtin_style   = ")
-                .append(Integer.toHexString(getBuiltin())).append("\n");
-            buffer.append("    .outline_level   = ")
-                .append(Integer.toHexString(getOutlineStyleLevel()))
-                .append("\n");
-        }
-        else if (getType() == STYLE_USER_DEFINED)
-        {
-            buffer.append("    .name_length     = ")
-                .append(Integer.toHexString(getNameLength())).append("\n");
-            buffer.append("    .name            = ").append(getName())
-                .append("\n");
-        }
-        buffer.append("[/STYLE]\n");
-        return buffer.toString();
-    }
-
-    private short setField(int fieldValue, int new_value, int mask,
-                           int shiftLeft)
-    {
-        return ( short ) ((fieldValue & ~mask)
-                          | ((new_value << shiftLeft) & mask));
-    }
-
-    public int serialize(int offset, byte [] data)
-    {
-        LittleEndian.putShort(data, 0 + offset, sid);
-        if (getType() == STYLE_BUILT_IN)
-        {
-            LittleEndian.putShort(data, 2 + offset,
-                                  (( short ) 0x04));   // 4 bytes (8 total)
-        }
-        else
-        {
-            LittleEndian.putShort(data, 2 + offset,
-                                  (( short ) (getRecordSize()-4)));
-        }
-        LittleEndian.putShort(data, 4 + offset, getIndex());
-        if (getType() == STYLE_BUILT_IN)
-        {
-            data[ 6 + offset ] = getBuiltin();
-            data[ 7 + offset ] = getOutlineStyleLevel();
-        }
-        else
-        {
-            LittleEndian.putShort(data, 6 + offset , getNameLength());
-            data[8+offset]=this.field_3_string_options;
-            StringUtil.putCompressedUnicode(getName(), data, 9 + offset);
-        }
-        return getRecordSize();
-    }
-
-    public int getRecordSize()
-    {
-        int retval;
-
-        if (getType() == STYLE_BUILT_IN)
-        {
-            retval = 8;
-        }
-        else
-        {
-             if (fHighByte.isSet(field_3_string_options))  {
-                 retval= 9+2*getNameLength();
-             }else {
-                retval = 9 + getNameLength();
-             }
-        }
-        return retval;
-    }
-
-    public short getSid()
-    {
-        return sid;
-    }
+	/** shared by both user defined and built-in styles */
+	private int field_1_xf_index;
+
+	// only for built in styles
+	private int field_2_builtin_style;
+	private int field_3_outline_style_level;
+
+	// only for user defined styles
+	private int field_3_string_options;
+	private String field_4_name;
+
+	/**
+	 * creates a new style record, initially set to 'built-in'
+	 */
+	public StyleRecord() {
+		field_1_xf_index = isBuiltinFlag.set(field_1_xf_index);
+	}
+
+	public StyleRecord(RecordInputStream in) {
+		field_1_xf_index = in.readShort();
+		if (isBuiltin()) {
+			field_2_builtin_style	   = in.readByte();
+			field_3_outline_style_level = in.readByte();
+		} else {
+			int field_2_name_length = in.readShort();
+			
+			if(in.remaining() < 1) {
+				// Some files from Crystal Reports lack the is16BitUnicode byte
+				//  the remaining fields, which is naughty
+				if (field_2_name_length != 0) {
+					throw new RecordFormatException("Ran out of data reading style record");
+				}
+				// guess this is OK if the string length is zero
+				field_4_name = "";
+			} else {
+				
+				int is16BitUnicode = in.readByte();
+				if (is16BitUnicodeFlag.isSet(is16BitUnicode)) {
+					field_4_name = StringUtil.readUnicodeLE(in, field_2_name_length);
+				} else {
+					field_4_name = StringUtil.readCompressedUnicode(in, field_2_name_length);
+				}
+			}
+		}
+	}
+
+	/**
+	 * set the actual index of the style extended format record
+	 * @param xfIndex of the xf record
+	 */
+	public void setXFIndex(int xfIndex) {
+		field_1_xf_index = styleIndexMask.setValue(field_1_xf_index, xfIndex);
+	}
+
+	/**
+	 * get the actual index of the style extended format record
+	 * @see #getIndex()
+	 * @return index of the xf record
+	 */
+	public int getXFIndex() {
+		return styleIndexMask.getValue(field_1_xf_index);
+	}
+
+	/**
+	 * set the style's name
+	 * @param name of the style
+	 */
+	public void setName(String name) {
+		field_4_name = name;
+		field_3_string_options = StringUtil.hasMultibyte(name) ? 0x01 : 0x00;
+		field_1_xf_index = isBuiltinFlag.clear(field_1_xf_index);
+	}
+
+	/**
+	 * if this is a builtin style set the number of the built in style
+	 * @param  builtinStyleId style number (0-7)
+	 *
+	 */
+	public void setBuiltinStyle(int builtinStyleId) {
+		field_1_xf_index = isBuiltinFlag.set(field_1_xf_index);
+		field_2_builtin_style = builtinStyleId;
+	}
+
+	/**
+	 * set the row or column level of the style (if builtin 1||2)
+	 */
+	public void setOutlineStyleLevel(int level) {
+		field_3_outline_style_level = level & 0x00FF;
+	}
+
+	public boolean isBuiltin(){
+		return isBuiltinFlag.isSet(field_1_xf_index);
+	}
+
+	/**
+	 * get the style's name
+	 * @return name of the style
+	 */
+	public String getName() {
+		return field_4_name;
+	}
+
+	public String toString() {
+		StringBuffer sb = new StringBuffer();
+
+		sb.append("[STYLE]\n");
+		sb.append("    .xf_index_raw =").append(HexDump.shortToHex(field_1_xf_index)).append("\n");
+		sb.append("        .type     =").append(isBuiltin() ? "built-in" : "user-defined").append("\n");
+		sb.append("        .xf_index =").append(HexDump.shortToHex(getXFIndex())).append("\n");
+		if (isBuiltin()){
+			sb.append("    .builtin_style=").append(HexDump.byteToHex(field_2_builtin_style)).append("\n");
+			sb.append("    .outline_level=").append(HexDump.byteToHex(field_3_outline_style_level)).append("\n");
+		} else {
+			 sb.append("    .name        =").append(getName()).append("\n");
+		}
+		sb.append("[/STYLE]\n");
+		return sb.toString();
+	}
+
+	
+	private int getDataSize() {
+		if (isBuiltin()) {
+			return 4; // short, byte, byte
+		}
+		int size = 2 + 3; // short
+		if (is16BitUnicodeFlag.isSet(field_3_string_options))  {
+			size += 2 * field_4_name.length();
+		} else {
+			size += field_4_name.length();
+		}
+		return size;
+	}
+
+	public int serialize(int offset, byte [] data) {
+		int dataSize = getDataSize();
+		LittleEndian.putShort(data, 0 + offset, sid);
+		LittleEndian.putUShort(data, 2 + offset, dataSize);
+		
+		LittleEndian.putUShort(data, 4 + offset, field_1_xf_index);
+		if (isBuiltin()) {
+			LittleEndian.putByte(data, 6 + offset, field_2_builtin_style);
+			LittleEndian.putByte(data, 7 + offset, field_3_outline_style_level);
+		} else {
+			LittleEndian.putUShort(data, 6 + offset, field_4_name.length());
+			LittleEndian.putByte(data, 8 + offset, field_3_string_options);
+			StringUtil.putCompressedUnicode(getName(), data, 9 + offset);
+		}
+		return 4+dataSize;
+	}
+
+	public int getRecordSize() {
+		return 4 + getDataSize();
+	}
+
+	public short getSid()
+	{
+		return sid;
+	}
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/WriteAccessRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/WriteAccessRecord.java?rev=707519&r1=707518&r2=707519&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/WriteAccessRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/WriteAccessRecord.java Thu Oct 23 17:58:49 2008
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -15,111 +14,130 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
+import java.util.Arrays;
+
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.StringUtil;
 
 /**
- * Title:        Write Access Record<P>
- * Description:  Stores the username of that who owns the spreadsheet generator
- *               (on unix the user's login, on Windoze its the name you typed when
- *                you installed the thing)<P>
- * REFERENCE:  PG 424 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
+ * Title: Write Access Record (0x005C)<p/>
+ * 
+ * Description: Stores the username of that who owns the spreadsheet generator (on unix the user's 
+ * login, on Windoze its the name you typed when you installed the thing)
+ * <p/>
+ * REFERENCE: PG 424 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
+ * <p/>
+ * 
  * @author Andrew C. Oliver (acoliver at apache dot org)
- * @version 2.0-pre
  */
-
-public class WriteAccessRecord
-    extends Record
-{
-    public final static short sid = 0x5c;
-    private String            field_1_username;
-
-    public WriteAccessRecord()
-    {
-    }
-
-    public WriteAccessRecord(RecordInputStream in)
-    {
-        byte[] data = in.readRemainder();
-        //The string is always 112 characters (padded with spaces), therefore
-        //this record can not be continued.
-
-        //What a wierd record, it is not really a unicode string because the
-        //header doesnt provide a correct size indication.???
-        //But the header is present, so we need to skip over it.
-        //Odd, Odd, Odd ;-)
-        field_1_username = StringUtil.getFromCompressedUnicode(data, 3, data.length - 3);
-    }
-
-    /**
-     * set the username for the user that created the report.  HSSF uses the logged in user.
-     * @param username of the user who  is logged in (probably "tomcat" or "apache")
-     */
-
-    public void setUsername(String username)
-    {
-        field_1_username = username;
-    }
-
-    /**
-     * get the username for the user that created the report.  HSSF uses the logged in user.  On
-     * natively created M$ Excel sheet this would be the name you typed in when you installed it
-     * in most cases.
-     * @return username of the user who  is logged in (probably "tomcat" or "apache")
-     */
-
-    public String getUsername()
-    {
-        return field_1_username;
-    }
-
-    public String toString()
-    {
-        StringBuffer buffer = new StringBuffer();
-
-        buffer.append("[WRITEACCESS]\n");
-        buffer.append("    .name            = ")
-            .append(field_1_username.toString()).append("\n");
-        buffer.append("[/WRITEACCESS]\n");
-        return buffer.toString();
-    }
-
-    public int serialize(int offset, byte [] data)
-    {
-        String       username = getUsername();
-        StringBuffer temp     = new StringBuffer(0x70 - (0x3));
-
-        temp.append(username);
-        while (temp.length() < 0x70 - 0x3)
-        {
-            temp.append(
-                " ");   // (70 = fixed lenght -3 = the overhead bits of unicode string)
-        }
-        username = temp.toString();
-        UnicodeString str = new UnicodeString(username);
-        str.setOptionFlags(( byte ) 0x0);
-
-        LittleEndian.putShort(data, 0 + offset, sid);
-        LittleEndian.putShort(data, 2 + offset, (short)112);   // 112 bytes (115 total)
-        UnicodeString.UnicodeRecordStats stats = new UnicodeString.UnicodeRecordStats();
-        stats.recordSize += 4;
-        stats.remainingSize-= 4;
-        str.serialize(stats, 4 + offset, data);
-
-        return getRecordSize();
-    }
-
-    public int getRecordSize()
-    {
-        return 116;
-    }
-
-    public short getSid()
-    {
-        return sid;
-    }
+public final class WriteAccessRecord extends Record {
+	private static final byte PAD_CHAR = (byte) ' ';
+	public final static short sid = 0x005C;
+	private static final int DATA_SIZE = 112;
+	private String field_1_username;
+	/** this record is always padded to a constant length */
+	private byte[] padding;
+
+	public WriteAccessRecord() {
+		setUsername("");
+		padding = new byte[DATA_SIZE - 3];
+	}
+
+	public WriteAccessRecord(RecordInputStream in) {
+		if (in.remaining() > DATA_SIZE) {
+			throw new RecordFormatException("Expected data size (" + DATA_SIZE + ") but got ("
+					+ in.remaining() + ")");
+		}
+		// The string is always 112 characters (padded with spaces), therefore
+		// this record can not be continued.
+
+		int nChars = in.readUShort();
+		int is16BitFlag = in.readUByte();
+		int expectedPadSize = DATA_SIZE - 3;
+		if ((is16BitFlag & 0x01) == 0x00) {
+			field_1_username = StringUtil.readCompressedUnicode(in, nChars);
+			expectedPadSize -= nChars;
+		} else {
+			field_1_username = StringUtil.readUnicodeLE(in, nChars);
+			expectedPadSize -= nChars * 2;
+		}
+		padding = new byte[expectedPadSize];
+		int padSize = in.remaining();
+		in.readFully(padding, 0, padSize);
+		if (padSize < expectedPadSize) {
+			// this occurs in a couple of test examples: "42564.xls",
+			// "bug_42794.xls"
+			Arrays.fill(padding, padSize, expectedPadSize, PAD_CHAR);
+		}
+	}
+
+	/**
+	 * set the username for the user that created the report. HSSF uses the
+	 * logged in user.
+	 * 
+	 * @param username of the user who is logged in (probably "tomcat" or "apache")
+	 */
+	public void setUsername(String username) {
+		boolean is16bit = StringUtil.hasMultibyte(username);
+		int encodedByteCount = 3 + username.length() * (is16bit ? 2 : 1);
+		int paddingSize = DATA_SIZE - encodedByteCount;
+		if (paddingSize < 0) {
+			throw new IllegalArgumentException("Name is too long: " + username);
+		}
+		padding = new byte[paddingSize];
+		Arrays.fill(padding, PAD_CHAR);
+
+		field_1_username = username;
+	}
+
+	/**
+	 * get the username for the user that created the report. HSSF uses the
+	 * logged in user. On natively created M$ Excel sheet this would be the name
+	 * you typed in when you installed it in most cases.
+	 * 
+	 * @return username of the user who is logged in (probably "tomcat" or "apache")
+	 */
+	public String getUsername() {
+		return field_1_username;
+	}
+
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+
+		buffer.append("[WRITEACCESS]\n");
+		buffer.append("    .name            = ").append(field_1_username.toString()).append("\n");
+		buffer.append("[/WRITEACCESS]\n");
+		return buffer.toString();
+	}
+
+	public int serialize(int offset, byte[] data) {
+		String username = getUsername();
+		boolean is16bit = StringUtil.hasMultibyte(username);
+
+		LittleEndian.putUShort(data, 0 + offset, sid);
+		LittleEndian.putUShort(data, 2 + offset, DATA_SIZE);
+		LittleEndian.putUShort(data, 4 + offset, username.length());
+		LittleEndian.putByte(data, 6 + offset, is16bit ? 0x01 : 0x00);
+		int pos = offset + 7;
+		if (is16bit) {
+			StringUtil.putUnicodeLE(username, data, pos);
+			pos += username.length() * 2;
+		} else {
+			StringUtil.putCompressedUnicode(username, data, pos);
+			pos += username.length();
+		}
+		System.arraycopy(padding, 0, data, pos, padding.length);
+		return 4 + DATA_SIZE;
+	}
+
+	public int getRecordSize() {
+		return 4 + DATA_SIZE;
+	}
+
+	public short getSid() {
+		return sid;
+	}
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java?rev=707519&r1=707518&r2=707519&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java Thu Oct 23 17:58:49 2008
@@ -962,7 +962,7 @@
     	if(sr == null) {
     		return null;
     	}
-    	if(sr.getType() == StyleRecord.STYLE_BUILT_IN) {
+    	if(sr.isBuiltin()) {
     		return null;
     	}
     	return sr.getName();
@@ -977,7 +977,7 @@
     	if(sr == null) {
     		sr = workbook.createStyleRecord(index);
     	}
-    	if(sr.getType() == StyleRecord.STYLE_BUILT_IN) {
+    	if(sr.isBuiltin()) {
     		throw new IllegalArgumentException("Unable to set user specified style names for built in styles!");
     	}
     	sr.setName(styleName);

Modified: poi/trunk/src/java/org/apache/poi/util/StringUtil.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/util/StringUtil.java?rev=707519&r1=707518&r2=707519&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/util/StringUtil.java (original)
+++ poi/trunk/src/java/org/apache/poi/util/StringUtil.java Thu Oct 23 17:58:49 2008
@@ -20,9 +20,14 @@
 import java.io.UnsupportedEncodingException;
 import java.text.FieldPosition;
 import java.text.NumberFormat;
+
+import org.apache.poi.hssf.record.RecordInputStream;
 /**
- *  Title: String Utility Description: Collection of string handling utilities
- *
+ *  Title: String Utility Description: Collection of string handling utilities<p/>
+ *  
+ * Note - none of the methods in this class deals with {@link ContinueRecord}s.  For such
+ * functionality, consider using {@link RecordInputStream
+} *
  *
  *@author     Andrew C. Oliver
  *@author     Sergei Kozello (sergeikozello at mail.ru)
@@ -84,65 +89,12 @@
 	 * @param  string  the byte array to be converted
 	 * @return         the converted string
 	 */
-	public static String getFromUnicodeLE(final byte[] string) {
+	public static String getFromUnicodeLE(byte[] string) {
 		if(string.length == 0) { return ""; }
 		return getFromUnicodeLE(string, 0, string.length / 2);
 	}
 
 	/**
-	 *  Given a byte array of 16-bit unicode characters in big endian
-	 *  format (most important byte first), return a Java String representation
-	 *  of it.
-	 *
-	 * { 0x00, 0x16 } -0x16
-	 *
-	 * @param  string                              the byte array to be converted
-	 * @param  offset                              the initial offset into the
-	 *      byte array. it is assumed that string[ offset ] and string[ offset +
-	 *      1 ] contain the first 16-bit unicode character
-     * @param len the length of the final string
-	 * @return                                     the converted string
-	 * @exception  ArrayIndexOutOfBoundsException  if offset is out of bounds for
-	 *      the byte array (i.e., is negative or is greater than or equal to
-	 *      string.length)
-	 * @exception  IllegalArgumentException        if len is too large (i.e.,
-	 *      there is not enough data in string to create a String of that
-	 *      length)
-	 */
-	public static String getFromUnicodeBE(
-		final byte[] string,
-		final int offset,
-		final int len)
-		throws ArrayIndexOutOfBoundsException, IllegalArgumentException {
-		if ((offset < 0) || (offset >= string.length)) {
-			throw new ArrayIndexOutOfBoundsException("Illegal offset");
-		}
-		if ((len < 0) || (((string.length - offset) / 2) < len)) {
-			throw new IllegalArgumentException("Illegal length");
-		}
-		try {
-			return new String(string, offset, len * 2, "UTF-16BE");
-		} catch (UnsupportedEncodingException e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	/**
-	 *  Given a byte array of 16-bit unicode characters in big endian
-	 *  format (most important byte first), return a Java String representation
-	 *  of it.
-	 *
-	 * { 0x00, 0x16 } -0x16
-	 *
-	 * @param  string  the byte array to be converted
-	 * @return         the converted string
-	 */
-	public static String getFromUnicodeBE(final byte[] string) {
-		if(string.length == 0) { return ""; }
-		return getFromUnicodeBE(string, 0, string.length / 2);
-	}
-
-	/**
 	 * Read 8 bit data (in ISO-8859-1 codepage) into a (unicode) Java
 	 * String and return.
 	 * (In Excel terms, read compressed 8 bit unicode as a string)
@@ -163,6 +115,31 @@
 			throw new RuntimeException(e);
 		}
 	}
+	public static String readCompressedUnicode(LittleEndianInput in, int nChars) {
+		char[] buf = new char[nChars];
+		for (int i = 0; i < buf.length; i++) {
+			buf[i] = (char) in.readUByte();
+		}
+		return new String(buf);
+	}
+	/**
+	 * InputStream <tt>in</tt> is expected to contain:
+	 * <ol>
+	 * <li>ushort nChars</li>
+	 * <li>byte is16BitFlag</li>
+	 * <li>byte[]/char[] characterData</li>
+	 * </ol>
+	 * For this encoding, the is16BitFlag is always present even if nChars==0.
+	 */
+	public static String readUnicodeString(LittleEndianInput in) {
+		
+		int nChars = in.readUShort();
+		byte flag = in.readByte();
+		if ((flag & 0x01) == 0) {
+			return readCompressedUnicode(in, nChars);
+		}
+		return readUnicodeLE(in, nChars);
+	}
 
 	/**
 	 * Takes a unicode (java) string, and returns it as 8 bit data (in ISO-8859-1
@@ -220,6 +197,14 @@
 		}
 		out.write(bytes);
 	}
+	
+	public static String readUnicodeLE(LittleEndianInput in, int nChars) {
+		char[] buf = new char[nChars];
+		for (int i = 0; i < buf.length; i++) {
+			buf[i] = (char) in.readUShort();
+		}
+		return new String(buf);
+	}
 
 	/**
 	 *  Apply printf() like formatting to a string.

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java?rev=707519&r1=707518&r2=707519&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java Thu Oct 23 17:58:49 2008
@@ -100,6 +100,7 @@
 		result.addTestSuite(TestSheetPropertiesRecord.class);
 		result.addTestSuite(TestSharedFormulaRecord.class);
 		result.addTestSuite(TestStringRecord.class);
+		result.addTestSuite(TestStyleRecord.class);
 		result.addTestSuite(TestSubRecord.class);
 		result.addTestSuite(TestSupBookRecord.class);
 		result.addTestSuite(TestTableRecord.class);

Added: poi/trunk/src/testcases/org/apache/poi/hssf/record/TestStyleRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/TestStyleRecord.java?rev=707519&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/TestStyleRecord.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/TestStyleRecord.java Thu Oct 23 17:58:49 2008
@@ -0,0 +1,33 @@
+/* ====================================================================
+   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.hssf.record;
+
+import junit.framework.TestCase;
+/**
+ * 
+ */
+public final class TestStyleRecord extends TestCase {
+    public void testUnicodeReadName() {
+    	byte[] data = {
+   			17, 0, 9, 0, 1, 56, 94, -60, -119, 95, 0, 83, 0, 104, 0, 101, 0, 101, 0, 116, 0, 49, 0, 92, 40, //92, 36    			
+    	};
+    	RecordInputStream in = TestcaseRecordInputStream.create(StyleRecord.sid, data);
+    	StyleRecord sr = new StyleRecord(in);
+    	assertEquals("\u5E38\u89C4_Sheet1", sr.getName()); // "<Conventional>_Sheet1"
+    }
+}

Modified: poi/trunk/src/testcases/org/apache/poi/util/TestStringUtil.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/util/TestStringUtil.java?rev=707519&r1=707518&r2=707519&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/util/TestStringUtil.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/util/TestStringUtil.java Thu Oct 23 17:58:49 2008
@@ -42,43 +42,7 @@
         super( name );
     }
 
-    /**
-     * test simple form of getFromUnicode
-     */
-    public void testSimpleGetFromUnicode()
-    {
-        byte[] test_data = new byte[32];
-        int index = 0;
-
-        for ( int k = 0; k < 16; k++ )
-        {
-            test_data[index++] = (byte) 0;
-            test_data[index++] = (byte) ( 'a' + k );
-        }
-
-        assertEquals( "abcdefghijklmnop",
-                StringUtil.getFromUnicodeBE( test_data ) );
-    }
-
-    /**
-     * test simple form of getFromUnicode with symbols with code below and more 127
-     */
-    public void testGetFromUnicodeSymbolsWithCodesMoreThan127()
-    {
-        byte[] test_data = new byte[]{0x04, 0x22,
-                                      0x04, 0x35,
-                                      0x04, 0x41,
-                                      0x04, 0x42,
-                                      0x00, 0x20,
-                                      0x00, 0x74,
-                                      0x00, 0x65,
-                                      0x00, 0x73,
-                                      0x00, 0x74,
-        };
 
-        assertEquals( "\u0422\u0435\u0441\u0442 test",
-                StringUtil.getFromUnicodeBE( test_data ) );
-    }
 
     /**
      * test getFromUnicodeHigh for symbols with code below and more 127
@@ -101,62 +65,7 @@
                 StringUtil.getFromUnicodeLE( test_data ) );
     }
 
-    /**
-     * Test more complex form of getFromUnicode
-     */
-    public void testComplexGetFromUnicode()
-    {
-        byte[] test_data = new byte[32];
-        int index = 0;
-        for ( int k = 0; k < 16; k++ )
-        {
-            test_data[index++] = (byte) 0;
-            test_data[index++] = (byte) ( 'a' + k );
-        }
-        assertEquals( "abcdefghijklmno",
-                StringUtil.getFromUnicodeBE( test_data, 0, 15 ) );
-        assertEquals( "bcdefghijklmnop",
-                StringUtil.getFromUnicodeBE( test_data, 2, 15 ) );
-        try
-        {
-            StringUtil.getFromUnicodeBE( test_data, -1, 16 );
-            fail( "Should have caught ArrayIndexOutOfBoundsException" );
-        }
-        catch ( ArrayIndexOutOfBoundsException ignored )
-        {
-            // as expected
-        }
 
-        try
-        {
-            StringUtil.getFromUnicodeBE( test_data, 32, 16 );
-            fail( "Should have caught ArrayIndexOutOfBoundsException" );
-        }
-        catch ( ArrayIndexOutOfBoundsException ignored )
-        {
-            // as expected
-        }
-
-        try
-        {
-            StringUtil.getFromUnicodeBE( test_data, 1, 16 );
-            fail( "Should have caught IllegalArgumentException" );
-        }
-        catch ( IllegalArgumentException ignored )
-        {
-            // as expected
-        }
-
-        try
-        {
-            StringUtil.getFromUnicodeBE( test_data, 1, -1 );
-            fail( "Should have caught IllegalArgumentException" );
-        }
-        catch ( IllegalArgumentException ignored )
-        {
-            // as expected
-        }
-    }
 
     /**
      * Test putCompressedUnicode



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org