mirror of https://github.com/apache/poi.git
PR:17039 - DBCS chars in header and footer
Obtained from: kamoshida.toshiaki@future.co.jp Tweaked and tests added by self. git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353654 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f4059c7cc2
commit
90bc3e260a
|
@ -36,7 +36,8 @@ public class FooterRecord
|
||||||
{
|
{
|
||||||
public final static short sid = 0x15;
|
public final static short sid = 0x15;
|
||||||
private byte field_1_footer_len;
|
private byte field_1_footer_len;
|
||||||
private String field_2_footer;
|
private byte field_2_unicode_flag;
|
||||||
|
private String field_3_footer;
|
||||||
|
|
||||||
public FooterRecord()
|
public FooterRecord()
|
||||||
{
|
{
|
||||||
|
@ -82,11 +83,46 @@ public class FooterRecord
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
field_1_footer_len = data[ 0 + offset ];
|
field_1_footer_len = data[ 0 + offset ];
|
||||||
field_2_footer = StringUtil.getFromCompressedUnicode(data, 3 + offset, // [Shawn] Changed 1 to 3 for offset of string
|
field_2_unicode_flag = data[ 2 + offset ];
|
||||||
LittleEndian.ubyteToInt( field_1_footer_len) );
|
if(isMultibyte())
|
||||||
|
{
|
||||||
|
field_3_footer = StringUtil.getFromUnicodeLE(
|
||||||
|
data,3 + offset,LittleEndian.ubyteToInt(field_1_footer_len));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
field_3_footer = new String(data, 3 + offset, // [Shawn] Changed 1 to 3 for offset of string
|
||||||
|
LittleEndian.ubyteToInt( field_1_footer_len) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see the unicode flag
|
||||||
|
*
|
||||||
|
* @return boolean flag
|
||||||
|
* true:footer string has at least one multibyte character
|
||||||
|
*/
|
||||||
|
public boolean isMultibyte() {
|
||||||
|
return ((field_2_unicode_flag & 0xFF) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check the parameter has multibyte character
|
||||||
|
*
|
||||||
|
* @param value string to check
|
||||||
|
* @return boolean result
|
||||||
|
* true:string has at least one multibyte character
|
||||||
|
*/
|
||||||
|
private static boolean hasMultibyte(String value){
|
||||||
|
if( value == null )return false;
|
||||||
|
for(int i = 0 ; i < value.length() ; i++ ){
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if(c > 0xFF )return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the length of the footer string
|
* set the length of the footer string
|
||||||
*
|
*
|
||||||
|
@ -108,7 +144,9 @@ public class FooterRecord
|
||||||
|
|
||||||
public void setFooter(String footer)
|
public void setFooter(String footer)
|
||||||
{
|
{
|
||||||
field_2_footer = footer;
|
field_3_footer = footer;
|
||||||
|
field_2_unicode_flag =
|
||||||
|
(byte) (hasMultibyte(field_3_footer) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -132,7 +170,7 @@ public class FooterRecord
|
||||||
|
|
||||||
public String getFooter()
|
public String getFooter()
|
||||||
{
|
{
|
||||||
return field_2_footer;
|
return field_3_footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
|
@ -156,13 +194,23 @@ public class FooterRecord
|
||||||
{
|
{
|
||||||
len+=3; // [Shawn] Fixed for two null bytes in the length
|
len+=3; // [Shawn] Fixed for two null bytes in the length
|
||||||
}
|
}
|
||||||
|
short bytelen = (short)(isMultibyte() ?
|
||||||
|
getFooterLength()*2 : getFooterLength() );
|
||||||
LittleEndian.putShort(data, 0 + offset, sid);
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
LittleEndian.putShort(data, 2 + offset,
|
LittleEndian.putShort(data, 2 + offset,
|
||||||
( short ) ((len - 4) + getFooterLength()));
|
( short ) ((len - 4) + bytelen ));
|
||||||
if (getFooterLength() > 0)
|
if (getFooterLength() > 0)
|
||||||
{
|
{
|
||||||
data[ 4 + offset ] = (byte)getFooterLength();
|
data[ 4 + offset ] = (byte)getFooterLength();
|
||||||
StringUtil.putCompressedUnicode(getFooter(), data, 7 + offset); // [Shawn] Place the string in the correct offset
|
data[ 6 + offset ] = field_2_unicode_flag;
|
||||||
|
if(isMultibyte())
|
||||||
|
{
|
||||||
|
StringUtil.putUnicodeLE(getFooter(), data, 7 + offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StringUtil.putCompressedUnicode(getFooter(), data, 7 + offset); // [Shawn] Place the string in the correct offset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return getRecordSize();
|
return getRecordSize();
|
||||||
}
|
}
|
||||||
|
@ -175,7 +223,8 @@ public class FooterRecord
|
||||||
{
|
{
|
||||||
retval+=3; // [Shawn] Fixed for two null bytes in the length
|
retval+=3; // [Shawn] Fixed for two null bytes in the length
|
||||||
}
|
}
|
||||||
return retval + getFooterLength();
|
return (isMultibyte() ?
|
||||||
|
(retval + getFooterLength()*2) : (retval + getFooterLength()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getSid()
|
public short getSid()
|
||||||
|
@ -186,7 +235,8 @@ public class FooterRecord
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
FooterRecord rec = new FooterRecord();
|
FooterRecord rec = new FooterRecord();
|
||||||
rec.field_1_footer_len = field_1_footer_len;
|
rec.field_1_footer_len = field_1_footer_len;
|
||||||
rec.field_2_footer = field_2_footer;
|
rec.field_2_unicode_flag = field_2_unicode_flag;
|
||||||
|
rec.field_3_footer = field_3_footer;
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,8 @@ public class HeaderRecord
|
||||||
{
|
{
|
||||||
public final static short sid = 0x14;
|
public final static short sid = 0x14;
|
||||||
private byte field_1_header_len;
|
private byte field_1_header_len;
|
||||||
private String field_2_header;
|
private byte field_2_unicode_flag;
|
||||||
|
private String field_3_header;
|
||||||
|
|
||||||
public HeaderRecord()
|
public HeaderRecord()
|
||||||
{
|
{
|
||||||
|
@ -82,11 +83,46 @@ public class HeaderRecord
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
field_1_header_len = data[ 0 + offset ];
|
field_1_header_len = data[ 0 + offset ];
|
||||||
field_2_header = StringUtil.getFromCompressedUnicode(data, 3 + offset, // [Shawn] Changed 1 to 3 for offset of string
|
field_2_unicode_flag = data[ 2 + offset ];
|
||||||
LittleEndian.ubyteToInt(field_1_header_len));
|
if(isMultibyte())
|
||||||
|
{
|
||||||
|
field_3_header = StringUtil.getFromUnicodeLE(
|
||||||
|
data,3 + offset,LittleEndian.ubyteToInt(field_1_header_len));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
field_3_header = new String(data, 3 + offset, // [Shawn] Changed 1 to 3 for offset of string
|
||||||
|
LittleEndian.ubyteToInt( field_1_header_len) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see the unicode flag
|
||||||
|
*
|
||||||
|
* @return boolean flag
|
||||||
|
* true:footer string has at least one multibyte character
|
||||||
|
*/
|
||||||
|
public boolean isMultibyte() {
|
||||||
|
return ((field_2_unicode_flag & 0xFF) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check the parameter has multibyte character
|
||||||
|
*
|
||||||
|
* @param value string to check
|
||||||
|
* @return boolean result
|
||||||
|
* true:string has at least one multibyte character
|
||||||
|
*/
|
||||||
|
private static boolean hasMultibyte(String value){
|
||||||
|
if( value == null )return false;
|
||||||
|
for(int i = 0 ; i < value.length() ; i++ ){
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if(c > 0xFF )return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the length of the header string
|
* set the length of the header string
|
||||||
*
|
*
|
||||||
|
@ -108,7 +144,9 @@ public class HeaderRecord
|
||||||
|
|
||||||
public void setHeader(String header)
|
public void setHeader(String header)
|
||||||
{
|
{
|
||||||
field_2_header = header;
|
field_3_header = header;
|
||||||
|
field_2_unicode_flag =
|
||||||
|
(byte) (hasMultibyte(field_3_header) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -132,7 +170,7 @@ public class HeaderRecord
|
||||||
|
|
||||||
public String getHeader()
|
public String getHeader()
|
||||||
{
|
{
|
||||||
return field_2_header;
|
return field_3_header;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
|
@ -156,14 +194,24 @@ public class HeaderRecord
|
||||||
{
|
{
|
||||||
len+=3; // [Shawn] Fixed for two null bytes in the length
|
len+=3; // [Shawn] Fixed for two null bytes in the length
|
||||||
}
|
}
|
||||||
|
short bytelen = (short)(isMultibyte() ?
|
||||||
|
getHeaderLength()*2 : getHeaderLength() );
|
||||||
LittleEndian.putShort(data, 0 + offset, sid);
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
LittleEndian.putShort(data, 2 + offset,
|
LittleEndian.putShort(data, 2 + offset,
|
||||||
( short ) ((len - 4) + getHeaderLength()));
|
( short ) ((len - 4) + bytelen));
|
||||||
|
|
||||||
if (getHeaderLength() > 0)
|
if (getHeaderLength() > 0)
|
||||||
{
|
{
|
||||||
data[ 4 + offset ] = (byte)getHeaderLength();
|
data[ 4 + offset ] = (byte)getHeaderLength();
|
||||||
StringUtil.putCompressedUnicode(getHeader(), data, 7 + offset); // [Shawn] Place the string in the correct offset
|
data[ 6 + offset ] = field_2_unicode_flag;
|
||||||
|
if(isMultibyte())
|
||||||
|
{
|
||||||
|
StringUtil.putUnicodeLE(getHeader(), data, 7 + offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StringUtil.putCompressedUnicode(getHeader(), data, 7 + offset); // [Shawn] Place the string in the correct offset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return getRecordSize();
|
return getRecordSize();
|
||||||
}
|
}
|
||||||
|
@ -176,8 +224,8 @@ public class HeaderRecord
|
||||||
{
|
{
|
||||||
retval+=3; // [Shawn] Fixed for two null bytes in the length
|
retval+=3; // [Shawn] Fixed for two null bytes in the length
|
||||||
}
|
}
|
||||||
retval += getHeaderLength();
|
return (isMultibyte() ?
|
||||||
return retval;
|
(retval + getHeaderLength()*2) : (retval + getHeaderLength()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getSid()
|
public short getSid()
|
||||||
|
@ -188,7 +236,8 @@ public class HeaderRecord
|
||||||
public Object clone() {
|
public Object clone() {
|
||||||
HeaderRecord rec = new HeaderRecord();
|
HeaderRecord rec = new HeaderRecord();
|
||||||
rec.field_1_header_len = field_1_header_len;
|
rec.field_1_header_len = field_1_header_len;
|
||||||
rec.field_2_header = field_2_header;
|
rec.field_2_unicode_flag = field_2_unicode_flag;
|
||||||
|
rec.field_3_header = field_3_header;
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -24,6 +24,8 @@ import org.apache.poi.hssf.usermodel.HSSFFooter;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -86,5 +88,65 @@ public class TestHSSFHeaderFooter extends TestCase {
|
||||||
assertEquals("Bottom Center", foot.getCenter());
|
assertEquals("Bottom Center", foot.getCenter());
|
||||||
assertEquals("Bottom Right", foot.getRight());
|
assertEquals("Bottom Right", foot.getRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Testcase for Bug 17039 HSSFHeader doesnot support DBCS
|
||||||
|
*/
|
||||||
|
public void testHeaderHas16bitCharacter() throws Exception {
|
||||||
|
HSSFWorkbook b = new HSSFWorkbook();
|
||||||
|
HSSFSheet s = b.createSheet("Test");
|
||||||
|
HSSFHeader h = s.getHeader();
|
||||||
|
h.setLeft("\u0391");
|
||||||
|
h.setCenter("\u0392");
|
||||||
|
h.setRight("\u0393");
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
b.write(out);
|
||||||
|
|
||||||
|
HSSFWorkbook b2 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||||
|
HSSFHeader h2 = b2.getSheet("Test").getHeader();
|
||||||
|
|
||||||
|
assertEquals(h2.getLeft(),"\u0391");
|
||||||
|
assertEquals(h2.getCenter(),"\u0392");
|
||||||
|
assertEquals(h2.getRight(),"\u0393");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Testcase for Bug 17039 HSSFFooter doesnot support DBCS
|
||||||
|
*/
|
||||||
|
public void testFooterHas16bitCharacter() throws Exception{
|
||||||
|
HSSFWorkbook b = new HSSFWorkbook();
|
||||||
|
HSSFSheet s = b.createSheet("Test");
|
||||||
|
HSSFFooter f = s.getFooter();
|
||||||
|
f.setLeft("\u0391");
|
||||||
|
f.setCenter("\u0392");
|
||||||
|
f.setRight("\u0393");
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
b.write(out);
|
||||||
|
|
||||||
|
HSSFWorkbook b2 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||||
|
HSSFFooter f2 = b2.getSheet("Test").getFooter();
|
||||||
|
|
||||||
|
assertEquals(f2.getLeft(),"\u0391");
|
||||||
|
assertEquals(f2.getCenter(),"\u0392");
|
||||||
|
assertEquals(f2.getRight(),"\u0393");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadDBCSHeaderFooter() throws Exception{
|
||||||
|
String readFilename = System.getProperty("HSSF.testdata.path");
|
||||||
|
FileInputStream in = new FileInputStream(readFilename+File.separator+"DBCSHeader.xls");
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook(in);
|
||||||
|
HSSFSheet s = wb.getSheetAt(0);
|
||||||
|
HSSFHeader h = s.getHeader();
|
||||||
|
assertEquals("Header Left " ,h.getLeft(),"\u090f\u0915");
|
||||||
|
assertEquals("Header Center " ,h.getCenter(),"\u0939\u094b\u0917\u093e");
|
||||||
|
assertEquals("Header Right " ,h.getRight(),"\u091c\u093e");
|
||||||
|
|
||||||
|
HSSFFooter f = s.getFooter();
|
||||||
|
assertEquals("Footer Left " ,f.getLeft(),"\u091c\u093e");
|
||||||
|
assertEquals("Footer Center " ,f.getCenter(),"\u091c\u093e");
|
||||||
|
assertEquals("Footer Right " ,f.getRight(),"\u091c\u093e");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue