mirror of https://github.com/apache/poi.git
Bugzilla 47001 - Fixed WriteAccessRecord and LinkTable to handle unusual format written by Google Docs
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@763391 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
0c1095db76
commit
9fa24eea2c
|
@ -37,6 +37,7 @@
|
|||
|
||||
<!-- Don't forget to update status.xml too! -->
|
||||
<release version="3.5-beta6" date="2009-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">47001 - Fixed WriteAccessRecord and LinkTable to handle unusual format written by Google Docs</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46973 - Fixed defined names to behave better when refersToFormula is unset</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46832 - Allow merged regions with columns greater than 255 or rows bigger than 65536 in XSSF</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46951 - Fixed formula parser to better handle range operators and whole row/column refs.</action>
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
<!-- Don't forget to update changes.xml too! -->
|
||||
<changes>
|
||||
<release version="3.5-beta6" date="2009-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">47001 - Fixed WriteAccessRecord and LinkTable to handle unusual format written by Google Docs</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46973 - Fixed defined names to behave better when refersToFormula is unset</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46832 - Allow merged regions with columns greater than 255 or rows bigger than 65536 in XSSF</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46951 - Fixed formula parser to better handle range operators and whole row/column refs.</action>
|
||||
|
|
|
@ -161,7 +161,12 @@ final class LinkTable {
|
|||
|
||||
if (_externalBookBlocks.length > 0) {
|
||||
// If any ExternalBookBlock present, there is always 1 of ExternSheetRecord
|
||||
_externSheetRecord = readExtSheetRecord(rs);
|
||||
if (rs.peekNextClass() != ExternSheetRecord.class) {
|
||||
// not quite - if written by google docs
|
||||
_externSheetRecord = null;
|
||||
} else {
|
||||
_externSheetRecord = readExtSheetRecord(rs);
|
||||
}
|
||||
} else {
|
||||
_externSheetRecord = null;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.poi.hssf.record;
|
|||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.LittleEndianOutput;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
|
@ -40,11 +41,13 @@ public final class WriteAccessRecord extends StandardRecord {
|
|||
private static final int DATA_SIZE = 112;
|
||||
private String field_1_username;
|
||||
/** this record is always padded to a constant length */
|
||||
private byte[] padding;
|
||||
private static final byte[] PADDING = new byte[DATA_SIZE];
|
||||
static {
|
||||
Arrays.fill(PADDING, PAD_CHAR);
|
||||
}
|
||||
|
||||
public WriteAccessRecord() {
|
||||
setUsername("");
|
||||
padding = new byte[DATA_SIZE - 3];
|
||||
}
|
||||
|
||||
public WriteAccessRecord(RecordInputStream in) {
|
||||
|
@ -57,21 +60,33 @@ public final class WriteAccessRecord extends StandardRecord {
|
|||
|
||||
int nChars = in.readUShort();
|
||||
int is16BitFlag = in.readUByte();
|
||||
int expectedPadSize = DATA_SIZE - 3;
|
||||
if ((is16BitFlag & 0x01) == 0x00) {
|
||||
field_1_username = StringUtil.readCompressedUnicode(in, nChars);
|
||||
expectedPadSize -= nChars;
|
||||
} else {
|
||||
field_1_username = StringUtil.readUnicodeLE(in, nChars);
|
||||
expectedPadSize -= nChars * 2;
|
||||
if (nChars > DATA_SIZE || (is16BitFlag & 0xFE) != 0) {
|
||||
// String header looks wrong (probably missing)
|
||||
// OOO doc says this is optional anyway.
|
||||
// reconstruct data
|
||||
byte[] data = new byte[3 + in.remaining()];
|
||||
LittleEndian.putUShort(data, 0, nChars);
|
||||
LittleEndian.putByte(data, 2, is16BitFlag);
|
||||
in.readFully(data, 3, data.length-3);
|
||||
String rawValue = new String(data);
|
||||
setUsername(rawValue.trim());
|
||||
return;
|
||||
}
|
||||
padding = new byte[expectedPadSize];
|
||||
|
||||
String rawText;
|
||||
if ((is16BitFlag & 0x01) == 0x00) {
|
||||
rawText = StringUtil.readCompressedUnicode(in, nChars);
|
||||
} else {
|
||||
rawText = StringUtil.readUnicodeLE(in, nChars);
|
||||
}
|
||||
field_1_username = rawText.trim();
|
||||
|
||||
// consume padding
|
||||
int padSize = in.remaining();
|
||||
in.readFully(padding, 0, padSize);
|
||||
if (padSize < expectedPadSize) {
|
||||
// this occurs in a couple of test examples: "42564.xls",
|
||||
// "bug_42794.xls"
|
||||
Arrays.fill(padding, padSize, expectedPadSize, PAD_CHAR);
|
||||
while (padSize > 0) {
|
||||
// in some cases this seems to be garbage (non spaces)
|
||||
in.readUByte();
|
||||
padSize--;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,8 +103,6 @@ public final class WriteAccessRecord extends StandardRecord {
|
|||
if (paddingSize < 0) {
|
||||
throw new IllegalArgumentException("Name is too long: " + username);
|
||||
}
|
||||
padding = new byte[paddingSize];
|
||||
Arrays.fill(padding, PAD_CHAR);
|
||||
|
||||
field_1_username = username;
|
||||
}
|
||||
|
@ -109,7 +122,7 @@ public final class WriteAccessRecord extends StandardRecord {
|
|||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
buffer.append("[WRITEACCESS]\n");
|
||||
buffer.append(" .name = ").append(field_1_username.toString()).append("\n");
|
||||
buffer.append(" .name = ").append(field_1_username.toString()).append("\n");
|
||||
buffer.append("[/WRITEACCESS]\n");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
@ -125,7 +138,9 @@ public final class WriteAccessRecord extends StandardRecord {
|
|||
} else {
|
||||
StringUtil.putCompressedUnicode(username, out);
|
||||
}
|
||||
out.write(padding);
|
||||
int encodedByteCount = 3 + username.length() * (is16bit ? 2 : 1);
|
||||
int paddingSize = DATA_SIZE - encodedByteCount;
|
||||
out.write(PADDING, 0, paddingSize);
|
||||
}
|
||||
|
||||
protected int getDataSize() {
|
||||
|
|
|
@ -34,6 +34,7 @@ public final class AllModelTests {
|
|||
result.addTestSuite(TestFormulaParser.class);
|
||||
result.addTestSuite(TestFormulaParserEval.class);
|
||||
result.addTestSuite(TestFormulaParserIf.class);
|
||||
result.addTestSuite(TestLinkTable.class);
|
||||
result.addTestSuite(TestOperandClassTransformer.class);
|
||||
result.addTestSuite(TestRowBlocksReader.class);
|
||||
result.addTestSuite(TestRVA.class);
|
||||
|
|
|
@ -15,12 +15,20 @@
|
|||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.usermodel;
|
||||
package org.apache.poi.hssf.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.record.Record;
|
||||
import org.apache.poi.hssf.record.SSTRecord;
|
||||
import org.apache.poi.hssf.record.SupBookRecord;
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
/**
|
||||
* Tests for {@link LinkTable}
|
||||
*
|
||||
|
@ -81,7 +89,7 @@ public final class TestLinkTable extends TestCase {
|
|||
The original file produces the same error.
|
||||
|
||||
This bug was caused by a combination of invalid sheet indexes in the EXTERNSHEET
|
||||
record, and eager initialisation of the extern sheet references. Note - the worbook
|
||||
record, and eager initialisation of the extern sheet references. Note - the workbook
|
||||
has 2 sheets, but the EXTERNSHEET record refers to sheet indexes 0, 1 and 2.
|
||||
|
||||
Offset 0x3954 (14676)
|
||||
|
@ -114,4 +122,30 @@ public final class TestLinkTable extends TestCase {
|
|||
}
|
||||
assertEquals("Data!$A2", cellFormula);
|
||||
}
|
||||
|
||||
/**
|
||||
* This problem was visible in POI svn r763332
|
||||
* when reading the workbook of attachment 23468 from bugzilla 47001
|
||||
*/
|
||||
public void testMissingExternSheetRecord_bug47001b() {
|
||||
|
||||
Record[] recs = {
|
||||
SupBookRecord.createAddInFunctions(),
|
||||
new SSTRecord(),
|
||||
};
|
||||
List<Record> recList = Arrays.asList(recs);
|
||||
WorkbookRecordList wrl = new WorkbookRecordList();
|
||||
|
||||
LinkTable lt;
|
||||
try {
|
||||
lt = new LinkTable(recList, 0, wrl);
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().equals("Expected an EXTERNSHEET record but got (org.apache.poi.hssf.record.SSTRecord)")) {
|
||||
throw new AssertionFailedError("Identified bug 47001b");
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
assertNotNull(lt);
|
||||
}
|
||||
}
|
|
@ -80,6 +80,7 @@ public final class AllRecordTests {
|
|||
result.addTestSuite(TestTextObjectRecord.class);
|
||||
result.addTestSuite(TestUnicodeNameRecord.class);
|
||||
result.addTestSuite(TestUnicodeString.class);
|
||||
result.addTestSuite(TestWriteAccessRecord.class);
|
||||
result.addTestSuite(TestCellRange.class);
|
||||
result.addTestSuite(TestConstantValueParser.class);
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.util.HexRead;
|
||||
|
||||
/**
|
||||
* Tests for {@link WriteAccessRecord}
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class TestWriteAccessRecord extends TestCase {
|
||||
|
||||
private static final String HEX_SIXTYFOUR_SPACES = ""
|
||||
+ "20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 "
|
||||
+ "20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 "
|
||||
+ "20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 "
|
||||
+ "20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20";
|
||||
|
||||
|
||||
public void testMissingStringHeader_bug47001a() {
|
||||
/*
|
||||
* Data taken from offset 0x0224 in
|
||||
* attachment 23468 from bugzilla 47001
|
||||
*/
|
||||
byte[] data = HexRead.readFromString(""
|
||||
+ "5C 00 70 00 "
|
||||
+ "4A 61 76 61 20 45 78 63 65 6C 20 41 50 49 20 76 "
|
||||
+ "32 2E 36 2E 34"
|
||||
+ "20 20 20 20 20 20 20 20 20 20 20 "
|
||||
+ "20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 "
|
||||
+ HEX_SIXTYFOUR_SPACES);
|
||||
|
||||
RecordInputStream in = TestcaseRecordInputStream.create(data);
|
||||
|
||||
WriteAccessRecord rec;
|
||||
try {
|
||||
rec = new WriteAccessRecord(in);
|
||||
} catch (RecordFormatException e) {
|
||||
if (e.getMessage().equals("Not enough data (0) to read requested (1) bytes")) {
|
||||
throw new AssertionFailedError("Identified bug 47001a");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
assertEquals("Java Excel API v2.6.4", rec.getUsername());
|
||||
|
||||
|
||||
byte[] expectedEncoding = HexRead.readFromString(""
|
||||
+ "15 00 00 4A 61 76 61 20 45 78 63 65 6C 20 41 50 "
|
||||
+ "49 20 76 32 2E 36 2E 34"
|
||||
+ "20 20 20 20 20 20 20 20 "
|
||||
+ "20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 "
|
||||
+ HEX_SIXTYFOUR_SPACES);
|
||||
|
||||
TestcaseRecordInputStream.confirmRecordEncoding(WriteAccessRecord.sid, expectedEncoding, rec.serialize());
|
||||
}
|
||||
|
||||
public void testShortRecordWrittenByMSAccess() {
|
||||
/*
|
||||
* Data taken from two example files
|
||||
* ex42564-21435.xls
|
||||
* bug_42794.xls (from bug 42794 attachment 20429)
|
||||
* In both cases, this data is found at offset 0x0C1C.
|
||||
*/
|
||||
byte[] data = HexRead.readFromString(""
|
||||
+ "5C 00 39 00 "
|
||||
+ "36 00 00 41 20 73 61 74 69 73 66 69 65 64 20 4D "
|
||||
+ "69 63 72 6F 73 6F 66 74 20 4F 66 66 69 63 65 39 "
|
||||
+ "20 55 73 65 72"
|
||||
+ "20 20 20 20 20 20 20 20 20 20 20 "
|
||||
+ "20 20 20 20 20 20 20 20 20");
|
||||
|
||||
RecordInputStream in = TestcaseRecordInputStream.create(data);
|
||||
WriteAccessRecord rec = new WriteAccessRecord(in);
|
||||
assertEquals("A satisfied Microsoft Office9 User", rec.getUsername());
|
||||
byte[] expectedEncoding = HexRead.readFromString(""
|
||||
+ "22 00 00 41 20 73 61 74 69 73 66 69 65 64 20 4D "
|
||||
+ "69 63 72 6F 73 6F 66 74 20 4F 66 66 69 63 65 39 "
|
||||
+ "20 55 73 65 72"
|
||||
+ "20 20 20 20 20 20 20 20 20 20 20 "
|
||||
+ HEX_SIXTYFOUR_SPACES);
|
||||
|
||||
TestcaseRecordInputStream.confirmRecordEncoding(WriteAccessRecord.sid, expectedEncoding, rec.serialize());
|
||||
}
|
||||
}
|
|
@ -59,7 +59,6 @@ public class AllUserModelTests {
|
|||
result.addTestSuite(TestHSSFSheet.class);
|
||||
result.addTestSuite(TestHSSFTextbox.class);
|
||||
result.addTestSuite(TestHSSFWorkbook.class);
|
||||
result.addTestSuite(TestLinkTable.class);
|
||||
result.addTestSuite(TestHSSFName.class);
|
||||
result.addTestSuite(TestOLE2Embeding.class);
|
||||
result.addTestSuite(TestPOIFSProperties.class);
|
||||
|
|
|
@ -586,7 +586,7 @@ public final class TestBugs extends BaseTestBugzillaIssues {
|
|||
* when reading the BOFRecord
|
||||
*/
|
||||
public void test42564() {
|
||||
HSSFWorkbook wb = openSample("42564.xls");
|
||||
HSSFWorkbook wb = openSample("ex42564-21435.xls");
|
||||
writeOutAndReadBack(wb);
|
||||
}
|
||||
|
||||
|
@ -596,7 +596,7 @@ public final class TestBugs extends BaseTestBugzillaIssues {
|
|||
* issue.
|
||||
*/
|
||||
public void test42564Alt() {
|
||||
HSSFWorkbook wb = openSample("42564-2.xls");
|
||||
HSSFWorkbook wb = openSample("ex42564-21503.xls");
|
||||
writeOutAndReadBack(wb);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue