Fix bug #54233 - Some HPSF documents require UnicodeStrings to be 4-byte aligned, spot these from the otherwise invalid length
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1496675 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
bd92cbc8b5
commit
40d49a54d2
@ -23,17 +23,36 @@ import org.apache.poi.util.POILogger;
|
|||||||
import org.apache.poi.util.StringUtil;
|
import org.apache.poi.util.StringUtil;
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
class UnicodeString
|
class UnicodeString {
|
||||||
{
|
private final static POILogger logger =
|
||||||
|
POILogFactory.getLogger( UnicodeString.class );
|
||||||
private final static POILogger logger = POILogFactory
|
|
||||||
.getLogger( UnicodeString.class );
|
|
||||||
|
|
||||||
private byte[] _value;
|
private byte[] _value;
|
||||||
|
|
||||||
UnicodeString( byte[] data, int offset )
|
UnicodeString(byte[] data, int offset) {
|
||||||
{
|
|
||||||
int length = LittleEndian.getInt( data, offset );
|
int length = LittleEndian.getInt( data, offset );
|
||||||
|
int dataOffset = offset + LittleEndian.INT_SIZE;
|
||||||
|
|
||||||
|
if (! validLength(length, data, dataOffset)) {
|
||||||
|
// If the length looks wrong, this might be because the offset is sometimes expected
|
||||||
|
// to be on a 4 byte boundary. Try checking with that if so, rather than blowing up with
|
||||||
|
// and ArrayIndexOutOfBoundsException below
|
||||||
|
boolean valid = false;
|
||||||
|
int past4byte = offset % 4;
|
||||||
|
if (past4byte != 0) {
|
||||||
|
offset = offset + past4byte;
|
||||||
|
length = LittleEndian.getInt( data, offset );
|
||||||
|
dataOffset = offset + LittleEndian.INT_SIZE;
|
||||||
|
|
||||||
|
valid = validLength(length, data, dataOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
throw new IllegalPropertySetDataException(
|
||||||
|
"UnicodeString started at offset #" + offset +
|
||||||
|
" is not NULL-terminated" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( length == 0 )
|
if ( length == 0 )
|
||||||
{
|
{
|
||||||
@ -41,13 +60,30 @@ class UnicodeString
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_value = LittleEndian.getByteArray( data, offset
|
_value = LittleEndian.getByteArray( data, dataOffset, length * 2 );
|
||||||
+ LittleEndian.INT_SIZE, length * 2 );
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the specified length seems valid,
|
||||||
|
* given the amount of data available still to read,
|
||||||
|
* and the requirement that the string be NULL-terminated
|
||||||
|
*/
|
||||||
|
boolean validLength(int length, byte[] data, int offset) {
|
||||||
|
if (length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if ( _value[length * 2 - 1] != 0 || _value[length * 2 - 2] != 0 )
|
int endOffset = offset + (length * 2);
|
||||||
throw new IllegalPropertySetDataException(
|
if (endOffset <= data.length) {
|
||||||
"UnicodeString started at offset #" + offset
|
// Data Length is OK, ensure it's null terminated too
|
||||||
+ " is not NULL-terminated" );
|
if (data[endOffset-1] == 0 && data[endOffset-2] == 0) {
|
||||||
|
// Length looks plausible
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something's up/invalid with that length for the given data+offset
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getSize()
|
int getSize()
|
||||||
|
@ -46,7 +46,6 @@ public final class TestPOIDocumentMain extends TestCase {
|
|||||||
* Set things up, two spreadsheets for our testing
|
* Set things up, two spreadsheets for our testing
|
||||||
*/
|
*/
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
|
||||||
doc = HSSFTestDataSamples.openSampleWorkbook("DateFormats.xls");
|
doc = HSSFTestDataSamples.openSampleWorkbook("DateFormats.xls");
|
||||||
doc2 = HSSFTestDataSamples.openSampleWorkbook("StringFormulas.xls");
|
doc2 = HSSFTestDataSamples.openSampleWorkbook("StringFormulas.xls");
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,20 @@ import java.util.Date;
|
|||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.POIDataSamples;
|
||||||
|
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||||
|
import org.apache.poi.hpsf.PropertySetFactory;
|
||||||
|
import org.apache.poi.hpsf.SummaryInformation;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||||
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests various bugs have been fixed
|
* Tests various bugs have been fixed
|
||||||
*/
|
*/
|
||||||
public final class TestHPSFBugs extends TestCase {
|
public final class TestHPSFBugs extends TestCase {
|
||||||
|
private static final POIDataSamples _samples = POIDataSamples.getHPSFInstance();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that we can create a new HSSF Workbook,
|
* Ensure that we can create a new HSSF Workbook,
|
||||||
* then add some properties to it, save +
|
* then add some properties to it, save +
|
||||||
@ -91,4 +99,31 @@ public final class TestHPSFBugs extends TestCase {
|
|||||||
assertEquals(12345, wb.getSummaryInformation().getCreateDateTime().getTime());
|
assertEquals(12345, wb.getSummaryInformation().getCreateDateTime().getTime());
|
||||||
assertEquals("Apache", wb.getDocumentSummaryInformation().getCompany());
|
assertEquals("Apache", wb.getDocumentSummaryInformation().getCompany());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some files seem to want the length and data to be on a 4-byte boundary,
|
||||||
|
* and without that you'll hit an ArrayIndexOutOfBoundsException after
|
||||||
|
* reading junk
|
||||||
|
*/
|
||||||
|
public void test54233() throws Exception {
|
||||||
|
DocumentInputStream dis;
|
||||||
|
POIFSFileSystem fs =
|
||||||
|
new POIFSFileSystem(_samples.openResourceAsStream("TestNon4ByteBoundary.doc"));
|
||||||
|
|
||||||
|
dis = fs.createDocumentInputStream(SummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
SummaryInformation si = (SummaryInformation)PropertySetFactory.create(dis);
|
||||||
|
|
||||||
|
dis = fs.createDocumentInputStream(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
DocumentSummaryInformation dsi = (DocumentSummaryInformation)PropertySetFactory.create(dis);
|
||||||
|
|
||||||
|
// Test
|
||||||
|
assertEquals("Microsoft Word 10.0", si.getApplicationName());
|
||||||
|
assertEquals("", si.getTitle());
|
||||||
|
assertEquals("", si.getAuthor());
|
||||||
|
assertEquals("Cour de Justice", dsi.getCompany());
|
||||||
|
|
||||||
|
|
||||||
|
// Write out and read back, should still be valid
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user