You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by fa...@apache.org on 2021/05/22 20:56:49 UTC

svn commit: r1890120 [7/43] - in /poi/trunk/poi/src: main/java/org/apache/poi/ main/java/org/apache/poi/ddf/ main/java/org/apache/poi/extractor/ main/java/org/apache/poi/hpsf/ main/java/org/apache/poi/hssf/ main/java/org/apache/poi/hssf/dev/ main/java/...

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NameRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NameRecord.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NameRecord.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NameRecord.java Sat May 22 20:56:44 2021
@@ -38,427 +38,427 @@ import org.apache.poi.util.StringUtil;
 @SuppressWarnings("unused")
 public final class NameRecord extends ContinuableRecord {
     public static final short sid = 0x0018;
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_CONSOLIDATE_AREA      = 1;
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_AUTO_OPEN             = 2;
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_AUTO_CLOSE            = 3;
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_DATABASE              = 4;
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_CRITERIA              = 5;
-
-	public static final byte  BUILTIN_PRINT_AREA            = 6;
-	public static final byte  BUILTIN_PRINT_TITLE           = 7;
-
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_RECORDER              = 8;
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_DATA_FORM             = 9;
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_AUTO_ACTIVATE         = 10;
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_AUTO_DEACTIVATE       = 11;
-	/**Included for completeness sake, not implemented */
-	public static final byte  BUILTIN_SHEET_TITLE           = 12;
-
-	public static final byte  BUILTIN_FILTER_DB             = 13;
-
-	private static final class Option {
-		public static final int OPT_HIDDEN_NAME =   0x0001;
-		public static final int OPT_FUNCTION_NAME = 0x0002;
-		public static final int OPT_COMMAND_NAME =  0x0004;
-		public static final int OPT_MACRO =         0x0008;
-		public static final int OPT_COMPLEX =       0x0010;
-		public static final int OPT_BUILTIN =       0x0020;
-		public static final int OPT_BINDATA =       0x1000;
-		public static boolean isFormula(int optValue) {
-			return (optValue & 0x0F) == 0;
-		}
-	}
-
-	private short             field_1_option_flag;
-	private byte              field_2_keyboard_shortcut;
-	/** One-based extern index of sheet (resolved via LinkTable). Zero if this is a global name  */
-	private short             field_5_externSheetIndex_plus1;
-	/** the one based sheet number.  */
-	private int               field_6_sheetNumber;
-	private boolean           field_11_nameIsMultibyte;
-	private byte              field_12_built_in_code;
-	private String            field_12_name_text;
-	private Formula           field_13_name_definition;
-	private String            field_14_custom_menu_text;
-	private String            field_15_description_text;
-	private String            field_16_help_topic_text;
-	private String            field_17_status_bar_text;
-
-
-	/** Creates new NameRecord */
-	public NameRecord() {
-		field_13_name_definition = Formula.create(Ptg.EMPTY_PTG_ARRAY);
-
-		field_12_name_text = "";
-		field_14_custom_menu_text = "";
-		field_15_description_text = "";
-		field_16_help_topic_text = "";
-		field_17_status_bar_text = "";
-	}
-
-	public NameRecord(NameRecord other) {
-		super(other);
-		field_1_option_flag = other.field_1_option_flag;
-		field_2_keyboard_shortcut = other.field_2_keyboard_shortcut;
-		field_5_externSheetIndex_plus1 = other.field_5_externSheetIndex_plus1;
-		field_6_sheetNumber = other.field_6_sheetNumber;
-		field_11_nameIsMultibyte = other.field_11_nameIsMultibyte;
-		field_12_built_in_code = other.field_12_built_in_code;
-		field_12_name_text = other.field_12_name_text;
-		field_13_name_definition = other.field_13_name_definition;
-		field_14_custom_menu_text = other.field_14_custom_menu_text;
-		field_15_description_text = other.field_15_description_text;
-		field_16_help_topic_text = other.field_16_help_topic_text;
-		field_17_status_bar_text = other.field_17_status_bar_text;
-	}
-
-	/**
-	 * Constructor to create a built-in named region
-	 * @param builtin Built-in byte representation for the name record, use the public constants
-	 * @param sheetNumber the sheet which the name applies to
-	 */
-	public NameRecord(byte builtin, int sheetNumber)
-	{
-		this();
-		field_12_built_in_code = builtin;
-		setOptionFlag((short)(field_1_option_flag | Option.OPT_BUILTIN));
-		// the extern sheets are set through references
-		field_6_sheetNumber = sheetNumber;
-	}
-
-	/** sets the option flag for the named range
-	 * @param flag option flag
-	 */
-	public void setOptionFlag(short flag){
-		field_1_option_flag = flag;
-	}
-
-
-	/** sets the keyboard shortcut
-	 * @param shortcut keyboard shortcut
-	 */
-	public void setKeyboardShortcut(byte shortcut){
-		field_2_keyboard_shortcut = shortcut;
-	}
-
-	/**
-	 * For named ranges, and built-in names
-	 * @return the 1-based sheet number.
-	 */
-	public int getSheetNumber()
-	{
-		return field_6_sheetNumber;
-	}
-
-	/**
-	 * @return function group
-	 * @see FnGroupCountRecord
-	 */
-	public byte getFnGroup() {
-		int masked = field_1_option_flag & 0x0fc0;
-		return (byte) (masked >> 4);
-	}
-
-
-	public void setSheetNumber(int value)
-	{
-		field_6_sheetNumber = value;
-	}
-
-
-	/** sets the name of the named range
-	 * @param name named range name
-	 */
-	public void setNameText(String name){
-		field_12_name_text = name;
-		field_11_nameIsMultibyte = StringUtil.hasMultibyte(name);
-	}
-
-	/** sets the custom menu text
-	 * @param text custom menu text
-	 */
-	public void setCustomMenuText(String text){
-		field_14_custom_menu_text = text;
-	}
-
-	/** sets the description text
-	 * @param text the description text
-	 */
-	public void setDescriptionText(String text){
-		field_15_description_text = text;
-	}
-
-	/** sets the help topic text
-	 * @param text help topix text
-	 */
-	public void setHelpTopicText(String text){
-		field_16_help_topic_text = text;
-	}
-
-	/** sets the status bar text
-	 * @param text status bar text
-	 */
-	public void setStatusBarText(String text){
-		field_17_status_bar_text = text;
-	}
-
-	/** gets the option flag
-	 * @return option flag
-	 */
-	public short getOptionFlag(){
-		return field_1_option_flag;
-	}
-
-	/** returns the keyboard shortcut
-	 * @return keyboard shortcut
-	 */
-	public byte getKeyboardShortcut(){
-		return field_2_keyboard_shortcut ;
-	}
-
-	/**
-	 * gets the name length, in characters
-	 * @return name length
-	 */
-	private int getNameTextLength(){
-		if (isBuiltInName()) {
-			return 1;
-		}
-		return field_12_name_text.length();
-	}
-
-
-	/**
-	 * @return true if name is hidden
-	 */
-	public boolean isHiddenName() {
-		return (field_1_option_flag & Option.OPT_HIDDEN_NAME) != 0;
-	}
-
-	public void setHidden(boolean b) {
-		if (b) {
-			field_1_option_flag |= Option.OPT_HIDDEN_NAME;
-		} else {
-			field_1_option_flag &= (~Option.OPT_HIDDEN_NAME);
-		}
-	}
-	/**
-	 * @return <code>true</code> if name is a function
-	 */
-	public boolean isFunctionName() {
-		return (field_1_option_flag & Option.OPT_FUNCTION_NAME) != 0;
-	}
-
-	/**
-	 * Indicates that the defined name refers to a user-defined function.
-	 * This attribute is used when there is an add-in or other code project associated with the file.
-	 *
-	 * @param function <code>true</code> indicates the name refers to a function.
-	 */
-	public void setFunction(boolean function){
-		if (function) {
-			field_1_option_flag |= Option.OPT_FUNCTION_NAME;
-		} else {
-			field_1_option_flag &= (~Option.OPT_FUNCTION_NAME);
-		}
-	}
-
-	/**
-	 * @return <code>true</code> if name has a formula (named range or defined value)
-	 */
-	public boolean hasFormula() {
-		return Option.isFormula(field_1_option_flag) && field_13_name_definition.getEncodedTokenSize() > 0;
-	}
-
-	/**
-	 * @return true if name is a command
-	 */
-	public boolean isCommandName() {
-		return (field_1_option_flag & Option.OPT_COMMAND_NAME) != 0;
-	}
-	/**
-	 * @return true if function macro or command macro
-	 */
-	public boolean isMacro() {
-		return (field_1_option_flag & Option.OPT_MACRO) != 0;
-	}
-	/**
-	 * @return true if array formula or user defined
-	 */
-	public boolean isComplexFunction() {
-		return (field_1_option_flag & Option.OPT_COMPLEX) != 0;
-	}
-
-	/**
-	 * Convenience Function to determine if the name is a built-in name
-	 *
-	 * @return true, if the name is a built-in name
-	 */
-	public boolean isBuiltInName()
-	{
-		return ((field_1_option_flag & Option.OPT_BUILTIN) != 0);
-	}
-
-
-	/** gets the name
-	 * @return name
-	 */
-	public String getNameText(){
-
-		return isBuiltInName() ? translateBuiltInName(getBuiltInName()) : field_12_name_text;
-	}
-
-	/** Gets the Built In Name
-	 * @return the built in Name
-	 */
-	public byte getBuiltInName()
-	{
-		return field_12_built_in_code;
-	}
-
-
-	/** gets the definition, reference (Formula)
-	 * @return the name formula. never <code>null</code>
-	 */
-	public Ptg[] getNameDefinition() {
-		return field_13_name_definition.getTokens();
-	}
-
-	public void setNameDefinition(Ptg[] ptgs) {
-		field_13_name_definition = Formula.create(ptgs);
-	}
-
-	/** get the custom menu text
-	 * @return custom menu text
-	 */
-	public String getCustomMenuText(){
-		return field_14_custom_menu_text;
-	}
-
-	/** gets the description text
-	 * @return description text
-	 */
-	public String getDescriptionText(){
-		return field_15_description_text;
-	}
-
-	/** get the help topic text
-	 * @return gelp topic text
-	 */
-	public String getHelpTopicText(){
-		return field_16_help_topic_text;
-	}
-
-	/** gets the status bar text
-	 * @return status bar text
-	 */
-	public String getStatusBarText(){
-		return field_17_status_bar_text;
-	}
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_CONSOLIDATE_AREA      = 1;
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_AUTO_OPEN             = 2;
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_AUTO_CLOSE            = 3;
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_DATABASE              = 4;
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_CRITERIA              = 5;
+
+    public static final byte  BUILTIN_PRINT_AREA            = 6;
+    public static final byte  BUILTIN_PRINT_TITLE           = 7;
+
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_RECORDER              = 8;
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_DATA_FORM             = 9;
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_AUTO_ACTIVATE         = 10;
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_AUTO_DEACTIVATE       = 11;
+    /**Included for completeness sake, not implemented */
+    public static final byte  BUILTIN_SHEET_TITLE           = 12;
+
+    public static final byte  BUILTIN_FILTER_DB             = 13;
+
+    private static final class Option {
+        public static final int OPT_HIDDEN_NAME =   0x0001;
+        public static final int OPT_FUNCTION_NAME = 0x0002;
+        public static final int OPT_COMMAND_NAME =  0x0004;
+        public static final int OPT_MACRO =         0x0008;
+        public static final int OPT_COMPLEX =       0x0010;
+        public static final int OPT_BUILTIN =       0x0020;
+        public static final int OPT_BINDATA =       0x1000;
+        public static boolean isFormula(int optValue) {
+            return (optValue & 0x0F) == 0;
+        }
+    }
+
+    private short             field_1_option_flag;
+    private byte              field_2_keyboard_shortcut;
+    /** One-based extern index of sheet (resolved via LinkTable). Zero if this is a global name  */
+    private short             field_5_externSheetIndex_plus1;
+    /** the one based sheet number.  */
+    private int               field_6_sheetNumber;
+    private boolean           field_11_nameIsMultibyte;
+    private byte              field_12_built_in_code;
+    private String            field_12_name_text;
+    private Formula           field_13_name_definition;
+    private String            field_14_custom_menu_text;
+    private String            field_15_description_text;
+    private String            field_16_help_topic_text;
+    private String            field_17_status_bar_text;
+
+
+    /** Creates new NameRecord */
+    public NameRecord() {
+        field_13_name_definition = Formula.create(Ptg.EMPTY_PTG_ARRAY);
+
+        field_12_name_text = "";
+        field_14_custom_menu_text = "";
+        field_15_description_text = "";
+        field_16_help_topic_text = "";
+        field_17_status_bar_text = "";
+    }
+
+    public NameRecord(NameRecord other) {
+        super(other);
+        field_1_option_flag = other.field_1_option_flag;
+        field_2_keyboard_shortcut = other.field_2_keyboard_shortcut;
+        field_5_externSheetIndex_plus1 = other.field_5_externSheetIndex_plus1;
+        field_6_sheetNumber = other.field_6_sheetNumber;
+        field_11_nameIsMultibyte = other.field_11_nameIsMultibyte;
+        field_12_built_in_code = other.field_12_built_in_code;
+        field_12_name_text = other.field_12_name_text;
+        field_13_name_definition = other.field_13_name_definition;
+        field_14_custom_menu_text = other.field_14_custom_menu_text;
+        field_15_description_text = other.field_15_description_text;
+        field_16_help_topic_text = other.field_16_help_topic_text;
+        field_17_status_bar_text = other.field_17_status_bar_text;
+    }
+
+    /**
+     * Constructor to create a built-in named region
+     * @param builtin Built-in byte representation for the name record, use the public constants
+     * @param sheetNumber the sheet which the name applies to
+     */
+    public NameRecord(byte builtin, int sheetNumber)
+    {
+        this();
+        field_12_built_in_code = builtin;
+        setOptionFlag((short)(field_1_option_flag | Option.OPT_BUILTIN));
+        // the extern sheets are set through references
+        field_6_sheetNumber = sheetNumber;
+    }
+
+    /** sets the option flag for the named range
+     * @param flag option flag
+     */
+    public void setOptionFlag(short flag){
+        field_1_option_flag = flag;
+    }
+
+
+    /** sets the keyboard shortcut
+     * @param shortcut keyboard shortcut
+     */
+    public void setKeyboardShortcut(byte shortcut){
+        field_2_keyboard_shortcut = shortcut;
+    }
+
+    /**
+     * For named ranges, and built-in names
+     * @return the 1-based sheet number.
+     */
+    public int getSheetNumber()
+    {
+        return field_6_sheetNumber;
+    }
+
+    /**
+     * @return function group
+     * @see FnGroupCountRecord
+     */
+    public byte getFnGroup() {
+        int masked = field_1_option_flag & 0x0fc0;
+        return (byte) (masked >> 4);
+    }
+
+
+    public void setSheetNumber(int value)
+    {
+        field_6_sheetNumber = value;
+    }
+
+
+    /** sets the name of the named range
+     * @param name named range name
+     */
+    public void setNameText(String name){
+        field_12_name_text = name;
+        field_11_nameIsMultibyte = StringUtil.hasMultibyte(name);
+    }
+
+    /** sets the custom menu text
+     * @param text custom menu text
+     */
+    public void setCustomMenuText(String text){
+        field_14_custom_menu_text = text;
+    }
+
+    /** sets the description text
+     * @param text the description text
+     */
+    public void setDescriptionText(String text){
+        field_15_description_text = text;
+    }
+
+    /** sets the help topic text
+     * @param text help topix text
+     */
+    public void setHelpTopicText(String text){
+        field_16_help_topic_text = text;
+    }
+
+    /** sets the status bar text
+     * @param text status bar text
+     */
+    public void setStatusBarText(String text){
+        field_17_status_bar_text = text;
+    }
+
+    /** gets the option flag
+     * @return option flag
+     */
+    public short getOptionFlag(){
+        return field_1_option_flag;
+    }
+
+    /** returns the keyboard shortcut
+     * @return keyboard shortcut
+     */
+    public byte getKeyboardShortcut(){
+        return field_2_keyboard_shortcut ;
+    }
+
+    /**
+     * gets the name length, in characters
+     * @return name length
+     */
+    private int getNameTextLength(){
+        if (isBuiltInName()) {
+            return 1;
+        }
+        return field_12_name_text.length();
+    }
+
+
+    /**
+     * @return true if name is hidden
+     */
+    public boolean isHiddenName() {
+        return (field_1_option_flag & Option.OPT_HIDDEN_NAME) != 0;
+    }
+
+    public void setHidden(boolean b) {
+        if (b) {
+            field_1_option_flag |= Option.OPT_HIDDEN_NAME;
+        } else {
+            field_1_option_flag &= (~Option.OPT_HIDDEN_NAME);
+        }
+    }
+    /**
+     * @return <code>true</code> if name is a function
+     */
+    public boolean isFunctionName() {
+        return (field_1_option_flag & Option.OPT_FUNCTION_NAME) != 0;
+    }
+
+    /**
+     * Indicates that the defined name refers to a user-defined function.
+     * This attribute is used when there is an add-in or other code project associated with the file.
+     *
+     * @param function <code>true</code> indicates the name refers to a function.
+     */
+    public void setFunction(boolean function){
+        if (function) {
+            field_1_option_flag |= Option.OPT_FUNCTION_NAME;
+        } else {
+            field_1_option_flag &= (~Option.OPT_FUNCTION_NAME);
+        }
+    }
+
+    /**
+     * @return <code>true</code> if name has a formula (named range or defined value)
+     */
+    public boolean hasFormula() {
+        return Option.isFormula(field_1_option_flag) && field_13_name_definition.getEncodedTokenSize() > 0;
+    }
+
+    /**
+     * @return true if name is a command
+     */
+    public boolean isCommandName() {
+        return (field_1_option_flag & Option.OPT_COMMAND_NAME) != 0;
+    }
+    /**
+     * @return true if function macro or command macro
+     */
+    public boolean isMacro() {
+        return (field_1_option_flag & Option.OPT_MACRO) != 0;
+    }
+    /**
+     * @return true if array formula or user defined
+     */
+    public boolean isComplexFunction() {
+        return (field_1_option_flag & Option.OPT_COMPLEX) != 0;
+    }
+
+    /**
+     * Convenience Function to determine if the name is a built-in name
+     *
+     * @return true, if the name is a built-in name
+     */
+    public boolean isBuiltInName()
+    {
+        return ((field_1_option_flag & Option.OPT_BUILTIN) != 0);
+    }
+
+
+    /** gets the name
+     * @return name
+     */
+    public String getNameText(){
+
+        return isBuiltInName() ? translateBuiltInName(getBuiltInName()) : field_12_name_text;
+    }
+
+    /** Gets the Built In Name
+     * @return the built in Name
+     */
+    public byte getBuiltInName()
+    {
+        return field_12_built_in_code;
+    }
+
+
+    /** gets the definition, reference (Formula)
+     * @return the name formula. never <code>null</code>
+     */
+    public Ptg[] getNameDefinition() {
+        return field_13_name_definition.getTokens();
+    }
+
+    public void setNameDefinition(Ptg[] ptgs) {
+        field_13_name_definition = Formula.create(ptgs);
+    }
+
+    /** get the custom menu text
+     * @return custom menu text
+     */
+    public String getCustomMenuText(){
+        return field_14_custom_menu_text;
+    }
+
+    /** gets the description text
+     * @return description text
+     */
+    public String getDescriptionText(){
+        return field_15_description_text;
+    }
+
+    /** get the help topic text
+     * @return gelp topic text
+     */
+    public String getHelpTopicText(){
+        return field_16_help_topic_text;
+    }
+
+    /** gets the status bar text
+     * @return status bar text
+     */
+    public String getStatusBarText(){
+        return field_17_status_bar_text;
+    }
 
     /**
      * NameRecord can span into
      *
      * @param out a data output stream
      */
-	@Override
+    @Override
     public void serialize(ContinuableRecordOutput out) {
 
-		int field_7_length_custom_menu = field_14_custom_menu_text.length();
-		int field_8_length_description_text = field_15_description_text.length();
-		int field_9_length_help_topic_text = field_16_help_topic_text.length();
-		int field_10_length_status_bar_text = field_17_status_bar_text.length();
-
-		// size defined below
-		out.writeShort(getOptionFlag());
-		out.writeByte(getKeyboardShortcut());
-		out.writeByte(getNameTextLength());
-		// Note - formula size is not immediately before encoded formula, and does not include any array constant data
-		out.writeShort(field_13_name_definition.getEncodedTokenSize());
-		out.writeShort(field_5_externSheetIndex_plus1);
-		out.writeShort(field_6_sheetNumber);
-		out.writeByte(field_7_length_custom_menu);
-		out.writeByte(field_8_length_description_text);
-		out.writeByte(field_9_length_help_topic_text);
-		out.writeByte(field_10_length_status_bar_text);
-		out.writeByte(field_11_nameIsMultibyte ? 1 : 0);
-
-		if (isBuiltInName()) {
-			//can send the builtin name directly in
-			out.writeByte(field_12_built_in_code);
-		} else {
-			String nameText = field_12_name_text;
-			if (field_11_nameIsMultibyte) {
-				StringUtil.putUnicodeLE(nameText, out);
-			} else {
-				StringUtil.putCompressedUnicode(nameText, out);
-			}
-		}
-		field_13_name_definition.serializeTokens(out);
-		field_13_name_definition.serializeArrayConstantData(out);
-
-		StringUtil.putCompressedUnicode( getCustomMenuText(), out);
-		StringUtil.putCompressedUnicode( getDescriptionText(), out);
-		StringUtil.putCompressedUnicode( getHelpTopicText(), out);
-		StringUtil.putCompressedUnicode( getStatusBarText(), out);
-	}
-	private int getNameRawSize() {
-		if (isBuiltInName()) {
-			return 1;
-		}
-		int nChars = field_12_name_text.length();
-		if(field_11_nameIsMultibyte) {
-			return 2 * nChars;
-		}
-		return nChars;
-	}
-
-	int getDataSize() {
-		return 13 // 3 shorts + 7 bytes
-			+ getNameRawSize()
-			+ field_14_custom_menu_text.length()
-			+ field_15_description_text.length()
-			+ field_16_help_topic_text.length()
-			+ field_17_status_bar_text.length()
-			+ field_13_name_definition.getEncodedSize();
-	}
-
-	/** gets the extern sheet number
-	 * @return extern sheet index
-	 */
-	public int getExternSheetNumber(){
-	    Ptg[] tokens = field_13_name_definition.getTokens();
-		if (tokens.length == 0) {
-			return 0;
-		}
-
-		Ptg ptg = tokens[0];
-		if (ptg.getClass() == Area3DPtg.class){
-			return ((Area3DPtg) ptg).getExternSheetIndex();
-
-		}
-		if (ptg.getClass() == Ref3DPtg.class){
-			return ((Ref3DPtg) ptg).getExternSheetIndex();
-		}
-		return 0;
-	}
-
-	/**
-	 * called by the constructor, should set class level fields.  Should throw
-	 * runtime exception for bad/icomplete data.
-	 *
-	 * @param ris the RecordInputstream to read the record from
-	 */
-	public NameRecord(RecordInputStream ris) {
+        int field_7_length_custom_menu = field_14_custom_menu_text.length();
+        int field_8_length_description_text = field_15_description_text.length();
+        int field_9_length_help_topic_text = field_16_help_topic_text.length();
+        int field_10_length_status_bar_text = field_17_status_bar_text.length();
+
+        // size defined below
+        out.writeShort(getOptionFlag());
+        out.writeByte(getKeyboardShortcut());
+        out.writeByte(getNameTextLength());
+        // Note - formula size is not immediately before encoded formula, and does not include any array constant data
+        out.writeShort(field_13_name_definition.getEncodedTokenSize());
+        out.writeShort(field_5_externSheetIndex_plus1);
+        out.writeShort(field_6_sheetNumber);
+        out.writeByte(field_7_length_custom_menu);
+        out.writeByte(field_8_length_description_text);
+        out.writeByte(field_9_length_help_topic_text);
+        out.writeByte(field_10_length_status_bar_text);
+        out.writeByte(field_11_nameIsMultibyte ? 1 : 0);
+
+        if (isBuiltInName()) {
+            //can send the builtin name directly in
+            out.writeByte(field_12_built_in_code);
+        } else {
+            String nameText = field_12_name_text;
+            if (field_11_nameIsMultibyte) {
+                StringUtil.putUnicodeLE(nameText, out);
+            } else {
+                StringUtil.putCompressedUnicode(nameText, out);
+            }
+        }
+        field_13_name_definition.serializeTokens(out);
+        field_13_name_definition.serializeArrayConstantData(out);
+
+        StringUtil.putCompressedUnicode( getCustomMenuText(), out);
+        StringUtil.putCompressedUnicode( getDescriptionText(), out);
+        StringUtil.putCompressedUnicode( getHelpTopicText(), out);
+        StringUtil.putCompressedUnicode( getStatusBarText(), out);
+    }
+    private int getNameRawSize() {
+        if (isBuiltInName()) {
+            return 1;
+        }
+        int nChars = field_12_name_text.length();
+        if(field_11_nameIsMultibyte) {
+            return 2 * nChars;
+        }
+        return nChars;
+    }
+
+    int getDataSize() {
+        return 13 // 3 shorts + 7 bytes
+            + getNameRawSize()
+            + field_14_custom_menu_text.length()
+            + field_15_description_text.length()
+            + field_16_help_topic_text.length()
+            + field_17_status_bar_text.length()
+            + field_13_name_definition.getEncodedSize();
+    }
+
+    /** gets the extern sheet number
+     * @return extern sheet index
+     */
+    public int getExternSheetNumber(){
+        Ptg[] tokens = field_13_name_definition.getTokens();
+        if (tokens.length == 0) {
+            return 0;
+        }
+
+        Ptg ptg = tokens[0];
+        if (ptg.getClass() == Area3DPtg.class){
+            return ((Area3DPtg) ptg).getExternSheetIndex();
+
+        }
+        if (ptg.getClass() == Ref3DPtg.class){
+            return ((Ref3DPtg) ptg).getExternSheetIndex();
+        }
+        return 0;
+    }
+
+    /**
+     * called by the constructor, should set class level fields.  Should throw
+     * runtime exception for bad/icomplete data.
+     *
+     * @param ris the RecordInputstream to read the record from
+     */
+    public NameRecord(RecordInputStream ris) {
         // YK: Formula data can span into continue records, for example,
         // when containing a large array of strings. See Bugzilla 50244
 
@@ -466,151 +466,151 @@ public final class NameRecord extends Co
         byte[] remainder = ris.readAllContinuedRemainder();
         LittleEndianInput in = new LittleEndianByteArrayInputStream(remainder);
 
-		field_1_option_flag                 = in.readShort();
-		field_2_keyboard_shortcut           = in.readByte();
-		int field_3_length_name_text        = in.readUByte();
-		int field_4_length_name_definition  = in.readShort();
-		field_5_externSheetIndex_plus1      = in.readShort();
-		field_6_sheetNumber                 = in.readUShort();
-		int f7_customMenuLen      = in.readUByte();
-		int f8_descriptionTextLen = in.readUByte();
-		int f9_helpTopicTextLen  = in.readUByte();
-		int f10_statusBarTextLen = in.readUByte();
-
-		//store the name in byte form if it's a built-in name
-		field_11_nameIsMultibyte = (in.readByte() != 0);
-		if (isBuiltInName()) {
-			field_12_built_in_code = in.readByte();
-		} else {
-			if (field_11_nameIsMultibyte) {
-				field_12_name_text = StringUtil.readUnicodeLE(in, field_3_length_name_text);
-			} else {
-				field_12_name_text = StringUtil.readCompressedUnicode(in, field_3_length_name_text);
-			}
-		}
-
-		int nBytesAvailable = in.available() - (f7_customMenuLen
-				+ f8_descriptionTextLen + f9_helpTopicTextLen + f10_statusBarTextLen);
-		field_13_name_definition = Formula.read(field_4_length_name_definition, in, nBytesAvailable);
-
-		//Who says that this can only ever be compressed unicode???
-		field_14_custom_menu_text = StringUtil.readCompressedUnicode(in, f7_customMenuLen);
-		field_15_description_text = StringUtil.readCompressedUnicode(in, f8_descriptionTextLen);
-		field_16_help_topic_text  = StringUtil.readCompressedUnicode(in, f9_helpTopicTextLen);
-		field_17_status_bar_text  = StringUtil.readCompressedUnicode(in, f10_statusBarTextLen);
-	}
-
-	/**
-	 * return the non static version of the id for this record.
-	 */
-	@Override
+        field_1_option_flag                 = in.readShort();
+        field_2_keyboard_shortcut           = in.readByte();
+        int field_3_length_name_text        = in.readUByte();
+        int field_4_length_name_definition  = in.readShort();
+        field_5_externSheetIndex_plus1      = in.readShort();
+        field_6_sheetNumber                 = in.readUShort();
+        int f7_customMenuLen      = in.readUByte();
+        int f8_descriptionTextLen = in.readUByte();
+        int f9_helpTopicTextLen  = in.readUByte();
+        int f10_statusBarTextLen = in.readUByte();
+
+        //store the name in byte form if it's a built-in name
+        field_11_nameIsMultibyte = (in.readByte() != 0);
+        if (isBuiltInName()) {
+            field_12_built_in_code = in.readByte();
+        } else {
+            if (field_11_nameIsMultibyte) {
+                field_12_name_text = StringUtil.readUnicodeLE(in, field_3_length_name_text);
+            } else {
+                field_12_name_text = StringUtil.readCompressedUnicode(in, field_3_length_name_text);
+            }
+        }
+
+        int nBytesAvailable = in.available() - (f7_customMenuLen
+                + f8_descriptionTextLen + f9_helpTopicTextLen + f10_statusBarTextLen);
+        field_13_name_definition = Formula.read(field_4_length_name_definition, in, nBytesAvailable);
+
+        //Who says that this can only ever be compressed unicode???
+        field_14_custom_menu_text = StringUtil.readCompressedUnicode(in, f7_customMenuLen);
+        field_15_description_text = StringUtil.readCompressedUnicode(in, f8_descriptionTextLen);
+        field_16_help_topic_text  = StringUtil.readCompressedUnicode(in, f9_helpTopicTextLen);
+        field_17_status_bar_text  = StringUtil.readCompressedUnicode(in, f10_statusBarTextLen);
+    }
+
+    /**
+     * return the non static version of the id for this record.
+     */
+    @Override
     public short getSid() {
-		return sid;
-	}
-	/*
-	  20 00
-	  00
-	  01
-	  1A 00 // sz = 0x1A = 26
-	  00 00
-	  01 00
-	  00
-	  00
-	  00
-	  00
-	  00 // unicode flag
-	  07 // name
-
-	  29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26
-	  00 07 00 07 00 00 00 FF 00 10                   //  }
+        return sid;
+    }
+    /*
+      20 00
+      00
+      01
+      1A 00 // sz = 0x1A = 26
+      00 00
+      01 00
+      00
+      00
+      00
+      00
+      00 // unicode flag
+      07 // name
+
+      29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26
+      00 07 00 07 00 00 00 FF 00 10                   //  }
 
 
 
-	  20 00
-	  00
-	  01
-	  0B 00 // sz = 0xB = 11
-	  00 00
-	  01 00
-	  00
-	  00
-	  00
-	  00
-	  00 // unicode flag
-	  07 // name
+      20 00
+      00
+      01
+      0B 00 // sz = 0xB = 11
+      00 00
+      01 00
+      00
+      00
+      00
+      00
+      00 // unicode flag
+      07 // name
 
-	  3B 00 00 07 00 07 00 00 00 FF 00   // { 11 }
+      3B 00 00 07 00 07 00 00 00 FF 00   // { 11 }
   */
-	/*
-	  18, 00,
-	  1B, 00,
-
-	  20, 00,
-	  00,
-	  01,
-	  0B, 00,
-	  00,
-	  00,
-	  00,
-	  00,
-	  00,
-	  07,
-	  3B 00 00 07 00 07 00 00 00 FF 00 ]
-	 */
-
-	/**Creates a human readable name for built in types
-	 * @return Unknown if the built-in name cannot be translated
-	 */
-	private static String translateBuiltInName(byte name)
-	{
-		switch (name)
-		{
-			case NameRecord.BUILTIN_AUTO_ACTIVATE :     return "Auto_Activate";
-			case NameRecord.BUILTIN_AUTO_CLOSE :        return "Auto_Close";
-			case NameRecord.BUILTIN_AUTO_DEACTIVATE :   return "Auto_Deactivate";
-			case NameRecord.BUILTIN_AUTO_OPEN :         return "Auto_Open";
-			case NameRecord.BUILTIN_CONSOLIDATE_AREA :  return "Consolidate_Area";
-			case NameRecord.BUILTIN_CRITERIA :          return "Criteria";
-			case NameRecord.BUILTIN_DATABASE :          return "Database";
-			case NameRecord.BUILTIN_DATA_FORM :         return "Data_Form";
-			case NameRecord.BUILTIN_PRINT_AREA :        return "Print_Area";
-			case NameRecord.BUILTIN_PRINT_TITLE :       return "Print_Titles";
-			case NameRecord.BUILTIN_RECORDER :          return "Recorder";
-			case NameRecord.BUILTIN_SHEET_TITLE :       return "Sheet_Title";
-			case NameRecord.BUILTIN_FILTER_DB  :        return "_FilterDatabase";
-
-		}
-
-		return "Unknown";
-	}
-
-	@Override
-	public NameRecord copy() {
-		return new NameRecord(this);
-	}
-
-	@Override
-	public HSSFRecordTypes getGenericRecordType() {
-		return HSSFRecordTypes.NAME;
-	}
-
-	@Override
-	public Map<String, Supplier<?>> getGenericProperties() {
-		final Map<String,Supplier<?>> m = new LinkedHashMap<>();
-		m.put("dataSize", this::getDataSize);
-		m.put("optionFlag", this::getOptionFlag);
-		m.put("keyboardShortcut", this::getKeyboardShortcut);
-		m.put("externSheetIndex", () -> field_5_externSheetIndex_plus1);
-		m.put("sheetNumber", this::getSheetNumber);
-		m.put("nameIsMultibyte", () -> field_11_nameIsMultibyte);
-		m.put("builtInName", this::getBuiltInName);
-		m.put("nameLength", this::getNameTextLength);
-		m.put("nameText", this::getNameText);
-		m.put("formula", this::getNameDefinition);
-		m.put("customMenuText", this::getCustomMenuText);
-		m.put("descriptionText", this::getDescriptionText);
-		m.put("helpTopicText", this::getHelpTopicText);
-		m.put("statusBarText", this::getStatusBarText);
-		return Collections.unmodifiableMap(m);
-	}
+    /*
+      18, 00,
+      1B, 00,
+
+      20, 00,
+      00,
+      01,
+      0B, 00,
+      00,
+      00,
+      00,
+      00,
+      00,
+      07,
+      3B 00 00 07 00 07 00 00 00 FF 00 ]
+     */
+
+    /**Creates a human readable name for built in types
+     * @return Unknown if the built-in name cannot be translated
+     */
+    private static String translateBuiltInName(byte name)
+    {
+        switch (name)
+        {
+            case NameRecord.BUILTIN_AUTO_ACTIVATE :     return "Auto_Activate";
+            case NameRecord.BUILTIN_AUTO_CLOSE :        return "Auto_Close";
+            case NameRecord.BUILTIN_AUTO_DEACTIVATE :   return "Auto_Deactivate";
+            case NameRecord.BUILTIN_AUTO_OPEN :         return "Auto_Open";
+            case NameRecord.BUILTIN_CONSOLIDATE_AREA :  return "Consolidate_Area";
+            case NameRecord.BUILTIN_CRITERIA :          return "Criteria";
+            case NameRecord.BUILTIN_DATABASE :          return "Database";
+            case NameRecord.BUILTIN_DATA_FORM :         return "Data_Form";
+            case NameRecord.BUILTIN_PRINT_AREA :        return "Print_Area";
+            case NameRecord.BUILTIN_PRINT_TITLE :       return "Print_Titles";
+            case NameRecord.BUILTIN_RECORDER :          return "Recorder";
+            case NameRecord.BUILTIN_SHEET_TITLE :       return "Sheet_Title";
+            case NameRecord.BUILTIN_FILTER_DB  :        return "_FilterDatabase";
+
+        }
+
+        return "Unknown";
+    }
+
+    @Override
+    public NameRecord copy() {
+        return new NameRecord(this);
+    }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.NAME;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+        m.put("dataSize", this::getDataSize);
+        m.put("optionFlag", this::getOptionFlag);
+        m.put("keyboardShortcut", this::getKeyboardShortcut);
+        m.put("externSheetIndex", () -> field_5_externSheetIndex_plus1);
+        m.put("sheetNumber", this::getSheetNumber);
+        m.put("nameIsMultibyte", () -> field_11_nameIsMultibyte);
+        m.put("builtInName", this::getBuiltInName);
+        m.put("nameLength", this::getNameTextLength);
+        m.put("nameText", this::getNameText);
+        m.put("formula", this::getNameDefinition);
+        m.put("customMenuText", this::getCustomMenuText);
+        m.put("descriptionText", this::getDescriptionText);
+        m.put("helpTopicText", this::getHelpTopicText);
+        m.put("statusBarText", this::getStatusBarText);
+        return Collections.unmodifiableMap(m);
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NoteRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NoteRecord.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NoteRecord.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NoteRecord.java Sat May 22 20:56:44 2021
@@ -28,237 +28,237 @@ import org.apache.poi.util.StringUtil;
  * NOTE: Comment Associated with a Cell (0x001C)
  */
 public final class NoteRecord extends StandardRecord {
-	public static final short sid = 0x001C;
+    public static final short sid = 0x001C;
 
-	public static final NoteRecord[] EMPTY_ARRAY = { };
+    public static final NoteRecord[] EMPTY_ARRAY = { };
 
-	/**
-	 * Flag indicating that the comment is hidden (default)
-	 */
-	public static final short NOTE_HIDDEN = 0x0;
-
-	/**
-	 * Flag indicating that the comment is visible
-	 */
-	public static final short NOTE_VISIBLE = 0x2;
-
-	private static final Byte DEFAULT_PADDING = (byte) 0;
-
-	private int field_1_row;
-	private int field_2_col;
-	private short field_3_flags;
-	private int field_4_shapeid;
-	private boolean field_5_hasMultibyte;
-	private String field_6_author;
-
-	/**
-	 * Saves padding byte value to reduce delta during round-trip serialization.<br>
-	 *
-	 * The documentation is not clear about how padding should work.  In any case
-	 * Excel(2007) does something different.
-	 */
-	private Byte field_7_padding;
-
-	/**
-	 * Construct a new <code>NoteRecord</code> and
-	 * fill its data with the default values
-	 */
-	public NoteRecord() {
-		field_6_author = "";
-		field_3_flags = 0;
-		field_7_padding = DEFAULT_PADDING; // seems to be always present regardless of author text
-	}
-
-	public NoteRecord(NoteRecord other) {
-		super(other);
-		field_1_row = other.field_1_row;
-		field_2_col = other.field_2_col;
-		field_3_flags = other.field_3_flags;
-		field_4_shapeid = other.field_4_shapeid;
-		field_5_hasMultibyte = other.field_5_hasMultibyte;
-		field_6_author = other.field_6_author;
-		field_7_padding = other.field_7_padding;
-	}
-
-	/**
-	 * @return id of this record.
-	 */
-	public short getSid() {
-		return sid;
-	}
-
-	/**
-	 * Read the record data from the supplied <code>RecordInputStream</code>
-	 *
-	 * @param in the RecordInputStream to read from
-	 */
-	public NoteRecord(RecordInputStream in) {
-		field_1_row = in.readUShort();
-		field_2_col = in.readShort();
-		field_3_flags = in.readShort();
-		field_4_shapeid = in.readUShort();
-		int length = in.readShort();
-		field_5_hasMultibyte = in.readByte() != 0x00;
-		if (field_5_hasMultibyte) {
-			field_6_author = StringUtil.readUnicodeLE(in, length);
-		} else {
-			field_6_author = StringUtil.readCompressedUnicode(in, length);
-		}
- 		if (in.available() == 1) {
-			field_7_padding = in.readByte();
-		} else if (in.available() == 2 && length == 0) {
-		    // If there's no author, may be double padded
+    /**
+     * Flag indicating that the comment is hidden (default)
+     */
+    public static final short NOTE_HIDDEN = 0x0;
+
+    /**
+     * Flag indicating that the comment is visible
+     */
+    public static final short NOTE_VISIBLE = 0x2;
+
+    private static final Byte DEFAULT_PADDING = (byte) 0;
+
+    private int field_1_row;
+    private int field_2_col;
+    private short field_3_flags;
+    private int field_4_shapeid;
+    private boolean field_5_hasMultibyte;
+    private String field_6_author;
+
+    /**
+     * Saves padding byte value to reduce delta during round-trip serialization.<br>
+     *
+     * The documentation is not clear about how padding should work.  In any case
+     * Excel(2007) does something different.
+     */
+    private Byte field_7_padding;
+
+    /**
+     * Construct a new <code>NoteRecord</code> and
+     * fill its data with the default values
+     */
+    public NoteRecord() {
+        field_6_author = "";
+        field_3_flags = 0;
+        field_7_padding = DEFAULT_PADDING; // seems to be always present regardless of author text
+    }
+
+    public NoteRecord(NoteRecord other) {
+        super(other);
+        field_1_row = other.field_1_row;
+        field_2_col = other.field_2_col;
+        field_3_flags = other.field_3_flags;
+        field_4_shapeid = other.field_4_shapeid;
+        field_5_hasMultibyte = other.field_5_hasMultibyte;
+        field_6_author = other.field_6_author;
+        field_7_padding = other.field_7_padding;
+    }
+
+    /**
+     * @return id of this record.
+     */
+    public short getSid() {
+        return sid;
+    }
+
+    /**
+     * Read the record data from the supplied <code>RecordInputStream</code>
+     *
+     * @param in the RecordInputStream to read from
+     */
+    public NoteRecord(RecordInputStream in) {
+        field_1_row = in.readUShort();
+        field_2_col = in.readShort();
+        field_3_flags = in.readShort();
+        field_4_shapeid = in.readUShort();
+        int length = in.readShort();
+        field_5_hasMultibyte = in.readByte() != 0x00;
+        if (field_5_hasMultibyte) {
+            field_6_author = StringUtil.readUnicodeLE(in, length);
+        } else {
+            field_6_author = StringUtil.readCompressedUnicode(in, length);
+        }
+        if (in.available() == 1) {
+            field_7_padding = in.readByte();
+        } else if (in.available() == 2 && length == 0) {
+            // If there's no author, may be double padded
             field_7_padding = in.readByte();
             in.readByte();
- 		}
-	}
+        }
+    }
 
-	public void serialize(LittleEndianOutput out) {
-		out.writeShort(field_1_row);
-		out.writeShort(field_2_col);
-		out.writeShort(field_3_flags);
-		out.writeShort(field_4_shapeid);
-		out.writeShort(field_6_author.length());
-		out.writeByte(field_5_hasMultibyte ? 0x01 : 0x00);
-		if (field_5_hasMultibyte) {
-			StringUtil.putUnicodeLE(field_6_author, out);
-		} else {
-			StringUtil.putCompressedUnicode(field_6_author, out);
-		}
-		if (field_7_padding != null) {
-			out.writeByte(field_7_padding.intValue());
-		}
-	}
-
-	protected int getDataSize() {
-		return 11 // 5 shorts + 1 byte
-			+ field_6_author.length() * (field_5_hasMultibyte ? 2 : 1)
-			+ (field_7_padding == null ? 0 : 1);
-	}
-
-	/**
-	 * Return the row that contains the comment
-	 *
-	 * @return the row that contains the comment
-	 */
-	public int getRow() {
-		return field_1_row;
-	}
-
-	/**
-	 * Specify the row that contains the comment
-	 *
-	 * @param row the row that contains the comment
-	 */
-	public void setRow(int row) {
-		field_1_row = row;
-	}
-
-	/**
-	 * Return the column that contains the comment
-	 *
-	 * @return the column that contains the comment
-	 */
-	public int getColumn() {
-		return field_2_col;
-	}
-
-	/**
-	 * Specify the column that contains the comment
-	 *
-	 * @param col the column that contains the comment
-	 */
-	public void setColumn(int col) {
-		field_2_col = col;
-	}
-
-	/**
-	 * Options flags.
-	 *
-	 * @return the options flag
-	 * @see #NOTE_VISIBLE
-	 * @see #NOTE_HIDDEN
-	 */
-	public short getFlags() {
-		return field_3_flags;
-	}
-
-	/**
-	 * Options flag
-	 *
-	 * @param flags the options flag
-	 * @see #NOTE_VISIBLE
-	 * @see #NOTE_HIDDEN
-	 */
-	public void setFlags(short flags) {
-		field_3_flags = flags;
-	}
-
-	/**
-	 * For unit testing only!
-	 *
-	 * @return true, if author element uses multi byte
-	 */
-	boolean authorIsMultibyte() {
-	   return field_5_hasMultibyte;
-	}
-
-	/**
-	 * Object id for OBJ record that contains the comment
-	 *
-	 * @return the Object id for OBJ record that contains the comment
-	 */
-	public int getShapeId() {
-		return field_4_shapeid;
-	}
-
-	/**
-	 * Object id for OBJ record that contains the comment
-	 *
-	 * @param id the Object id for OBJ record that contains the comment
-	 */
-	public void setShapeId(int id) {
-		field_4_shapeid = id;
-	}
-
-	/**
-	 * Name of the original comment author
-	 *
-	 * @return the name of the original author of the comment
-	 */
-	public String getAuthor() {
-		return field_6_author;
-	}
-
-	/**
-	 * Name of the original comment author
-	 *
-	 * @param author the name of the original author of the comment
-	 */
-	public void setAuthor(String author) {
-		field_6_author = author;
-      	field_5_hasMultibyte = StringUtil.hasMultibyte(author);
-	}
-
-
-	@Override
-	public NoteRecord copy() {
-		return new NoteRecord(this);
-	}
-
-	@Override
-	public HSSFRecordTypes getGenericRecordType() {
-		return HSSFRecordTypes.NOTE;
-	}
-
-	@Override
-	public Map<String, Supplier<?>> getGenericProperties() {
-		return GenericRecordUtil.getGenericProperties(
-			"row", this::getRow,
-			"column", this::getColumn,
-			"flags", this::getFlags,
-			"shapeId", this::getShapeId,
-			"author", this::getAuthor
-		);
-	}
+    public void serialize(LittleEndianOutput out) {
+        out.writeShort(field_1_row);
+        out.writeShort(field_2_col);
+        out.writeShort(field_3_flags);
+        out.writeShort(field_4_shapeid);
+        out.writeShort(field_6_author.length());
+        out.writeByte(field_5_hasMultibyte ? 0x01 : 0x00);
+        if (field_5_hasMultibyte) {
+            StringUtil.putUnicodeLE(field_6_author, out);
+        } else {
+            StringUtil.putCompressedUnicode(field_6_author, out);
+        }
+        if (field_7_padding != null) {
+            out.writeByte(field_7_padding.intValue());
+        }
+    }
+
+    protected int getDataSize() {
+        return 11 // 5 shorts + 1 byte
+            + field_6_author.length() * (field_5_hasMultibyte ? 2 : 1)
+            + (field_7_padding == null ? 0 : 1);
+    }
+
+    /**
+     * Return the row that contains the comment
+     *
+     * @return the row that contains the comment
+     */
+    public int getRow() {
+        return field_1_row;
+    }
+
+    /**
+     * Specify the row that contains the comment
+     *
+     * @param row the row that contains the comment
+     */
+    public void setRow(int row) {
+        field_1_row = row;
+    }
+
+    /**
+     * Return the column that contains the comment
+     *
+     * @return the column that contains the comment
+     */
+    public int getColumn() {
+        return field_2_col;
+    }
+
+    /**
+     * Specify the column that contains the comment
+     *
+     * @param col the column that contains the comment
+     */
+    public void setColumn(int col) {
+        field_2_col = col;
+    }
+
+    /**
+     * Options flags.
+     *
+     * @return the options flag
+     * @see #NOTE_VISIBLE
+     * @see #NOTE_HIDDEN
+     */
+    public short getFlags() {
+        return field_3_flags;
+    }
+
+    /**
+     * Options flag
+     *
+     * @param flags the options flag
+     * @see #NOTE_VISIBLE
+     * @see #NOTE_HIDDEN
+     */
+    public void setFlags(short flags) {
+        field_3_flags = flags;
+    }
+
+    /**
+     * For unit testing only!
+     *
+     * @return true, if author element uses multi byte
+     */
+    boolean authorIsMultibyte() {
+       return field_5_hasMultibyte;
+    }
+
+    /**
+     * Object id for OBJ record that contains the comment
+     *
+     * @return the Object id for OBJ record that contains the comment
+     */
+    public int getShapeId() {
+        return field_4_shapeid;
+    }
+
+    /**
+     * Object id for OBJ record that contains the comment
+     *
+     * @param id the Object id for OBJ record that contains the comment
+     */
+    public void setShapeId(int id) {
+        field_4_shapeid = id;
+    }
+
+    /**
+     * Name of the original comment author
+     *
+     * @return the name of the original author of the comment
+     */
+    public String getAuthor() {
+        return field_6_author;
+    }
+
+    /**
+     * Name of the original comment author
+     *
+     * @param author the name of the original author of the comment
+     */
+    public void setAuthor(String author) {
+        field_6_author = author;
+        field_5_hasMultibyte = StringUtil.hasMultibyte(author);
+    }
+
+
+    @Override
+    public NoteRecord copy() {
+        return new NoteRecord(this);
+    }
+
+    @Override
+    public HSSFRecordTypes getGenericRecordType() {
+        return HSSFRecordTypes.NOTE;
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "row", this::getRow,
+            "column", this::getColumn,
+            "flags", this::getFlags,
+            "shapeId", this::getShapeId,
+            "author", this::getAuthor
+        );
+    }
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java Sat May 22 20:56:44 2021
@@ -85,7 +85,7 @@ public final class NoteStructureSubRecor
         out.write(reserved);
     }
 
-	@Override
+    @Override
     protected int getDataSize() {
         return reserved.length;
     }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/PageBreakRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/PageBreakRecord.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/PageBreakRecord.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/PageBreakRecord.java Sat May 22 20:56:44 2021
@@ -124,7 +124,7 @@ public abstract class PageBreakRecord ex
     }
 
     public boolean isEmpty() {
-    	return _breaks.isEmpty();
+        return _breaks.isEmpty();
     }
     protected int getDataSize() {
         return 2 + _breaks.size() * Break.ENCODED_SIZE;

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RKRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RKRecord.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RKRecord.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RKRecord.java Sat May 22 20:56:44 2021
@@ -75,17 +75,17 @@ public final class RKRecord extends Cell
 
     @Override
     protected String getRecordName() {
-    	return "RK";
+        return "RK";
     }
 
     @Override
     protected void serializeValue(LittleEndianOutput out) {
-    	out.writeInt(field_4_rk_number);
+        out.writeInt(field_4_rk_number);
     }
 
     @Override
     protected int getValueDataSize() {
-    	return 4;
+        return 4;
     }
 
     @Override

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecalcIdRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecalcIdRecord.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecalcIdRecord.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecalcIdRecord.java Sat May 22 20:56:44 2021
@@ -56,9 +56,9 @@ public final class RecalcIdRecord extend
     }
 
     public RecalcIdRecord(RecordInputStream in) {
-    	in.readUShort(); // field 'rt' should have value 0x01C1, but Excel doesn't care during reading
-    	_reserved0 = in.readUShort();
-    	_engineId = in.readInt();
+        in.readUShort(); // field 'rt' should have value 0x01C1, but Excel doesn't care during reading
+        _reserved0 = in.readUShort();
+        _engineId = in.readInt();
     }
 
     public boolean isNeeded() {

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordBase.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordBase.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordBase.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordBase.java Sat May 22 20:56:44 2021
@@ -21,22 +21,22 @@ package org.apache.poi.hssf.record;
  * Common base class of {@link Record} and {@link org.apache.poi.hssf.record.aggregates.RecordAggregate}
  */
 public abstract class RecordBase {
-	/**
-	 * called by the class that is responsible for writing this sucker.
-	 * Subclasses should implement this so that their data is passed back in a
-	 * byte array.
-	 *
-	 * @param offset to begin writing at
-	 * @param data byte array containing instance data
-	 * @return number of bytes written
-	 */
-	public abstract int serialize(int offset, byte[] data);
+    /**
+     * called by the class that is responsible for writing this sucker.
+     * Subclasses should implement this so that their data is passed back in a
+     * byte array.
+     *
+     * @param offset to begin writing at
+     * @param data byte array containing instance data
+     * @return number of bytes written
+     */
+    public abstract int serialize(int offset, byte[] data);
 
-	/**
-	 * gives the current serialized size of the record. Should include the sid
-	 * and reclength (4 bytes).
-	 *
-	 * @return the record size
-	 */
-	public abstract int getRecordSize();
+    /**
+     * gives the current serialized size of the record. Should include the sid
+     * and reclength (4 bytes).
+     *
+     * @return the record size
+     */
+    public abstract int getRecordSize();
 }

Modified: poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java?rev=1890120&r1=1890119&r2=1890120&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java Sat May 22 20:56:44 2021
@@ -41,75 +41,75 @@ import org.apache.poi.util.RecordFormatE
  */
 public final class RecordFactoryInputStream {
 
-	/**
-	 * Keeps track of the sizes of the initial records up to and including {@link FilePassRecord}
-	 * Needed for protected files because each byte is encrypted with respect to its absolute
-	 * position from the start of the stream.
-	 */
-	private static final class StreamEncryptionInfo {
-		private final int _initialRecordsSize;
-		private final FilePassRecord _filePassRec;
-		private final Record _lastRecord;
-		private final boolean _hasBOFRecord;
-
-		public StreamEncryptionInfo(RecordInputStream rs, List<org.apache.poi.hssf.record.Record> outputRecs) {
-			Record rec;
-			rs.nextRecord();
-			int recSize = 4 + rs.remaining();
-			rec = RecordFactory.createSingleRecord(rs);
-			outputRecs.add(rec);
-			FilePassRecord fpr = null;
-			if (rec instanceof BOFRecord) {
-				_hasBOFRecord = true;
-				
-				// Fetch the next record, and see if it indicates whether
-				//  the document is encrypted or not
-				if (rs.hasNextRecord()) {
-					rs.nextRecord();
-					rec = RecordFactory.createSingleRecord(rs);
-					recSize += rec.getRecordSize();
-					outputRecs.add(rec);
-					
-					// Encrypted is normally BOF then FILEPASS
-					// May sometimes be BOF, WRITEPROTECT, FILEPASS
-					if (rec instanceof WriteProtectRecord && rs.hasNextRecord()) {
-	               rs.nextRecord();
-	               rec = RecordFactory.createSingleRecord(rs);
-	               recSize += rec.getRecordSize();
-	               outputRecs.add(rec);
-					}
-					
-					// If it's a FILEPASS, track it specifically
-					if (rec instanceof FilePassRecord) {
-						fpr = (FilePassRecord) rec;
-					}
-
-					// workbook not encrypted (typical case)
-					if (rec instanceof EOFRecord) {
-						// A workbook stream is never empty, so crash instead
-						// of trying to keep track of nesting level
-						throw new IllegalStateException("Nothing between BOF and EOF");
-					}
-				}
-			} else {
-				// Invalid in a normal workbook stream.
-				// However, some test cases work on sub-sections of
-				// the workbook stream that do not begin with BOF
-				_hasBOFRecord = false;
-			}
-			_initialRecordsSize = recSize;
-			_filePassRec = fpr;
-			_lastRecord = rec;
-		}
+    /**
+     * Keeps track of the sizes of the initial records up to and including {@link FilePassRecord}
+     * Needed for protected files because each byte is encrypted with respect to its absolute
+     * position from the start of the stream.
+     */
+    private static final class StreamEncryptionInfo {
+        private final int _initialRecordsSize;
+        private final FilePassRecord _filePassRec;
+        private final Record _lastRecord;
+        private final boolean _hasBOFRecord;
+
+        public StreamEncryptionInfo(RecordInputStream rs, List<org.apache.poi.hssf.record.Record> outputRecs) {
+            Record rec;
+            rs.nextRecord();
+            int recSize = 4 + rs.remaining();
+            rec = RecordFactory.createSingleRecord(rs);
+            outputRecs.add(rec);
+            FilePassRecord fpr = null;
+            if (rec instanceof BOFRecord) {
+                _hasBOFRecord = true;
+                
+                // Fetch the next record, and see if it indicates whether
+                //  the document is encrypted or not
+                if (rs.hasNextRecord()) {
+                    rs.nextRecord();
+                    rec = RecordFactory.createSingleRecord(rs);
+                    recSize += rec.getRecordSize();
+                    outputRecs.add(rec);
+                    
+                    // Encrypted is normally BOF then FILEPASS
+                    // May sometimes be BOF, WRITEPROTECT, FILEPASS
+                    if (rec instanceof WriteProtectRecord && rs.hasNextRecord()) {
+                   rs.nextRecord();
+                   rec = RecordFactory.createSingleRecord(rs);
+                   recSize += rec.getRecordSize();
+                   outputRecs.add(rec);
+                    }
+                    
+                    // If it's a FILEPASS, track it specifically
+                    if (rec instanceof FilePassRecord) {
+                        fpr = (FilePassRecord) rec;
+                    }
+
+                    // workbook not encrypted (typical case)
+                    if (rec instanceof EOFRecord) {
+                        // A workbook stream is never empty, so crash instead
+                        // of trying to keep track of nesting level
+                        throw new IllegalStateException("Nothing between BOF and EOF");
+                    }
+                }
+            } else {
+                // Invalid in a normal workbook stream.
+                // However, some test cases work on sub-sections of
+                // the workbook stream that do not begin with BOF
+                _hasBOFRecord = false;
+            }
+            _initialRecordsSize = recSize;
+            _filePassRec = fpr;
+            _lastRecord = rec;
+        }
 
-		@SuppressWarnings({"squid:S2068"})
-		public RecordInputStream createDecryptingStream(InputStream original) {
+        @SuppressWarnings({"squid:S2068"})
+        public RecordInputStream createDecryptingStream(InputStream original) {
             String userPassword = Biff8EncryptionKey.getCurrentUserPassword();
-			if (userPassword == null) {
-			    userPassword = Decryptor.DEFAULT_PASSWORD;
-			}
+            if (userPassword == null) {
+                userPassword = Decryptor.DEFAULT_PASSWORD;
+            }
 
-			EncryptionInfo info = _filePassRec.getEncryptionInfo();
+            EncryptionInfo info = _filePassRec.getEncryptionInfo();
             try {
                 if (!info.getDecryptor().verifyPassword(userPassword)) {
                     throw new EncryptedDocumentException(
@@ -120,250 +120,250 @@ public final class RecordFactoryInputStr
                 throw new EncryptedDocumentException(e);
             }
 
-			return new RecordInputStream(original, info, _initialRecordsSize);
-		}
+            return new RecordInputStream(original, info, _initialRecordsSize);
+        }
 
-		public boolean hasEncryption() {
-			return _filePassRec != null;
-		}
-
-		/**
-		 * @return last record scanned while looking for encryption info.
-		 * This will typically be the first or second record read. Possibly <code>null</code>
-		 * if stream was empty
-		 */
-		public Record getLastRecord() {
-			return _lastRecord;
-		}
-
-		/**
-		 * <code>false</code> in some test cases
-		 */
-		public boolean hasBOFRecord() {
-			return _hasBOFRecord;
-		}
-	}
-
-
-	private final RecordInputStream _recStream;
-	private final boolean _shouldIncludeContinueRecords;
-
-	/**
-	 * Temporarily stores a group of {@link Record}s, for future return by {@link #nextRecord()}.
-	 * This is used at the start of the workbook stream, and also when the most recently read
-	 * underlying record is a {@link MulRKRecord}
-	 */
-	private Record[] _unreadRecordBuffer;
-
-	/**
-	 * used to help iterating over the unread records
-	 */
-	private int _unreadRecordIndex = -1;
-
-	/**
-	 * The most recent record that we gave to the user
-	 */
-	private Record _lastRecord;
-	/**
-	 * The most recent DrawingRecord seen
-	 */
-	private DrawingRecord _lastDrawingRecord = new DrawingRecord();
-
-	private int _bofDepth;
-
-	private boolean _lastRecordWasEOFLevelZero;
-
-
-	/**
-	 * @param in the InputStream to read from
-	 * 
-	 * @param shouldIncludeContinueRecords caller can pass <code>false</code> if loose
-	 * {@link ContinueRecord}s should be skipped (this is sometimes useful in event based
-	 * processing).
-	 */
-	public RecordFactoryInputStream(InputStream in, boolean shouldIncludeContinueRecords) {
-		RecordInputStream rs = new RecordInputStream(in);
-		List<org.apache.poi.hssf.record.Record> records = new ArrayList<>();
-		StreamEncryptionInfo sei = new StreamEncryptionInfo(rs, records);
-		if (sei.hasEncryption()) {
-			rs = sei.createDecryptingStream(in);
-		} else {
-			// typical case - non-encrypted stream
-		}
-
-		if (!records.isEmpty()) {
-			_unreadRecordBuffer = new Record[records.size()];
-			records.toArray(_unreadRecordBuffer);
-			_unreadRecordIndex =0;
-		}
-		_recStream = rs;
-		_shouldIncludeContinueRecords = shouldIncludeContinueRecords;
-		_lastRecord = sei.getLastRecord();
-
-		/*
-		* How to recognise end of stream?
-		* In the best case, the underlying input stream (in) ends just after the last EOF record
-		* Usually however, the stream is padded with an arbitrary byte count.  Excel and most apps
-		* reliably use zeros for padding and if this were always the case, this code could just
-		* skip all the (zero sized) records with sid==0.  However, bug 46987 shows a file with
-		* non-zero padding that is read OK by Excel (Excel also fixes the padding).
-		*
-		* So to properly detect the workbook end of stream, this code has to identify the last
-		* EOF record.  This is not so easy because the worbook bof+eof pair do not bracket the
-		* whole stream.  The worksheets follow the workbook, but it is not easy to tell how many
-		* sheet sub-streams should be present.  Hence we are looking for an EOF record that is not
-		* immediately followed by a BOF record.  One extra complication is that bof+eof sub-
-		* streams can be nested within worksheet streams and it's not clear in these cases what
-		* record might follow any EOF record.  So we also need to keep track of the bof/eof
-		* nesting level.
-		*/
-		_bofDepth = sei.hasBOFRecord() ? 1 : 0;
-		_lastRecordWasEOFLevelZero = false;
-	}
-
-	/**
-	 * @return the next (complete) record from the stream, or null if there are no more.
-	 */
-	public Record nextRecord() {
-		Record r;
-		r = getNextUnreadRecord();
-		if (r != null) {
-			// found an unread record
-			return r;
-		}
-		while (true) {
-			if (!_recStream.hasNextRecord()) {
-				// recStream is exhausted;
-				return null;
-			}
-
-			if (_lastRecordWasEOFLevelZero) {
-				// Potential place for ending the workbook stream
-				// Check that the next record is not BOFRecord(0x0809)
-				// Normally the input stream contains only zero padding after the last EOFRecord,
-				// but bug 46987 and 48068 suggests that the padding may be garbage.
-				// This code relies on the padding bytes not starting with BOFRecord.sid
-				if (_recStream.getNextSid() != BOFRecord.sid) {
-					return null;
-				}
-				// else - another sheet substream starting here
-			}
+        public boolean hasEncryption() {
+            return _filePassRec != null;
+        }
+
+        /**
+         * @return last record scanned while looking for encryption info.
+         * This will typically be the first or second record read. Possibly <code>null</code>
+         * if stream was empty
+         */
+        public Record getLastRecord() {
+            return _lastRecord;
+        }
+
+        /**
+         * <code>false</code> in some test cases
+         */
+        public boolean hasBOFRecord() {
+            return _hasBOFRecord;
+        }
+    }
+
+
+    private final RecordInputStream _recStream;
+    private final boolean _shouldIncludeContinueRecords;
+
+    /**
+     * Temporarily stores a group of {@link Record}s, for future return by {@link #nextRecord()}.
+     * This is used at the start of the workbook stream, and also when the most recently read
+     * underlying record is a {@link MulRKRecord}
+     */
+    private Record[] _unreadRecordBuffer;
+
+    /**
+     * used to help iterating over the unread records
+     */
+    private int _unreadRecordIndex = -1;
+
+    /**
+     * The most recent record that we gave to the user
+     */
+    private Record _lastRecord;
+    /**
+     * The most recent DrawingRecord seen
+     */
+    private DrawingRecord _lastDrawingRecord = new DrawingRecord();
+
+    private int _bofDepth;
+
+    private boolean _lastRecordWasEOFLevelZero;
+
+
+    /**
+     * @param in the InputStream to read from
+     * 
+     * @param shouldIncludeContinueRecords caller can pass <code>false</code> if loose
+     * {@link ContinueRecord}s should be skipped (this is sometimes useful in event based
+     * processing).
+     */
+    public RecordFactoryInputStream(InputStream in, boolean shouldIncludeContinueRecords) {
+        RecordInputStream rs = new RecordInputStream(in);
+        List<org.apache.poi.hssf.record.Record> records = new ArrayList<>();
+        StreamEncryptionInfo sei = new StreamEncryptionInfo(rs, records);
+        if (sei.hasEncryption()) {
+            rs = sei.createDecryptingStream(in);
+        } else {
+            // typical case - non-encrypted stream
+        }
+
+        if (!records.isEmpty()) {
+            _unreadRecordBuffer = new Record[records.size()];
+            records.toArray(_unreadRecordBuffer);
+            _unreadRecordIndex =0;
+        }
+        _recStream = rs;
+        _shouldIncludeContinueRecords = shouldIncludeContinueRecords;
+        _lastRecord = sei.getLastRecord();
+
+        /*
+        * How to recognise end of stream?
+        * In the best case, the underlying input stream (in) ends just after the last EOF record
+        * Usually however, the stream is padded with an arbitrary byte count.  Excel and most apps
+        * reliably use zeros for padding and if this were always the case, this code could just
+        * skip all the (zero sized) records with sid==0.  However, bug 46987 shows a file with
+        * non-zero padding that is read OK by Excel (Excel also fixes the padding).
+        *
+        * So to properly detect the workbook end of stream, this code has to identify the last
+        * EOF record.  This is not so easy because the worbook bof+eof pair do not bracket the
+        * whole stream.  The worksheets follow the workbook, but it is not easy to tell how many
+        * sheet sub-streams should be present.  Hence we are looking for an EOF record that is not
+        * immediately followed by a BOF record.  One extra complication is that bof+eof sub-
+        * streams can be nested within worksheet streams and it's not clear in these cases what
+        * record might follow any EOF record.  So we also need to keep track of the bof/eof
+        * nesting level.
+        */
+        _bofDepth = sei.hasBOFRecord() ? 1 : 0;
+        _lastRecordWasEOFLevelZero = false;
+    }
+
+    /**
+     * @return the next (complete) record from the stream, or null if there are no more.
+     */
+    public Record nextRecord() {
+        Record r;
+        r = getNextUnreadRecord();
+        if (r != null) {
+            // found an unread record
+            return r;
+        }
+        while (true) {
+            if (!_recStream.hasNextRecord()) {
+                // recStream is exhausted;
+                return null;
+            }
+
+            if (_lastRecordWasEOFLevelZero) {
+                // Potential place for ending the workbook stream
+                // Check that the next record is not BOFRecord(0x0809)
+                // Normally the input stream contains only zero padding after the last EOFRecord,
+                // but bug 46987 and 48068 suggests that the padding may be garbage.
+                // This code relies on the padding bytes not starting with BOFRecord.sid
+                if (_recStream.getNextSid() != BOFRecord.sid) {
+                    return null;
+                }
+                // else - another sheet substream starting here
+            }
 
             // step underlying RecordInputStream to the next record
             _recStream.nextRecord();
 
-			r = readNextRecord();
-			if (r == null) {
-				// some record types may get skipped (e.g. DBCellRecord and ContinueRecord)
-				continue;
-			}
-			return r;
-		}
-	}
-
-	/**
-	 * @return the next {@link Record} from the multiple record group as expanded from
-	 * a recently read {@link MulRKRecord}. <code>null</code> if not present.
-	 */
-	private Record getNextUnreadRecord() {
-		if (_unreadRecordBuffer != null) {
-			int ix = _unreadRecordIndex;
-			if (ix < _unreadRecordBuffer.length) {
-				Record result = _unreadRecordBuffer[ix];
-				_unreadRecordIndex = ix + 1;
-				return result;
-			}
-			_unreadRecordIndex = -1;
-			_unreadRecordBuffer = null;
-		}
-		return null;
-	}
-
-	/**
-	 * @return the next available record, or <code>null</code> if
-	 * this pass didn't return a record that's
-	 * suitable for returning (eg was a continue record).
-	 */
-	private Record readNextRecord() {
-
-		Record record = RecordFactory.createSingleRecord(_recStream);
-		_lastRecordWasEOFLevelZero = false;
-
-		if (record instanceof BOFRecord) {
-			_bofDepth++;
-			return record;
-		}
-
-		if (record instanceof EOFRecord) {
-			_bofDepth--;
-			if (_bofDepth < 1) {
-				_lastRecordWasEOFLevelZero = true;
-			}
-
-			return record;
-		}
-
-		if (record instanceof DBCellRecord) {
-			// Not needed by POI.  Regenerated from scratch by POI when spreadsheet is written
-			return null;
-		}
-
-		if (record instanceof RKRecord) {
-			return RecordFactory.convertToNumberRecord((RKRecord) record);
-		}
-
-		if (record instanceof MulRKRecord) {
-			Record[] records = RecordFactory.convertRKRecords((MulRKRecord) record);
-
-			_unreadRecordBuffer = records;
-			_unreadRecordIndex = 1;
-			return records[0];
-		}
-
-		if (record.getSid() == DrawingGroupRecord.sid
-				&& _lastRecord instanceof DrawingGroupRecord) {
-			DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) _lastRecord;
-			lastDGRecord.join((AbstractEscherHolderRecord) record);
-			return null;
-		}
-		if (record.getSid() == ContinueRecord.sid) {
-			ContinueRecord contRec = (ContinueRecord) record;
-
-			if (_lastRecord instanceof ObjRecord || _lastRecord instanceof TextObjectRecord) {
-				// Drawing records have a very strange continue behaviour.
-				//There can actually be OBJ records mixed between the continues.
-				_lastDrawingRecord.processContinueRecord(contRec.getData());
-				//we must remember the position of the continue record.
-				//in the serialization procedure the original structure of records must be preserved
-				if (_shouldIncludeContinueRecords) {
-					return record;
-				}
-				return null;
-			}
-			if (_lastRecord instanceof DrawingGroupRecord) {
-				((DrawingGroupRecord) _lastRecord).processContinueRecord(contRec.getData());
-				return null;
-			}
-			if (_lastRecord instanceof DrawingRecord) {
-//				((DrawingRecord) _lastRecord).appendContinueRecord(contRec.getData());
-				return contRec;
-			}
-			if (_lastRecord instanceof UnknownRecord) {
-				//Gracefully handle records that we don't know about,
-				//that happen to be continued
-				return record;
-			}
-			if (_lastRecord instanceof EOFRecord) {
-				// This is really odd, but excel still sometimes
-				//  outputs a file like this all the same
-				return record;
-			}
-			throw new RecordFormatException("Unhandled Continue Record followining " + _lastRecord.getClass());
-		}
-		_lastRecord = record;
-		if (record instanceof DrawingRecord) {
-			_lastDrawingRecord = (DrawingRecord) record;
-		}
-		return record;
-	}
+            r = readNextRecord();
+            if (r == null) {
+                // some record types may get skipped (e.g. DBCellRecord and ContinueRecord)
+                continue;
+            }
+            return r;
+        }
+    }
+
+    /**
+     * @return the next {@link Record} from the multiple record group as expanded from
+     * a recently read {@link MulRKRecord}. <code>null</code> if not present.
+     */
+    private Record getNextUnreadRecord() {
+        if (_unreadRecordBuffer != null) {
+            int ix = _unreadRecordIndex;
+            if (ix < _unreadRecordBuffer.length) {
+                Record result = _unreadRecordBuffer[ix];
+                _unreadRecordIndex = ix + 1;
+                return result;
+            }
+            _unreadRecordIndex = -1;
+            _unreadRecordBuffer = null;
+        }
+        return null;
+    }
+
+    /**
+     * @return the next available record, or <code>null</code> if
+     * this pass didn't return a record that's
+     * suitable for returning (eg was a continue record).
+     */
+    private Record readNextRecord() {
+
+        Record record = RecordFactory.createSingleRecord(_recStream);
+        _lastRecordWasEOFLevelZero = false;
+
+        if (record instanceof BOFRecord) {
+            _bofDepth++;
+            return record;
+        }
+
+        if (record instanceof EOFRecord) {
+            _bofDepth--;
+            if (_bofDepth < 1) {
+                _lastRecordWasEOFLevelZero = true;
+            }
+
+            return record;
+        }
+
+        if (record instanceof DBCellRecord) {
+            // Not needed by POI.  Regenerated from scratch by POI when spreadsheet is written
+            return null;
+        }
+
+        if (record instanceof RKRecord) {
+            return RecordFactory.convertToNumberRecord((RKRecord) record);
+        }
+
+        if (record instanceof MulRKRecord) {
+            Record[] records = RecordFactory.convertRKRecords((MulRKRecord) record);
+
+            _unreadRecordBuffer = records;
+            _unreadRecordIndex = 1;
+            return records[0];
+        }
+
+        if (record.getSid() == DrawingGroupRecord.sid
+                && _lastRecord instanceof DrawingGroupRecord) {
+            DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) _lastRecord;
+            lastDGRecord.join((AbstractEscherHolderRecord) record);
+            return null;
+        }
+        if (record.getSid() == ContinueRecord.sid) {
+            ContinueRecord contRec = (ContinueRecord) record;
+
+            if (_lastRecord instanceof ObjRecord || _lastRecord instanceof TextObjectRecord) {
+                // Drawing records have a very strange continue behaviour.
+                //There can actually be OBJ records mixed between the continues.
+                _lastDrawingRecord.processContinueRecord(contRec.getData());
+                //we must remember the position of the continue record.
+                //in the serialization procedure the original structure of records must be preserved
+                if (_shouldIncludeContinueRecords) {
+                    return record;
+                }
+                return null;
+            }
+            if (_lastRecord instanceof DrawingGroupRecord) {
+                ((DrawingGroupRecord) _lastRecord).processContinueRecord(contRec.getData());
+                return null;
+            }
+            if (_lastRecord instanceof DrawingRecord) {
+//              ((DrawingRecord) _lastRecord).appendContinueRecord(contRec.getData());
+                return contRec;
+            }
+            if (_lastRecord instanceof UnknownRecord) {
+                //Gracefully handle records that we don't know about,
+                //that happen to be continued
+                return record;
+            }
+            if (_lastRecord instanceof EOFRecord) {
+                // This is really odd, but excel still sometimes
+                //  outputs a file like this all the same
+                return record;
+            }
+            throw new RecordFormatException("Unhandled Continue Record followining " + _lastRecord.getClass());
+        }
+        _lastRecord = record;
+        if (record instanceof DrawingRecord) {
+            _lastDrawingRecord = (DrawingRecord) record;
+        }
+        return record;
+    }
 }



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