Browse Source

#64004 - Replace clone() with copy constructor - mainly HSSF classes

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1871911 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_4_1_2
Andreas Beeker 4 years ago
parent
commit
ba6152503e
100 changed files with 2743 additions and 2011 deletions
  1. 25
    25
      src/integrationtest/org/apache/poi/TestAllFiles.java
  2. 9
    11
      src/integrationtest/org/apache/poi/hssf/usermodel/RecordsStresser.java
  3. 39
    0
      src/java/org/apache/poi/common/Duplicatable.java
  4. 0
    3
      src/java/org/apache/poi/ddf/AbstractEscherOptRecord.java
  5. 3
    6
      src/java/org/apache/poi/ddf/EscherContainerRecord.java
  6. 7
    1
      src/java/org/apache/poi/ddf/EscherRecord.java
  7. 1
    1
      src/java/org/apache/poi/ddf/EscherTextboxRecord.java
  8. 1
    1
      src/java/org/apache/poi/ddf/UnknownEscherRecord.java
  9. 3
    5
      src/java/org/apache/poi/hssf/eventusermodel/dummyrecord/DummyRecordBase.java
  10. 11
    6
      src/java/org/apache/poi/hssf/eventusermodel/dummyrecord/LastCellOfRowDummyRecord.java
  11. 8
    3
      src/java/org/apache/poi/hssf/eventusermodel/dummyrecord/MissingCellDummyRecord.java
  12. 7
    2
      src/java/org/apache/poi/hssf/eventusermodel/dummyrecord/MissingRowDummyRecord.java
  13. 16
    24
      src/java/org/apache/poi/hssf/model/InternalSheet.java
  14. 8
    1
      src/java/org/apache/poi/hssf/model/RecordStream.java
  15. 22
    15
      src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java
  16. 21
    11
      src/java/org/apache/poi/hssf/record/ArrayRecord.java
  17. 20
    13
      src/java/org/apache/poi/hssf/record/AutoFilterInfoRecord.java
  18. 41
    35
      src/java/org/apache/poi/hssf/record/BOFRecord.java
  19. 18
    15
      src/java/org/apache/poi/hssf/record/BackupRecord.java
  20. 27
    19
      src/java/org/apache/poi/hssf/record/BlankRecord.java
  21. 18
    15
      src/java/org/apache/poi/hssf/record/BookBoolRecord.java
  22. 21
    14
      src/java/org/apache/poi/hssf/record/BoolErrRecord.java
  23. 17
    10
      src/java/org/apache/poi/hssf/record/BottomMarginRecord.java
  24. 29
    23
      src/java/org/apache/poi/hssf/record/BoundSheetRecord.java
  25. 18
    7
      src/java/org/apache/poi/hssf/record/CFHeader12Record.java
  26. 18
    11
      src/java/org/apache/poi/hssf/record/CFHeaderBase.java
  27. 16
    5
      src/java/org/apache/poi/hssf/record/CFHeaderRecord.java
  28. 84
    86
      src/java/org/apache/poi/hssf/record/CFRule12Record.java
  29. 56
    53
      src/java/org/apache/poi/hssf/record/CFRuleBase.java
  30. 22
    12
      src/java/org/apache/poi/hssf/record/CFRuleRecord.java
  31. 18
    14
      src/java/org/apache/poi/hssf/record/CRNCountRecord.java
  32. 23
    12
      src/java/org/apache/poi/hssf/record/CRNRecord.java
  33. 28
    19
      src/java/org/apache/poi/hssf/record/CalcCountRecord.java
  34. 28
    32
      src/java/org/apache/poi/hssf/record/CalcModeRecord.java
  35. 12
    10
      src/java/org/apache/poi/hssf/record/CellRecord.java
  36. 21
    16
      src/java/org/apache/poi/hssf/record/CodepageRecord.java
  37. 29
    18
      src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java
  38. 79
    71
      src/java/org/apache/poi/hssf/record/CommonObjectDataSubRecord.java
  39. 20
    9
      src/java/org/apache/poi/hssf/record/ContinueRecord.java
  40. 20
    16
      src/java/org/apache/poi/hssf/record/CountryRecord.java
  41. 18
    36
      src/java/org/apache/poi/hssf/record/DBCellRecord.java
  42. 43
    59
      src/java/org/apache/poi/hssf/record/DConRefRecord.java
  43. 15
    5
      src/java/org/apache/poi/hssf/record/DSFRecord.java
  44. 26
    17
      src/java/org/apache/poi/hssf/record/DVALRecord.java
  45. 61
    45
      src/java/org/apache/poi/hssf/record/DVRecord.java
  46. 18
    15
      src/java/org/apache/poi/hssf/record/DateWindow1904Record.java
  47. 23
    15
      src/java/org/apache/poi/hssf/record/DefaultColWidthRecord.java
  48. 26
    22
      src/java/org/apache/poi/hssf/record/DefaultRowHeightRecord.java
  49. 18
    8
      src/java/org/apache/poi/hssf/record/DeltaRecord.java
  50. 25
    20
      src/java/org/apache/poi/hssf/record/DimensionsRecord.java
  51. 13
    7
      src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java
  52. 20
    13
      src/java/org/apache/poi/hssf/record/DrawingRecord.java
  53. 9
    2
      src/java/org/apache/poi/hssf/record/DrawingRecordForBiffViewer.java
  54. 21
    7
      src/java/org/apache/poi/hssf/record/DrawingSelectionRecord.java
  55. 16
    16
      src/java/org/apache/poi/hssf/record/EOFRecord.java
  56. 28
    7
      src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
  57. 13
    8
      src/java/org/apache/poi/hssf/record/EndSubRecord.java
  58. 13
    1
      src/java/org/apache/poi/hssf/record/EscherAggregate.java
  59. 32
    16
      src/java/org/apache/poi/hssf/record/ExtSSTRecord.java
  60. 130
    141
      src/java/org/apache/poi/hssf/record/ExtendedFormatRecord.java
  61. 55
    47
      src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
  62. 65
    48
      src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
  63. 40
    22
      src/java/org/apache/poi/hssf/record/FeatHdrRecord.java
  64. 49
    31
      src/java/org/apache/poi/hssf/record/FeatRecord.java
  65. 16
    10
      src/java/org/apache/poi/hssf/record/FilePassRecord.java
  66. 25
    14
      src/java/org/apache/poi/hssf/record/FileSharingRecord.java
  67. 16
    14
      src/java/org/apache/poi/hssf/record/FnGroupCountRecord.java
  68. 53
    30
      src/java/org/apache/poi/hssf/record/FontRecord.java
  69. 18
    6
      src/java/org/apache/poi/hssf/record/FooterRecord.java
  70. 15
    8
      src/java/org/apache/poi/hssf/record/FormatRecord.java
  71. 38
    169
      src/java/org/apache/poi/hssf/record/FormulaRecord.java
  72. 167
    0
      src/java/org/apache/poi/hssf/record/FormulaSpecialCachedValue.java
  73. 19
    12
      src/java/org/apache/poi/hssf/record/FtCblsSubRecord.java
  74. 21
    10
      src/java/org/apache/poi/hssf/record/FtCfSubRecord.java
  75. 31
    20
      src/java/org/apache/poi/hssf/record/FtPioGrbitSubRecord.java
  76. 19
    16
      src/java/org/apache/poi/hssf/record/GridsetRecord.java
  77. 17
    6
      src/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java
  78. 33
    23
      src/java/org/apache/poi/hssf/record/GutsRecord.java
  79. 22
    19
      src/java/org/apache/poi/hssf/record/HCenterRecord.java
  80. 9
    2
      src/java/org/apache/poi/hssf/record/HeaderFooterBase.java
  81. 24
    14
      src/java/org/apache/poi/hssf/record/HeaderFooterRecord.java
  82. 18
    9
      src/java/org/apache/poi/hssf/record/HeaderRecord.java
  83. 20
    17
      src/java/org/apache/poi/hssf/record/HideObjRecord.java
  84. 16
    11
      src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java
  85. 60
    41
      src/java/org/apache/poi/hssf/record/HyperlinkRecord.java
  86. 26
    22
      src/java/org/apache/poi/hssf/record/IndexRecord.java
  87. 6
    5
      src/java/org/apache/poi/hssf/record/InterfaceEndRecord.java
  88. 15
    7
      src/java/org/apache/poi/hssf/record/InterfaceHdrRecord.java
  89. 21
    11
      src/java/org/apache/poi/hssf/record/IterationRecord.java
  90. 32
    24
      src/java/org/apache/poi/hssf/record/LabelRecord.java
  91. 19
    12
      src/java/org/apache/poi/hssf/record/LabelSSTRecord.java
  92. 48
    12
      src/java/org/apache/poi/hssf/record/LbsDataSubRecord.java
  93. 20
    9
      src/java/org/apache/poi/hssf/record/LeftMarginRecord.java
  94. 20
    17
      src/java/org/apache/poi/hssf/record/MMSRecord.java
  95. 27
    13
      src/java/org/apache/poi/hssf/record/MergeCellsRecord.java
  96. 14
    8
      src/java/org/apache/poi/hssf/record/MulBlankRecord.java
  97. 14
    11
      src/java/org/apache/poi/hssf/record/MulRKRecord.java
  98. 140
    131
      src/java/org/apache/poi/hssf/record/NameCommentRecord.java
  99. 43
    20
      src/java/org/apache/poi/hssf/record/NameRecord.java
  100. 0
    0
      src/java/org/apache/poi/hssf/record/NoteRecord.java

+ 25
- 25
src/integrationtest/org/apache/poi/TestAllFiles.java View File

@@ -65,26 +65,26 @@ import org.junit.runners.Parameterized.Parameters;

/**
* This is an integration test which performs various actions on all stored test-files and tries
* to reveal problems which are introduced, but not covered (yet) by unit tests.
*
* This test looks for any file under the test-data directory and tries to do some useful
* to reveal problems which are introduced, but not covered (yet) by unit tests.
*
* This test looks for any file under the test-data directory and tries to do some useful
* processing with it based on it's type.
*
*
* The test is implemented as a junit {@link Parameterized} test, which leads
* to one test-method call for each file (currently around 950 files are handled).
*
* There is a a mapping of extension to implementations of the interface
* {@link FileHandler} which defines how the file is loaded and which actions are
* tried with the file.
*
* to one test-method call for each file (currently around 950 files are handled).
*
* There is a a mapping of extension to implementations of the interface
* {@link FileHandler} which defines how the file is loaded and which actions are
* tried with the file.
*
* The test can be expanded by adding more actions to the FileHandlers, this automatically
* applies the action to any such file in our test-data repository.
*
*
* There is also a list of files that should actually fail.
*
* Note: It is also a test-failure if a file that is expected to fail now actually works,
* i.e. if a bug was fixed in POI itself, the file should be removed from the expected-failures
* here as well! This is to ensure that files that should not work really do not work, e.g.
*
* Note: It is also a test-failure if a file that is expected to fail now actually works,
* i.e. if a bug was fixed in POI itself, the file should be removed from the expected-failures
* here as well! This is to ensure that files that should not work really do not work, e.g.
* that we do not remove expected sanity checks.
*/
@RunWith(Parameterized.class)
@@ -96,7 +96,7 @@ public class TestAllFiles {

private static final Map<String,String> FILE_PASSWORD;

// map file extensions to the actual mappers
public static final Map<String, FileHandler> HANDLERS = new HashMap<>();

@@ -136,7 +136,7 @@ public class TestAllFiles {

// Visio - binary
HANDLERS.put(".vsd", IGNORE_SCRATCHPAD ? new HPSFFileHandler() : new HDGFFileHandler());
// Visio - ooxml
HANDLERS.put(".vsdm", new XDGFFileHandler());
HANDLERS.put(".vsdx", new XDGFFileHandler());
@@ -238,7 +238,7 @@ public class TestAllFiles {
passmap.put("poifs/protected_agile.docx", Decryptor.DEFAULT_PASSWORD);
passmap.put("poifs/60320-protected.xlsx", "Test001!!");
passmap.put("poifs/protected_sha512.xlsx", "this is a test");
FILE_PASSWORD = Collections.unmodifiableMap(passmap);
}

@@ -326,7 +326,7 @@ public class TestAllFiles {
"spreadsheet/testEXCEL_95.xls",
"spreadsheet/59074.xls",
"spreadsheet/60284.xls",
// OOXML Strict is not yet supported, see bug #57699
"spreadsheet/SampleSS.strict.xlsx",
"spreadsheet/SimpleStrict.xlsx",
@@ -342,7 +342,7 @@ public class TestAllFiles {

// sheet cloning errors
"spreadsheet/56450.xls",
"spreadsheet/OddStyleRecord.xls",
// "spreadsheet/OddStyleRecord.xls",

// msg files with non-standard encodings
"hsmf/ASCII_CP1251_LCID1049.msg",
@@ -377,7 +377,7 @@ public class TestAllFiles {
}
FileHandler handler = HANDLERS.get(getExtension(file));
files.add(new Object[] { file, handler });
// for some file-types also run OPCFileHandler
if(handler instanceof XSSFFileHandler ||
handler instanceof XWPFFileHandler ||
@@ -385,7 +385,7 @@ public class TestAllFiles {
handler instanceof XDGFFileHandler) {
files.add(new Object[] { file, new OPCFileHandler() });
}
if (handler instanceof HSSFFileHandler ||
handler instanceof HSLFFileHandler ||
handler instanceof HWPFFileHandler ||
@@ -410,7 +410,7 @@ public class TestAllFiles {
String pass = TestAllFiles.FILE_PASSWORD.get(file);
Biff8EncryptionKey.setCurrentUserPassword(pass);
}
@Test
public void testAllFiles() throws Exception {
if(handler == null) {
@@ -426,7 +426,7 @@ public class TestAllFiles {
file.endsWith(".xlsb") || file.endsWith(".pptx")) &&
handler instanceof OPCFileHandler;
boolean ignoreHPSF = (handler instanceof HPSFFileHandler);
try {
try (InputStream stream = new BufferedInputStream(new FileInputStream(inputFile), 64 * 1024)) {
handler.handleFile(stream, file);
@@ -436,7 +436,7 @@ public class TestAllFiles {

handler.handleExtracting(inputFile);

assertFalse("Expected to fail for file " + file + " and handler " + handler + ", but did not fail!",
assertFalse("Expected to fail for file " + file + " and handler " + handler + ", but did not fail!",
EXPECTED_FAILURES.contains(file) && !ignoredOPC && !ignoreHPSF);
} catch (OldFileFormatException e) {
// for old word files we should still support extracting text

+ 9
- 11
src/integrationtest/org/apache/poi/hssf/usermodel/RecordsStresser.java View File

@@ -28,14 +28,14 @@ import org.apache.poi.hssf.record.Record;
import org.junit.Test;

/**
* Needs to be implemented in this package to have access to
* Needs to be implemented in this package to have access to
* HSSFWorkbook.getWorkbook()
*/
public class RecordsStresser {
public static void handleWorkbook(HSSFWorkbook wb) {
List<Record> records = wb.getWorkbook().getRecords();
for(Record record : records) {
// some Records do not implement clone ?!
// some Records do not implement clone ?!
// equals instead of instanceof is on purpose here to only skip exactly this class and not any derived ones
// if(record.getClass().equals(InterfaceHdrRecord.class) ||
// record.getClass().equals(MMSRecord.class) ||
@@ -46,18 +46,16 @@ public class RecordsStresser {
// continue;
// }
try {
Record newRecord = (Record) record.clone();
assertEquals("Expecting the same class back from clone(), but had Record of type " + record.getClass() + " and got back a " + newRecord.getClass() + " from clone()",
record.getClass(), newRecord.getClass());
Record newRecord = record.copy();
assertEquals("Expecting the same class back from clone(), but had Record of type " + record.getClass() + " and got back a " + newRecord.getClass() + " from clone()",
record.getClass(), newRecord.getClass());
byte[] origBytes = record.serialize();
byte[] newBytes = newRecord.serialize();
assertArrayEquals("Record of type " + record.getClass() + " should return the same byte array via the clone() method, but did return a different array",
assertArrayEquals("Record of type " + record.getClass() + " should return the same byte array via the clone() method, but did return a different array",
origBytes, newBytes);
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
} catch (RuntimeException e) {
// some Records do not implement clone, ignore those for now
assertTrue(e.getMessage().contains("needs to define a clone method"));

+ 39
- 0
src/java/org/apache/poi/common/Duplicatable.java View File

@@ -0,0 +1,39 @@
/* ====================================================================
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.common;

/**
* This is an alternative to the {@link Cloneable} interface without its side-effects.
* A class implementing Duplicatable provides a deep-copy of itself - usually this is done via a copy-constructor,
* which is invoked with a self-reference by the copy method.
* References to child objects are duplicated - references to parents are kept as-is and
* might need to be replaced by the parent copy operation.
*
* @param <T> the implementing class itself
*
* @see <a href="https://www.artima.com/intv/bloch.html#part13">Copy Constructor versus Cloning</a>
*/
public interface Duplicatable {
// Providing a generics interface Duplicatable<T extends Duplicatable<T>> pushes too many
// changes to the implementing classes and the benefit of providing a subtype-specific copy method
// is not sufficient
/**
* @return a deep copy of the implementing class / instance
*/
Duplicatable copy();
}

+ 0
- 3
src/java/org/apache/poi/ddf/AbstractEscherOptRecord.java View File

@@ -171,7 +171,4 @@ public abstract class AbstractEscherOptRecord extends EscherRecord {
"properties", this::getEscherProperties
);
}

@Override
public abstract AbstractEscherOptRecord copy();
}

+ 3
- 6
src/java/org/apache/poi/ddf/EscherContainerRecord.java View File

@@ -142,13 +142,9 @@ public final class EscherContainerRecord extends EscherRecord implements Iterabl
* @return true, if any child has the given recordId
*/
public boolean hasChildOfType(short recordId) {
for (EscherRecord r : this) {
if(r.getRecordId() == recordId) {
return true;
}
}
return false;
return _childRecords.stream().anyMatch(r -> r.getRecordId() == recordId);
}

@Override
public EscherRecord getChild( int index ) {
return _childRecords.get(index);
@@ -170,6 +166,7 @@ public final class EscherContainerRecord extends EscherRecord implements Iterabl
return Collections.unmodifiableList(_childRecords).iterator();
}


/**
* replaces the internal child list with the contents of the supplied <tt>childRecords</tt>
*/

+ 7
- 1
src/java/org/apache/poi/ddf/EscherRecord.java View File

@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

import org.apache.poi.common.Duplicatable;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
@@ -32,12 +33,13 @@ import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.GenericRecordXmlWriter;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.Removal;

/**
* The base abstract record from which all escher records are defined. Subclasses will need
* to define methods for serialization/deserialization and for determining the record size.
*/
public abstract class EscherRecord implements Cloneable, GenericRecord {
public abstract class EscherRecord implements Duplicatable, GenericRecord {
private static final BitField fInstance = BitFieldFactory.getInstance(0xfff0);
private static final BitField fVersion = BitFieldFactory.getInstance(0x000f);

@@ -238,9 +240,12 @@ public abstract class EscherRecord implements Cloneable, GenericRecord {
* Escher records may need to be clonable in the future.
*
* @return the cloned object
* @deprecated use {@link #copy()}
*/
@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public final EscherRecord clone() {
return copy();
}
@@ -350,5 +355,6 @@ public abstract class EscherRecord implements Cloneable, GenericRecord {
);
}

@Override
public abstract EscherRecord copy();
}

+ 1
- 1
src/java/org/apache/poi/ddf/EscherTextboxRecord.java View File

@@ -31,7 +31,7 @@ import org.apache.poi.util.RecordFormatException;
* Escher format. We don't attempt to understand the contents, since
* they will be in the parent's format, not Escher format.
*/
public final class EscherTextboxRecord extends EscherRecord implements Cloneable {
public final class EscherTextboxRecord extends EscherRecord {

//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;

+ 1
- 1
src/java/org/apache/poi/ddf/UnknownEscherRecord.java View File

@@ -31,7 +31,7 @@ import org.apache.poi.util.LittleEndian;
* This record is used whenever a escher record is encountered that
* we do not explicitly support.
*/
public final class UnknownEscherRecord extends EscherRecord implements Cloneable {
public final class UnknownEscherRecord extends EscherRecord {

//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000_000;

+ 3
- 5
src/java/org/apache/poi/hssf/eventusermodel/dummyrecord/DummyRecordBase.java View File

@@ -23,11 +23,9 @@ import org.apache.poi.util.RecordFormatException;
/**
*/
abstract class DummyRecordBase extends Record {
protected DummyRecordBase() {
//
}

protected DummyRecordBase() {}

public final short getSid() {
return -1;
}

+ 11
- 6
src/java/org/apache/poi/hssf/eventusermodel/dummyrecord/LastCellOfRowDummyRecord.java View File

@@ -25,37 +25,42 @@ package org.apache.poi.hssf.eventusermodel.dummyrecord;
public final class LastCellOfRowDummyRecord extends DummyRecordBase {
private final int row;
private final int lastColumnNumber;
public LastCellOfRowDummyRecord(int row, int lastColumnNumber) {
this.row = row;
this.lastColumnNumber = lastColumnNumber;
}
/**
* Returns the (0 based) number of the row we are
* currently working on.
*
*
* @return the (0 based) number of the row
*/
public int getRow() {
return row;
}
/**
* Returns the (0 based) number of the last column
* seen for this row. You should have already been
* called with that record.
* This is -1 in the case of there being no columns
* for the row.
*
*
* @return the (0 based) number of the last column
*/
public int getLastColumnNumber() {
return lastColumnNumber;
}
@Override
public String toString() {
return "End-of-Row for Row=" + row + " at Column=" + lastColumnNumber;
}

@Override
public LastCellOfRowDummyRecord copy() {
return this;
}
}

+ 8
- 3
src/java/org/apache/poi/hssf/eventusermodel/dummyrecord/MissingCellDummyRecord.java View File

@@ -23,13 +23,18 @@ package org.apache.poi.hssf.eventusermodel.dummyrecord;
* but still want to trigger something
*/
public final class MissingCellDummyRecord extends DummyRecordBase {
private int row;
private int column;
private final int row;
private final int column;
public MissingCellDummyRecord(int row, int column) {
this.row = row;
this.column = column;
}
public int getRow() { return row; }
public int getColumn() { return column; }

@Override
public MissingCellDummyRecord copy() {
return this;
}
}

+ 7
- 2
src/java/org/apache/poi/hssf/eventusermodel/dummyrecord/MissingRowDummyRecord.java View File

@@ -23,12 +23,17 @@ package org.apache.poi.hssf.eventusermodel.dummyrecord;
* want to trigger something
*/
public final class MissingRowDummyRecord extends DummyRecordBase {
private int rowNumber;
private final int rowNumber;
public MissingRowDummyRecord(int rowNumber) {
this.rowNumber = rowNumber;
}
public int getRowNumber() {
return rowNumber;
}

@Override
public MissingRowDummyRecord copy() {
return this;
}
}

+ 16
- 24
src/java/org/apache/poi/hssf/model/InternalSheet.java View File

@@ -132,7 +132,7 @@ public final class InternalSheet {
if (rs.peekNextSid() != BOFRecord.sid) {
throw new RecordFormatException("BOF record expected");
}
BOFRecord bof = (BOFRecord) rs.getNext();
if (bof.getType() == BOFRecord.TYPE_WORKSHEET) {
// Good, well supported
@@ -152,7 +152,7 @@ public final class InternalSheet {
throw new UnsupportedBOFType(bof.getType());
}
records.add(bof);
while (rs.hasNext()) {
int recSid = rs.peekNextSid();

@@ -339,14 +339,14 @@ public final class InternalSheet {
recs.add(r);
}});
}
public static class UnsupportedBOFType extends RecordFormatException {
private final int type;
protected UnsupportedBOFType(int type) {
super("BOF not of a supported type, found " + type);
this.type = type;
}
public int getType() {
return type;
}
@@ -360,11 +360,7 @@ public final class InternalSheet {
_destList = destList;
}
public void visitRecord(Record r) {
try {
_destList.add((Record)r.clone());
} catch (CloneNotSupportedException e) {
throw new RecordFormatException(e);
}
_destList.add(r.copy());
}
}

@@ -374,7 +370,7 @@ public final class InternalSheet {
* can be added to a sheet. The <b>Record</b> object does not implement cloneable.
* When adding a new record, implement a public clone method if and only if the record
* belongs to a sheet.
*
*
* @return the cloned sheet
*/
public InternalSheet cloneSheet() {
@@ -391,12 +387,8 @@ public final class InternalSheet {
*/
rb = new DrawingRecord();
}
try {
Record rec = (Record) ((Record) rb).clone();
clonedRecords.add(rec);
} catch (CloneNotSupportedException e) {
throw new RecordFormatException(e);
}
Record rec = ((Record) rb).copy();
clonedRecords.add(rec);
}
return createSheet(new RecordStream(clonedRecords, 0));
}
@@ -478,7 +470,7 @@ public final class InternalSheet {

/**
* Updates formulas in cells and conditional formats due to moving of cells
*
*
* @param shifter the formular shifter
* @param externSheetIndex the externSheet index of this sheet
*/
@@ -995,7 +987,7 @@ public final class InternalSheet {

/**
* set the default row height for the sheet (if the rows do not define their own height)
*
*
* @param dch the default row height
*/
public void setDefaultRowHeight(short dch) {
@@ -1247,7 +1239,7 @@ public final class InternalSheet {

/**
* Gets the gridset record for this sheet.
*
*
* @return the gridset record for this sheet
*/
public GridsetRecord getGridsetRecord()
@@ -1257,9 +1249,9 @@ public final class InternalSheet {

/**
* Returns the first occurrence of a record matching a particular sid.
*
*
* @param sid the sid to search for
*
*
* @return the matching record or {@code null} if it wasn't found
*/
public Record findFirstRecordBySid(short sid) {
@@ -1330,7 +1322,7 @@ public final class InternalSheet {
{
printGridlines = newPrintGridlines;
}
/**
* Returns the PrintHeadersRecord.
* @return PrintHeadersRecord for the sheet.
@@ -1519,7 +1511,7 @@ public final class InternalSheet {
public boolean isDisplayRowColHeadings() {
return windowTwo.getDisplayRowColHeadings();
}
/**
* Sets whether the RowColHeadings are shown in a viewer.
* @param show whether to show RowColHeadings or not
@@ -1681,7 +1673,7 @@ public final class InternalSheet {
temp.toArray(result);
return result;
}
public int getColumnOutlineLevel(int columnIndex) {
return _columnInfos.getOutlineLevel(columnIndex);
}

+ 8
- 1
src/java/org/apache/poi/hssf/model/RecordStream.java View File

@@ -32,7 +32,7 @@ public final class RecordStream {

/**
* Creates a RecordStream bounded by startIndex and endIndex
*
*
* @param inputList the list to iterate over
* @param startIndex the start index within the list
* @param endIx the end index within the list, which is the index of the end element + 1
@@ -70,6 +70,13 @@ public final class RecordStream {
return _list.get(_nextIndex).getClass();
}

/**
* @return the next Record. <code>null</code> if this stream is exhausted.
*/
public Record peekNextRecord() {
return (hasNext()) ? _list.get(_nextIndex) : null;
}

/**
* @return -1 if at end of records
*/

+ 22
- 15
src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java View File

@@ -25,14 +25,15 @@ import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherRecordFactory;
import org.apache.poi.ddf.NullEscherSerializationListener;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hssf.util.LazilyConcatenatedByteArray;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.Removal;

/**
* The escher container record is used to hold escher records. It is abstract and
* must be subclassed for maximum benefit.
*/
public abstract class AbstractEscherHolderRecord extends Record implements Cloneable {
public abstract class AbstractEscherHolderRecord extends Record {
private static boolean DESERIALISE;
static {
try {
@@ -42,17 +43,17 @@ public abstract class AbstractEscherHolderRecord extends Record implements Clone
}
}

private final List<EscherRecord> escherRecords;
private final List<EscherRecord> escherRecords = new ArrayList<>();
private final LazilyConcatenatedByteArray rawDataContainer = new LazilyConcatenatedByteArray();

public AbstractEscherHolderRecord()
{
escherRecords = new ArrayList<>();
public AbstractEscherHolderRecord() {}

public AbstractEscherHolderRecord(AbstractEscherHolderRecord other) {
other.escherRecords.stream().map(EscherRecord::copy).forEach(escherRecords::add);
rawDataContainer.concatenate(other.rawDataContainer);
}

public AbstractEscherHolderRecord(RecordInputStream in)
{
escherRecords = new ArrayList<>();
public AbstractEscherHolderRecord(RecordInputStream in) {
if (! DESERIALISE ) {
rawDataContainer.concatenate(in.readRemainder());
} else {
@@ -143,10 +144,16 @@ public abstract class AbstractEscherHolderRecord extends Record implements Clone
public abstract short getSid();

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public AbstractEscherHolderRecord clone() {
return (AbstractEscherHolderRecord)cloneViaReserialise();
return copy();
}

@Override
public abstract AbstractEscherHolderRecord copy();

public void addEscherRecord(int index, EscherRecord element)
{
escherRecords.add( index, element );
@@ -171,7 +178,7 @@ public abstract class AbstractEscherHolderRecord extends Record implements Clone
* If we have a EscherContainerRecord as one of our
* children (and most top level escher holders do),
* then return that.
*
*
* @return the EscherContainerRecord or {@code null} if no child is a container record
*/
public EscherContainerRecord getEscherContainer() {
@@ -187,15 +194,15 @@ public abstract class AbstractEscherHolderRecord extends Record implements Clone
* Descends into all our children, returning the
* first EscherRecord with the given id, or null
* if none found
*
*
* @param id the record to look for
*
*
* @return the record or {@code null} if it can't be found
*/
public EscherRecord findFirstWithId(short id) {
return findFirstWithId(id, getEscherRecords());
}
private EscherRecord findFirstWithId(short id, List<EscherRecord> records) {
// Check at our level
for (EscherRecord r : records) {
@@ -227,7 +234,7 @@ public abstract class AbstractEscherHolderRecord extends Record implements Clone
/**
* Big drawing group records are split but it's easier to deal with them
* as a whole group so we need to join them together.
*
*
* @param record the record data to concatenate to the end
*/
public void join( AbstractEscherHolderRecord record )

+ 21
- 11
src/java/org/apache/poi/hssf/record/ArrayRecord.java View File

@@ -17,18 +17,19 @@

package org.apache.poi.hssf.record;

import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.hssf.util.CellRangeAddress8Bit;
import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* ARRAY (0x0221)<p>
*
* Treated in a similar way to SharedFormulaRecord
*/
public final class ArrayRecord extends SharedValueRecordBase implements Cloneable {
public final class ArrayRecord extends SharedValueRecordBase {

public final static short sid = 0x0221;
private static final int OPT_ALWAYS_RECALCULATE = 0x0001;
@@ -38,6 +39,13 @@ public final class ArrayRecord extends SharedValueRecordBase implements Cloneabl
private int _field3notUsed;
private Formula _formula;

public ArrayRecord(ArrayRecord other) {
super(other);
_options = other._options;
_field3notUsed = other._field3notUsed;
_formula = (other._formula == null) ? null : other._formula.copy();
}

public ArrayRecord(RecordInputStream in) {
super(in);
_options = in.readUShort();
@@ -92,16 +100,18 @@ public final class ArrayRecord extends SharedValueRecordBase implements Cloneabl
}
sb.append("]");
return sb.toString();
}
@Override
public ArrayRecord clone() {
ArrayRecord rec = new ArrayRecord(_formula.copy(), getRange());
}

// they both seem unused, but clone them nevertheless to have an exact copy
rec._options = _options;
rec._field3notUsed = _field3notUsed;
@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public ArrayRecord clone() {
return copy();
}

return rec;
@Override
public ArrayRecord copy() {
return new ArrayRecord(this);
}
}

+ 20
- 13
src/java/org/apache/poi/hssf/record/AutoFilterInfoRecord.java View File

@@ -20,27 +20,28 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* The AutoFilterInfo record specifies the number of columns that have AutoFilter enabled
* and indicates the beginning of the collection of AutoFilter records.
*
* @author Yegor Kozlov
*/

public final class AutoFilterInfoRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x9D;
public final class AutoFilterInfoRecord extends StandardRecord {
public static final short sid = 0x9D;
/**
* Number of AutoFilter drop-down arrows on the sheet
*/
private short _cEntries; // = 0;
private short _cEntries;

public AutoFilterInfoRecord()
{
public AutoFilterInfoRecord() {}

public AutoFilterInfoRecord(AutoFilterInfoRecord other) {
super(other);
_cEntries = other._cEntries;
}

public AutoFilterInfoRecord(RecordInputStream in)
{
public AutoFilterInfoRecord(RecordInputStream in) {
_cEntries = in.readShort();
}

@@ -91,9 +92,15 @@ public final class AutoFilterInfoRecord extends StandardRecord implements Clonea
}

@Override
public AutoFilterInfoRecord clone()
{
return (AutoFilterInfoRecord)cloneViaReserialise();
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public AutoFilterInfoRecord clone() {
return copy();
}

@Override
public AutoFilterInfoRecord copy() {
return new AutoFilterInfoRecord(this);
}
}

+ 41
- 35
src/java/org/apache/poi/hssf/record/BOFRecord.java View File

@@ -19,44 +19,40 @@ package org.apache.poi.hssf.record;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Beginning Of File (0x0809)<P>
* Description: Somewhat of a misnomer, its used for the beginning of a set of
* records that have a particular purpose or subject.
* Used in sheets and workbooks.<P>
* REFERENCE: PG 289 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver
* @author Jason Height (jheight at chariot dot net dot au)
* Somewhat of a misnomer, its used for the beginning of a set of records that
* have a particular purpose or subject. Used in sheets and workbooks.
*/
public final class BOFRecord extends StandardRecord implements Cloneable {
public final class BOFRecord extends StandardRecord {
/**
* for BIFF8 files the BOF is 0x809. For earlier versions see
* {@link #biff2_sid} {@link #biff3_sid} {@link #biff4_sid}
* {@link #biff2_sid} {@link #biff3_sid} {@link #biff4_sid}
* {@link #biff5_sid}
*/
public final static short sid = 0x809;
public static final short sid = 0x809;
// SIDs from earlier BIFF versions
public final static short biff2_sid = 0x009;
public final static short biff3_sid = 0x209;
public final static short biff4_sid = 0x409;
public final static short biff5_sid = 0x809;
public static final short biff2_sid = 0x009;
public static final short biff3_sid = 0x209;
public static final short biff4_sid = 0x409;
public static final short biff5_sid = 0x809;

/** suggested default (0x0600 - BIFF8) */
public final static int VERSION = 0x0600;
public static final int VERSION = 0x0600;
/** suggested default 0x10d3 */
public final static int BUILD = 0x10d3;
public static final int BUILD = 0x10d3;
/** suggested default 0x07CC (1996) */
public final static int BUILD_YEAR = 0x07CC; // 1996
public static final int BUILD_YEAR = 0x07CC; // 1996
/** suggested default for a normal sheet (0x41) */
public final static int HISTORY_MASK = 0x41;
public static final int HISTORY_MASK = 0x41;

public final static int TYPE_WORKBOOK = 0x05;
public final static int TYPE_VB_MODULE = 0x06;
public final static int TYPE_WORKSHEET = 0x10;
public final static int TYPE_CHART = 0x20;
public final static int TYPE_EXCEL_4_MACRO = 0x40;
public final static int TYPE_WORKSPACE_FILE = 0x100;
public static final int TYPE_WORKBOOK = 0x05;
public static final int TYPE_VB_MODULE = 0x06;
public static final int TYPE_WORKSHEET = 0x10;
public static final int TYPE_CHART = 0x20;
public static final int TYPE_EXCEL_4_MACRO = 0x40;
public static final int TYPE_WORKSPACE_FILE = 0x100;

private int field_1_version;
private int field_2_type;
@@ -68,9 +64,18 @@ public final class BOFRecord extends StandardRecord implements Cloneable {
/**
* Constructs an empty BOFRecord with no fields set.
*/
public BOFRecord() {
public BOFRecord() {}

public BOFRecord(BOFRecord other) {
super(other);
field_1_version = other.field_1_version;
field_2_type = other.field_2_type;
field_3_build = other.field_3_build;
field_4_year = other.field_4_year;
field_5_history = other.field_5_history;
field_6_rversion = other.field_6_rversion;
}
private BOFRecord(int type) {
field_1_version = VERSION;
field_2_type = type;
@@ -79,7 +84,7 @@ public final class BOFRecord extends StandardRecord implements Cloneable {
field_5_history = 0x01;
field_6_rversion = VERSION;
}
public static BOFRecord createSheetBOF() {
return new BOFRecord(TYPE_WORKSHEET);
}
@@ -269,14 +274,15 @@ public final class BOFRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public BOFRecord clone() {
BOFRecord rec = new BOFRecord();
rec.field_1_version = field_1_version;
rec.field_2_type = field_2_type;
rec.field_3_build = field_3_build;
rec.field_4_year = field_4_year;
rec.field_5_history = field_5_history;
rec.field_6_rversion = field_6_rversion;
return rec;
return copy();
}

@Override
public BOFRecord copy() {
return new BOFRecord(this);
}
}

+ 18
- 15
src/java/org/apache/poi/hssf/record/BackupRecord.java View File

@@ -15,33 +15,31 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Backup Record <P>
* Description: Boolean specifying whether
* the GUI should store a backup of the file.<P>
* REFERENCE: PG 287 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* Boolean specifying whether the GUI should store a backup of the file.
*
* @version 2.0-pre
*/

public final class BackupRecord
extends StandardRecord
{
public final static short sid = 0x40;
private short field_1_backup; // = 0;
public final class BackupRecord extends StandardRecord {
public static final short sid = 0x40;

public BackupRecord()
{
private short field_1_backup;

public BackupRecord() {}

public BackupRecord(BackupRecord other) {
super(other);
field_1_backup = other.field_1_backup;
}

public BackupRecord(RecordInputStream in)
{
public BackupRecord(RecordInputStream in) {
field_1_backup = in.readShort();
}

@@ -90,4 +88,9 @@ public final class BackupRecord
{
return sid;
}

@Override
public BackupRecord copy() {
return new BackupRecord(this);
}
}

+ 27
- 19
src/java/org/apache/poi/hssf/record/BlankRecord.java View File

@@ -19,28 +19,32 @@ package org.apache.poi.hssf.record;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Blank cell record (0x0201) <P>
* Description: Represents a column in a row with no value but with styling.<P>
* REFERENCE: PG 287 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
* Represents a column in a row with no value but with styling.
*
* @version 2.0-pre
*/
public final class BlankRecord extends StandardRecord implements CellValueRecordInterface, Cloneable {
public final static short sid = 0x0201;
private int field_1_row;
private short field_2_col;
private short field_3_xf;
public final class BlankRecord extends StandardRecord implements CellValueRecordInterface {
public static final short sid = 0x0201;

private int field_1_row;
private short field_2_col;
private short field_3_xf;

/** Creates a new instance of BlankRecord */
public BlankRecord()
{
public BlankRecord() {}

public BlankRecord(BlankRecord other) {
super(other);
field_1_row = other.field_1_row;
field_2_col = other.field_2_col;
field_3_xf = other.field_3_xf;
}

public BlankRecord(RecordInputStream in)
{
public BlankRecord(RecordInputStream in) {
field_1_row = in.readUShort();
field_2_col = in.readShort();
field_3_xf = in.readShort();
@@ -138,11 +142,15 @@ public final class BlankRecord extends StandardRecord implements CellValueRecord
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public BlankRecord clone() {
BlankRecord rec = new BlankRecord();
rec.field_1_row = field_1_row;
rec.field_2_col = field_2_col;
rec.field_3_xf = field_3_xf;
return rec;
return copy();
}

@Override
public BlankRecord copy() {
return new BlankRecord(this);
}
}

+ 18
- 15
src/java/org/apache/poi/hssf/record/BookBoolRecord.java View File

@@ -15,33 +15,31 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Save External Links record (BookBool)<P>
* Description: Contains a flag specifying whether the Gui should save externally
* linked values from other workbooks. <P>
* REFERENCE: PG 289 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* Contains a flag specifying whether the Gui should save externally linked values from other workbooks.
*
* @version 2.0-pre
*/

public final class BookBoolRecord
extends StandardRecord
{
public final static short sid = 0xDA;
private short field_1_save_link_values;
public final class BookBoolRecord extends StandardRecord {
public static final short sid = 0xDA;

public BookBoolRecord()
{
private short field_1_save_link_values;

public BookBoolRecord() {}

public BookBoolRecord(BookBoolRecord other) {
super(other);
field_1_save_link_values = other.field_1_save_link_values;
}

public BookBoolRecord(RecordInputStream in)
{
public BookBoolRecord(RecordInputStream in) {
field_1_save_link_values = in.readShort();
}

@@ -90,4 +88,9 @@ public final class BookBoolRecord
{
return sid;
}

@Override
public BookBoolRecord copy() {
return new BookBoolRecord(this);
}
}

+ 21
- 14
src/java/org/apache/poi/hssf/record/BoolErrRecord.java View File

@@ -21,24 +21,27 @@ import org.apache.poi.ss.usermodel.FormulaError;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;

/**
* Creates new BoolErrRecord. (0x0205) <P>
* REFERENCE: PG ??? Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Michael P. Harhen
* @author Jason Height (jheight at chariot dot net dot au)
* Creates new BoolErrRecord. (0x0205)
*/
public final class BoolErrRecord extends CellRecord implements Cloneable {
public final static short sid = 0x0205;
public final class BoolErrRecord extends CellRecord {
public static final short sid = 0x0205;
private int _value;
/**
* If <code>true</code>, this record represents an error cell value, otherwise this record represents a boolean cell value
* If <code>true</code>, this record represents an error cell value,
* otherwise this record represents a boolean cell value
*/
private boolean _isError;

/** Creates new BoolErrRecord */
public BoolErrRecord() {
// fields uninitialised
public BoolErrRecord() {}

public BoolErrRecord(BoolErrRecord other) {
super(other);
_value = other._value;
_isError = other._isError;
}

/**
@@ -183,11 +186,15 @@ public final class BoolErrRecord extends CellRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public BoolErrRecord clone() {
BoolErrRecord rec = new BoolErrRecord();
copyBaseFields(rec);
rec._value = _value;
rec._isError = _isError;
return rec;
return copy();
}

@Override
public BoolErrRecord copy() {
return new BoolErrRecord(this);
}
}

+ 17
- 10
src/java/org/apache/poi/hssf/record/BottomMarginRecord.java View File

@@ -20,22 +20,24 @@ package org.apache.poi.hssf.record;


import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;


/**
* Record for the bottom margin.
*/
public final class BottomMarginRecord extends StandardRecord implements Margin, Cloneable {
public final static short sid = 0x29;
public final class BottomMarginRecord extends StandardRecord implements Margin {
public static final short sid = 0x29;
private double field_1_margin;

public BottomMarginRecord()
{
public BottomMarginRecord() {}

public BottomMarginRecord(BottomMarginRecord other) {
super(other);
field_1_margin = other.field_1_margin;
}

public BottomMarginRecord( RecordInputStream in )
{
public BottomMarginRecord( RecordInputStream in ) {
field_1_margin = in.readDouble();
}

@@ -79,10 +81,15 @@ public final class BottomMarginRecord extends StandardRecord implements Margin,
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public BottomMarginRecord clone() {
BottomMarginRecord rec = new BottomMarginRecord();
rec.field_1_margin = this.field_1_margin;
return rec;
return copy();
}

} // END OF
@Override
public BottomMarginRecord copy() {
return new BottomMarginRecord(this);
}
}

+ 29
- 23
src/java/org/apache/poi/hssf/record/BoundSheetRecord.java View File

@@ -18,9 +18,9 @@
package org.apache.poi.hssf.record;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
@@ -28,20 +28,16 @@ import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil;
import org.apache.poi.ss.util.WorkbookUtil;

/**
* Title: Bound Sheet Record (aka BundleSheet) (0x0085)<P>
* Description: Defines a sheet within a workbook. Basically stores the sheet name
* and tells where the Beginning of file record is within the HSSF
* file. <P>
* REFERENCE: PG 291 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Defines a sheet within a workbook. Basically stores the sheet name and
* tells where the Beginning of file record is within the HSSF file.
*/
public final class BoundSheetRecord extends StandardRecord {
public final static short sid = 0x0085;

public static final short sid = 0x0085;
private static final BitField hiddenFlag = BitFieldFactory.getInstance(0x01);
private static final BitField veryHiddenFlag = BitFieldFactory.getInstance(0x02);

private int field_1_position_of_BOF;
private int field_2_option_flags;
private int field_4_isMultibyteUnicode;
@@ -52,13 +48,21 @@ public final class BoundSheetRecord extends StandardRecord {
setSheetname(sheetname);
}

public BoundSheetRecord(BoundSheetRecord other) {
super(other);
field_1_position_of_BOF = other.field_1_position_of_BOF;
field_2_option_flags = other.field_2_option_flags;
field_4_isMultibyteUnicode = other.field_4_isMultibyteUnicode;
field_5_sheetname = other.field_5_sheetname;
}

/**
* UTF8: sid + len + bof + flags + len(str) + unicode + str 2 + 2 + 4 + 2 +
* 1 + 1 + len(str)
*
* UNICODE: sid + len + bof + flags + len(str) + unicode + str 2 + 2 + 4 + 2 +
* 1 + 1 + 2 * len(str)
*
*
* @param in the record stream to read from
*/
public BoundSheetRecord(RecordInputStream in) {
@@ -158,7 +162,7 @@ public final class BoundSheetRecord extends StandardRecord {

/**
* Is the sheet hidden? Different from very hidden
*
*
* @return {@code true} if hidden
*/
public boolean isHidden() {
@@ -167,7 +171,7 @@ public final class BoundSheetRecord extends StandardRecord {

/**
* Is the sheet hidden? Different from very hidden
*
*
* @param hidden {@code true} if hidden
*/
public void setHidden(boolean hidden) {
@@ -176,7 +180,7 @@ public final class BoundSheetRecord extends StandardRecord {

/**
* Is the sheet very hidden? Different from (normal) hidden
*
*
* @return {@code true} if very hidden
*/
public boolean isVeryHidden() {
@@ -185,7 +189,7 @@ public final class BoundSheetRecord extends StandardRecord {

/**
* Is the sheet very hidden? Different from (normal) hidden
*
*
* @param veryHidden {@code true} if very hidden
*/
public void setVeryHidden(boolean veryHidden) {
@@ -195,22 +199,24 @@ public final class BoundSheetRecord extends StandardRecord {
/**
* Converts a List of {@link BoundSheetRecord}s to an array and sorts by the position of their
* BOFs.
*
*
* @param boundSheetRecords the boundSheetRecord list to arrayify
*
*
* @return the sorted boundSheetRecords
*/
public static BoundSheetRecord[] orderByBofPosition(List<BoundSheetRecord> boundSheetRecords) {
BoundSheetRecord[] bsrs = new BoundSheetRecord[boundSheetRecords.size()];
boundSheetRecords.toArray(bsrs);
Arrays.sort(bsrs, BOFComparator);
Arrays.sort(bsrs, BoundSheetRecord::compareRecords);
return bsrs;
}
private static final Comparator<BoundSheetRecord> BOFComparator = new Comparator<BoundSheetRecord>() {

public int compare(BoundSheetRecord bsr1, BoundSheetRecord bsr2) {
return bsr1.getPositionOfBof() - bsr2.getPositionOfBof();
}
};
private static int compareRecords(BoundSheetRecord bsr1, BoundSheetRecord bsr2) {
return bsr1.getPositionOfBof() - bsr2.getPositionOfBof();
}

@Override
public BoundSheetRecord copy() {
return new BoundSheetRecord(this);
}
}

+ 18
- 7
src/java/org/apache/poi/hssf/record/CFHeader12Record.java View File

@@ -21,22 +21,28 @@ import org.apache.poi.hssf.record.common.FtrHeader;
import org.apache.poi.hssf.record.common.FutureRecord;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Conditional Formatting Header v12 record CFHEADER12 (0x0879),
* for conditional formattings introduced in Excel 2007 and newer.
*/
public final class CFHeader12Record extends CFHeaderBase implements FutureRecord, Cloneable {
public final class CFHeader12Record extends CFHeaderBase implements FutureRecord {
public static final short sid = 0x0879;

private FtrHeader futureHeader;

/** Creates new CFHeaderRecord */
public CFHeader12Record() {
createEmpty();
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
}

public CFHeader12Record(CFHeader12Record other) {
super(other);
futureHeader = other.futureHeader.copy();
}

public CFHeader12Record(CellRangeAddress[] regions, int nRules) {
super(regions, nRules);
futureHeader = new FtrHeader();
@@ -78,12 +84,17 @@ public final class CFHeader12Record extends CFHeaderBase implements FutureRecord
public CellRangeAddress getAssociatedRange() {
return futureHeader.getAssociatedRange();
}
@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public CFHeader12Record clone() {
CFHeader12Record result = new CFHeader12Record();
result.futureHeader = (FtrHeader)futureHeader.clone();
super.copyTo(result);
return result;
return copy();
}

@Override
public CFHeader12Record copy() {
return new CFHeader12Record(this);
}
}

+ 18
- 11
src/java/org/apache/poi/hssf/record/CFHeaderBase.java View File

@@ -21,20 +21,28 @@ import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.ss.util.CellRangeUtil;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Parent of Conditional Formatting Header records,
* {@link CFHeaderRecord} and {@link CFHeader12Record}.
*/
public abstract class CFHeaderBase extends StandardRecord implements Cloneable {
public abstract class CFHeaderBase extends StandardRecord {
private int field_1_numcf;
private int field_2_need_recalculation_and_id;
private CellRangeAddress field_3_enclosing_cell_range;
private CellRangeAddressList field_4_cell_ranges;

/** Creates new CFHeaderBase */
protected CFHeaderBase() {
protected CFHeaderBase() {}

protected CFHeaderBase(CFHeaderBase other) {
super(other);
field_1_numcf = other.field_1_numcf;
field_2_need_recalculation_and_id = other.field_2_need_recalculation_and_id;
field_3_enclosing_cell_range = other.field_3_enclosing_cell_range.copy();
field_4_cell_ranges = other.field_4_cell_ranges.copy();
}

protected CFHeaderBase(CellRangeAddress[] regions, int nRules) {
CellRangeAddress[] mergeCellRanges = CellRangeUtil.mergeCellRanges(regions);
setCellRanges(mergeCellRanges);
@@ -97,7 +105,7 @@ public abstract class CFHeaderBase extends StandardRecord implements Cloneable {
}

/**
* Set cell ranges list to a single cell range and
* Set cell ranges list to a single cell range and
* modify the enclosing cell range accordingly.
* @param cellRanges - list of CellRange objects
*/
@@ -151,13 +159,12 @@ public abstract class CFHeaderBase extends StandardRecord implements Cloneable {
field_4_cell_ranges.serialize(out);
}

protected void copyTo(CFHeaderBase result) {
result.field_1_numcf = field_1_numcf;
result.field_2_need_recalculation_and_id = field_2_need_recalculation_and_id;
result.field_3_enclosing_cell_range = field_3_enclosing_cell_range.copy();
result.field_4_cell_ranges = field_4_cell_ranges.copy();
}
@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public abstract CFHeaderBase clone();

@Override
public abstract CFHeaderBase clone(); // NOSONAR
public abstract CFHeaderBase copy();
}

+ 16
- 5
src/java/org/apache/poi/hssf/record/CFHeaderRecord.java View File

@@ -18,19 +18,24 @@
package org.apache.poi.hssf.record;

import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Removal;

/**
* Conditional Formatting Header record CFHEADER (0x01B0).
* Used to describe a {@link CFRuleRecord}.
* @see CFHeader12Record
*/
public final class CFHeaderRecord extends CFHeaderBase implements Cloneable {
public final class CFHeaderRecord extends CFHeaderBase {
public static final short sid = 0x01B0;

/** Creates new CFHeaderRecord */
public CFHeaderRecord() {
createEmpty();
}

public CFHeaderRecord(CFHeaderRecord other) {
super(other);
}

public CFHeaderRecord(CellRangeAddress[] regions, int nRules) {
super(regions, nRules);
}
@@ -48,9 +53,15 @@ public final class CFHeaderRecord extends CFHeaderBase implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public CFHeaderRecord clone() {
CFHeaderRecord result = new CFHeaderRecord();
super.copyTo(result);
return result;
return copy();
}

@Override
public CFHeaderRecord copy() {
return new CFHeaderRecord(this);
}
}

+ 84
- 86
src/java/org/apache/poi/hssf/record/CFRule12Record.java View File

@@ -39,18 +39,19 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Removal;

/**
* Conditional Formatting v12 Rule Record (0x087A).
*
* Conditional Formatting v12 Rule Record (0x087A).
*
* <p>This is for newer-style Excel conditional formattings,
* from Excel 2007 onwards.
*
*
* <p>{@link CFRuleRecord} is used where the condition type is
* {@link #CONDITION_TYPE_CELL_VALUE_IS} or {@link #CONDITION_TYPE_FORMULA},
* this is only used for the other types
*/
public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cloneable {
public final class CFRule12Record extends CFRuleBase implements FutureRecord {

//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
@@ -66,14 +67,35 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
private int template_type;
private byte template_param_length;
private byte[] template_params;
private DataBarFormatting data_bar;
private IconMultiStateFormatting multistate;
private ColorGradientFormatting color_gradient;
// TODO Parse this, see #58150
private byte[] filter_data;

/** Creates new CFRuleRecord */
public CFRule12Record(CFRule12Record other) {
super(other);
futureHeader = (other.futureHeader == null) ? null : other.futureHeader.copy();

// use min() to gracefully handle cases where the length-property and the array-length do not match
// we saw some such files in circulation
ext_formatting_length = Math.min(other.ext_formatting_length, other.ext_formatting_data.length);
ext_formatting_data = other.ext_formatting_data.clone();

formula_scale = other.formula_scale.copy();

ext_opts = other.ext_opts;
priority = other.priority;
template_type = other.template_type;
template_param_length = other.template_param_length;
template_params = (other.template_params == null) ? null : other.template_params.clone();
color_gradient = (other.color_gradient == null) ? null : other.color_gradient.copy();
multistate = (other.multistate == null) ? null : other.multistate.copy();
data_bar = (other.data_bar == null) ? null : other.data_bar.copy();
filter_data = (other.filter_data == null) ? null : other.filter_data.clone();
}

private CFRule12Record(byte conditionType, byte comparisonOperation) {
super(conditionType, comparisonOperation);
setDefaults();
@@ -84,15 +106,17 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
setDefaults();
this.formula_scale = Formula.create(formulaScale);
}


private void setDefaults() {
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
ext_formatting_length = 0;
ext_formatting_data = new byte[4];
formula_scale = Formula.create(Ptg.EMPTY_PTG_ARRAY);
ext_opts = 0;
priority = 0;
template_type = getConditionType();
@@ -102,10 +126,10 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl

/**
* Creates a new comparison operation rule
*
*
* @param sheet the sheet
* @param formulaText the first formula text
*
*
* @return a new comparison operation rule
*/
public static CFRule12Record create(HSSFSheet sheet, String formulaText) {
@@ -113,34 +137,34 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
return new CFRule12Record(CONDITION_TYPE_FORMULA, ComparisonOperator.NO_COMPARISON,
formula1, null, null);
}
/**
* Creates a new comparison operation rule
*
*
* @param sheet the sheet
* @param comparisonOperation the comparison operation
* @param formulaText1 the first formula text
* @param formulaText2 the second formula text
*
*
* @return a new comparison operation rule
*/
public static CFRule12Record create(HSSFSheet sheet, byte comparisonOperation,
String formulaText1, String formulaText2) {
Ptg[] formula1 = parseFormula(formulaText1, sheet);
Ptg[] formula2 = parseFormula(formulaText2, sheet);
return new CFRule12Record(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation,
return new CFRule12Record(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation,
formula1, formula2, null);
}
/**
* Creates a new comparison operation rule
*
*
* @param sheet the sheet
* @param comparisonOperation the comparison operation
* @param formulaText1 the first formula text
* @param formulaText2 the second formula text
* @param formulaTextScale the scale to apply for the comparison
*
*
* @return a new comparison operation rule
*/
public static CFRule12Record create(HSSFSheet sheet, byte comparisonOperation,
@@ -148,43 +172,43 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
Ptg[] formula1 = parseFormula(formulaText1, sheet);
Ptg[] formula2 = parseFormula(formulaText2, sheet);
Ptg[] formula3 = parseFormula(formulaTextScale, sheet);
return new CFRule12Record(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation,
return new CFRule12Record(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation,
formula1, formula2, formula3);
}
/**
* Creates a new Data Bar formatting
*
*
* @param sheet the sheet
* @param color the data bar color
*
*
* @return a new Data Bar formatting
*/
public static CFRule12Record create(HSSFSheet sheet, ExtendedColor color) {
CFRule12Record r = new CFRule12Record(CONDITION_TYPE_DATA_BAR,
CFRule12Record r = new CFRule12Record(CONDITION_TYPE_DATA_BAR,
ComparisonOperator.NO_COMPARISON);
DataBarFormatting dbf = r.createDataBarFormatting();
dbf.setColor(color);
dbf.setPercentMin((byte)0);
dbf.setPercentMax((byte)100);
DataBarThreshold min = new DataBarThreshold();
min.setType(RangeType.MIN.id);
dbf.setThresholdMin(min);
DataBarThreshold max = new DataBarThreshold();
max.setType(RangeType.MAX.id);
dbf.setThresholdMax(max);
return r;
}
/**
* Creates a new Icon Set / Multi-State formatting
*
*
* @param sheet the sheet
* @param iconSet the icon set
*
*
* @return a new Icon Set / Multi-State formatting
*/
public static CFRule12Record create(HSSFSheet sheet, IconSet iconSet) {
@@ -192,20 +216,20 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
for (int i=0; i<ts.length; i++) {
ts[i] = new IconMultiStateThreshold();
}
CFRule12Record r = new CFRule12Record(CONDITION_TYPE_ICON_SET,
CFRule12Record r = new CFRule12Record(CONDITION_TYPE_ICON_SET,
ComparisonOperator.NO_COMPARISON);
IconMultiStateFormatting imf = r.createMultiStateFormatting();
imf.setIconSet(iconSet);
imf.setThresholds(ts);
return r;
}
/**
* Creates a new Color Scale / Color Gradient formatting
*
*
* @param sheet the sheet
*
*
* @return a new Color Scale / Color Gradient formatting
*/
public static CFRule12Record createColorScale(HSSFSheet sheet) {
@@ -216,8 +240,8 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
ts[i] = new ColorGradientThreshold();
colors[i] = new ExtendedColor();
}
CFRule12Record r = new CFRule12Record(CONDITION_TYPE_COLOR_SCALE,
CFRule12Record r = new CFRule12Record(CONDITION_TYPE_COLOR_SCALE,
ComparisonOperator.NO_COMPARISON);
ColorGradientFormatting cgf = r.createColorGradientFormatting();
cgf.setNumControlPoints(numPoints);
@@ -232,7 +256,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
setComparisonOperation(in.readByte());
int field_3_formula1_len = in.readUShort();
int field_4_formula2_len = in.readUShort();
ext_formatting_length = in.readInt();
ext_formatting_data = new byte[0];
if (ext_formatting_length == 0) {
@@ -245,13 +269,13 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
in.readFully(ext_formatting_data);
}
}
setFormula1(Formula.read(field_3_formula1_len, in));
setFormula2(Formula.read(field_4_formula2_len, in));
int formula_scale_len = in.readUShort();
formula_scale = Formula.read(formula_scale_len, in);
ext_opts = in.readByte();
priority = in.readUShort();
template_type = in.readUShort();
@@ -263,7 +287,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
logger.log(POILogger.WARN, "CF Rule v12 template params length should be 0 or 16, found " + template_param_length);
in.readRemainder();
}
byte type = getConditionType();
if (type == CONDITION_TYPE_COLOR_SCALE) {
color_gradient = new ColorGradientFormatting(in);
@@ -275,7 +299,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
multistate = new IconMultiStateFormatting(in);
}
}
public boolean containsDataBarBlock() {
return (data_bar != null);
}
@@ -284,7 +308,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
}
public DataBarFormatting createDataBarFormatting() {
if (data_bar != null) return data_bar;
// Convert, setup and return
setConditionType(CONDITION_TYPE_DATA_BAR);
data_bar = new DataBarFormatting();
@@ -299,7 +323,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
}
public IconMultiStateFormatting createMultiStateFormatting() {
if (multistate != null) return multistate;
// Convert, setup and return
setConditionType(CONDITION_TYPE_ICON_SET);
multistate = new IconMultiStateFormatting();
@@ -314,7 +338,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
}
public ColorGradientFormatting createColorGradientFormatting() {
if (color_gradient != null) return color_gradient;
// Convert, setup and return
setConditionType(CONDITION_TYPE_COLOR_SCALE);
color_gradient = new ColorGradientFormatting();
@@ -356,7 +380,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
*/
public void serialize(LittleEndianOutput out) {
futureHeader.serialize(out);
int formula1Len=getFormulaSize(getFormula1());
int formula2Len=getFormulaSize(getFormula2());

@@ -364,7 +388,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
out.writeByte(getComparisonOperation());
out.writeShort(formula1Len);
out.writeShort(formula2Len);
// TODO Update ext_formatting_length
if (ext_formatting_length == 0) {
out.writeInt(0);
@@ -374,18 +398,18 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
serializeFormattingBlock(out);
out.write(ext_formatting_data);
}
getFormula1().serializeTokens(out);
getFormula2().serializeTokens(out);
out.writeShort(getFormulaSize(formula_scale));
formula_scale.serializeTokens(out);
out.writeByte(ext_opts);
out.writeShort(priority);
out.writeShort(template_type);
out.writeByte(template_param_length);
out.write(template_params);
byte type = getConditionType();
if (type == CONDITION_TYPE_COLOR_SCALE) {
color_gradient.serialize(out);
@@ -409,7 +433,7 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
len += getFormulaSize(getFormula2());
len += 2 + getFormulaSize(formula_scale);
len += 6 + template_params.length;
byte type = getConditionType();
if (type == CONDITION_TYPE_COLOR_SCALE) {
len += color_gradient.getDataLength();
@@ -461,44 +485,18 @@ public final class CFRule12Record extends CFRuleBase implements FutureRecord, Cl
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public CFRule12Record clone() {
CFRule12Record rec = new CFRule12Record(getConditionType(), getComparisonOperation());
rec.futureHeader.setAssociatedRange(futureHeader.getAssociatedRange().copy());
super.copyTo(rec);

// use min() to gracefully handle cases where the length-property and the array-length do not match
// we saw some such files in circulation
rec.ext_formatting_length = Math.min(ext_formatting_length, ext_formatting_data.length);
rec.ext_formatting_data = IOUtils.safelyAllocate(ext_formatting_length, MAX_RECORD_LENGTH);
System.arraycopy(ext_formatting_data, 0, rec.ext_formatting_data, 0, rec.ext_formatting_length);
rec.formula_scale = formula_scale.copy();
rec.ext_opts = ext_opts;
rec.priority = priority;
rec.template_type = template_type;
rec.template_param_length = template_param_length;
rec.template_params = IOUtils.safelyAllocate(template_param_length, MAX_RECORD_LENGTH);
System.arraycopy(template_params, 0, rec.template_params, 0, template_param_length);
return copy();
}

if (color_gradient != null) {
rec.color_gradient = (ColorGradientFormatting)color_gradient.clone();
}
if (multistate != null) {
rec.multistate = (IconMultiStateFormatting)multistate.clone();
}
if (data_bar != null) {
rec.data_bar = (DataBarFormatting)data_bar.clone();
}
if (filter_data != null) {
rec.filter_data = IOUtils.safelyAllocate(filter_data.length, MAX_RECORD_LENGTH);
System.arraycopy(filter_data, 0, rec.filter_data, 0, filter_data.length);
}
return rec;
@Override
public CFRule12Record copy() {
return new CFRule12Record(this);
}

public short getFutureRecordType() {
return futureHeader.getRecordType();
}

+ 56
- 53
src/java/org/apache/poi/hssf/record/CFRuleBase.java View File

@@ -30,32 +30,31 @@ import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Removal;

/**
* Conditional Formatting Rules. This can hold old-style rules
*
*
*
*
* <p>This is for the older-style Excel conditional formattings,
* new-style (Excel 2007+) also make use of {@link CFRule12Record}
* for their rules.</p>
*/
public abstract class CFRuleBase extends StandardRecord implements Cloneable {
public abstract class CFRuleBase extends StandardRecord {
// FIXME: Merge with org.apache.poi.ss.usermodel.ComparisonOperator and rewrite as an enum
public static final class ComparisonOperator {
public static final byte NO_COMPARISON = 0;
public static final byte BETWEEN = 1;
public static final byte NOT_BETWEEN = 2;
public static final byte EQUAL = 3;
public static final byte NOT_EQUAL = 4;
public static final byte GT = 5;
public static final byte LT = 6;
public static final byte GE = 7;
public static final byte LE = 8;
private static final byte max_operator = 8;
public interface ComparisonOperator {
byte NO_COMPARISON = 0;
byte BETWEEN = 1;
byte NOT_BETWEEN = 2;
byte EQUAL = 3;
byte NOT_EQUAL = 4;
byte GT = 5;
byte LT = 6;
byte GE = 7;
byte LE = 8;
byte max_operator = 8;
}
protected static final POILogger logger = POILogFactory.getLogger(CFRuleBase.class);

private byte condition_type;
// The only kinds that CFRuleRecord handles
public static final byte CONDITION_TYPE_CELL_VALUE_IS = 1;
public static final byte CONDITION_TYPE_FORMULA = 2;
@@ -65,8 +64,6 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
public static final byte CONDITION_TYPE_FILTER = 5;
public static final byte CONDITION_TYPE_ICON_SET = 6;

private byte comparison_operator;

public static final int TEMPLATE_CELL_VALUE = 0x0000;
public static final int TEMPLATE_FORMULA = 0x0001;
public static final int TEMPLATE_COLOR_SCALE_FORMATTING = 0x0002;
@@ -94,7 +91,9 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
public static final int TEMPLATE_DUPLICATE_VALUES = 0x001B;
public static final int TEMPLATE_ABOVE_OR_EQUAL_TO_AVERAGE = 0x001D;
public static final int TEMPLATE_BELOW_OR_EQUAL_TO_AVERAGE = 0x001E;

protected static final POILogger logger = POILogFactory.getLogger(CFRuleBase.class);

static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
static final BitField alignHor = bf(0x00000001); // 0 = Horizontal alignment modified
static final BitField alignVer = bf(0x00000002); // 0 = Vertical alignment modified
@@ -129,19 +128,24 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
return BitFieldFactory.getInstance(i);
}


private byte condition_type;
private byte comparison_operator;

protected int formatting_options;
protected short formatting_not_used; // TODO Decode this properly
// TODO Decode this properly
protected short formatting_not_used;

protected FontFormatting _fontFormatting;
protected BorderFormatting _borderFormatting;
protected PatternFormatting _patternFormatting;
private Formula formula1;
private Formula formula2;

/**
* Creates new CFRuleRecord
*
*
* @param conditionType the condition type
* @param comparisonOperation the comparison operation
*/
@@ -151,19 +155,34 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
formula1 = Formula.create(Ptg.EMPTY_PTG_ARRAY);
formula2 = Formula.create(Ptg.EMPTY_PTG_ARRAY);
}

protected CFRuleBase(byte conditionType, byte comparisonOperation, Ptg[] formula1, Ptg[] formula2) {
this(conditionType, comparisonOperation);
this.formula1 = Formula.create(formula1);
this.formula2 = Formula.create(formula2);
}

protected CFRuleBase() {}

protected CFRuleBase(CFRuleBase other) {
super(other);
setConditionType(other.getConditionType());
setComparisonOperation(other.getComparisonOperation());
formatting_options = other.formatting_options;
formatting_not_used = other.formatting_not_used;
_fontFormatting = (!other.containsFontFormattingBlock()) ? null : other.getFontFormatting().copy();
_borderFormatting = (!other.containsBorderFormattingBlock()) ? null : other.getBorderFormatting().copy();
_patternFormatting = (!other.containsPatternFormattingBlock()) ? null : other.getPatternFormatting().copy();
formula1 = other.getFormula1().copy();
formula2 = other.getFormula2().copy();
}

protected int readFormatOptions(RecordInputStream in) {
formatting_options = in.readInt();
formatting_not_used = in.readShort();

int len = 6;
if (containsFontFormattingBlock()) {
_fontFormatting = new FontFormatting(in);
len += _fontFormatting.getDataLength();
@@ -178,7 +197,7 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
_patternFormatting = new PatternFormatting(in);
len += _patternFormatting.getDataLength();
}
return len;
}

@@ -187,10 +206,8 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
}
protected void setConditionType(byte condition_type) {
if ((this instanceof CFRuleRecord)) {
if (condition_type == CONDITION_TYPE_CELL_VALUE_IS ||
condition_type == CONDITION_TYPE_FORMULA) {
// Good, valid combination
} else {
if (!(condition_type == CONDITION_TYPE_CELL_VALUE_IS ||
condition_type == CONDITION_TYPE_FORMULA)) {
throw new IllegalArgumentException("CFRuleRecord only accepts Value-Is and Formula types");
}
}
@@ -201,7 +218,7 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
if (operation < 0 || operation > ComparisonOperator.max_operator)
throw new IllegalArgumentException(
"Valid operators are only in the range 0 to " +ComparisonOperator.max_operator);
this.comparison_operator = operation;
}
public byte getComparisonOperation() {
@@ -351,7 +368,7 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
private void setOptionFlag(boolean flag, BitField field) {
formatting_options = field.setBoolean(formatting_options, flag);
}
protected int getFormattingBlockSize() {
return 6 +
(containsFontFormattingBlock()?_fontFormatting.getRawRecord().length:0)+
@@ -375,7 +392,7 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
_patternFormatting.serialize(out);
}
}
/**
* get the stack of the 1st expression as a list
*
@@ -440,27 +457,13 @@ public abstract class CFRuleBase extends StandardRecord implements Cloneable {
int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet);
return HSSFFormulaParser.parse(formula, sheet.getWorkbook(), FormulaType.CELL, sheetIndex);
}
protected void copyTo(CFRuleBase rec) {
rec.condition_type = condition_type;
rec.comparison_operator = comparison_operator;
rec.formatting_options = formatting_options;
rec.formatting_not_used = formatting_not_used;
if (containsFontFormattingBlock()) {
rec._fontFormatting = _fontFormatting.clone();
}
if (containsBorderFormattingBlock()) {
rec._borderFormatting = _borderFormatting.clone();
}
if (containsPatternFormattingBlock()) {
rec._patternFormatting = (PatternFormatting) _patternFormatting.clone();
}
rec.setFormula1(getFormula1().copy());
rec.setFormula2(getFormula2().copy());
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public abstract CFRuleBase clone();

@Override
public abstract CFRuleBase copy();
}

+ 22
- 12
src/java/org/apache/poi/hssf/record/CFRuleRecord.java View File

@@ -23,18 +23,22 @@ import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Conditional Formatting Rule Record (0x01B1).
*
* Conditional Formatting Rule Record (0x01B1).
*
* <p>This is for the older-style Excel conditional formattings,
* new-style (Excel 2007+) also make use of {@link CFRule12Record}
* for their rules.</p>
*/
public final class CFRuleRecord extends CFRuleBase implements Cloneable {
public final class CFRuleRecord extends CFRuleBase {
public static final short sid = 0x01B1;

/** Creates new CFRuleRecord */
public CFRuleRecord(CFRuleRecord other) {
super(other);
}

private CFRuleRecord(byte conditionType, byte comparisonOperation) {
super(conditionType, comparisonOperation);
setDefaults();
@@ -59,10 +63,10 @@ public final class CFRuleRecord extends CFRuleBase implements Cloneable {

/**
* Creates a new comparison operation rule
*
*
* @param sheet the sheet
* @param formulaText the formula text
*
*
* @return a new comparison operation rule
*/
public static CFRuleRecord create(HSSFSheet sheet, String formulaText) {
@@ -72,12 +76,12 @@ public final class CFRuleRecord extends CFRuleBase implements Cloneable {
}
/**
* Creates a new comparison operation rule
*
*
* @param sheet the sheet
* @param comparisonOperation the comparison operation
* @param formulaText1 the first formula text
* @param formulaText2 the second formula text
*
*
* @return a new comparison operation rule
*/
public static CFRuleRecord create(HSSFSheet sheet, byte comparisonOperation,
@@ -120,7 +124,7 @@ public final class CFRuleRecord extends CFRuleBase implements Cloneable {
out.writeByte(getComparisonOperation());
out.writeShort(formula1Len);
out.writeShort(formula2Len);
serializeFormattingBlock(out);

getFormula1().serializeTokens(out);
@@ -156,9 +160,15 @@ public final class CFRuleRecord extends CFRuleBase implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public CFRuleRecord clone() {
CFRuleRecord rec = new CFRuleRecord(getConditionType(), getComparisonOperation());
super.copyTo(rec);
return rec;
return copy();
}

@Override
public CFRuleRecord copy() {
return new CFRuleRecord(this);
}
}

+ 18
- 14
src/java/org/apache/poi/hssf/record/CRNCountRecord.java View File

@@ -19,30 +19,26 @@ package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
/**
* XCT - CRN Count <P>
*
* REFERENCE: 5.114<P>
*
* @author Josh Micich
* XCT - CRN Count
*/
public final class CRNCountRecord extends StandardRecord {
public final static short sid = 0x59;
public static final short sid = 0x59;

private static final short DATA_SIZE = 4;

private int field_1_number_crn_records;
private int field_2_sheet_table_index;

private int field_1_number_crn_records;
private int field_2_sheet_table_index;

public CRNCountRecord() {
throw new RuntimeException("incomplete code");
private CRNCountRecord() {
// incomplete code
}

public int getNumberOfCRNs() {
return field_1_number_crn_records;
public CRNCountRecord(CRNCountRecord other) {
super(other);
field_1_number_crn_records = other.field_1_number_crn_records;
field_2_sheet_table_index = other.field_2_sheet_table_index;
}


public CRNCountRecord(RecordInputStream in) {
field_1_number_crn_records = in.readShort();
if(field_1_number_crn_records < 0) {
@@ -53,6 +49,9 @@ public final class CRNCountRecord extends StandardRecord {
field_2_sheet_table_index = in.readShort();
}

public int getNumberOfCRNs() {
return field_1_number_crn_records;
}

public String toString() {
StringBuilder sb = new StringBuilder();
@@ -77,4 +76,9 @@ public final class CRNCountRecord extends StandardRecord {
public short getSid() {
return sid;
}

@Override
public CRNCountRecord copy() {
return new CRNCountRecord(this);
}
}

+ 23
- 12
src/java/org/apache/poi/hssf/record/CRNRecord.java View File

@@ -21,27 +21,30 @@ import org.apache.poi.ss.formula.constant.ConstantValueParser;
import org.apache.poi.util.LittleEndianOutput;

/**
* Title: CRN(0x005A)<p>
* Description: This record stores the contents of an external cell or cell range<p>
* REFERENCE: OOO 5.23
* This record stores the contents of an external cell or cell range
*/
public final class CRNRecord extends StandardRecord {
public final static short sid = 0x005A;
public static final short sid = 0x005A;

private int field_1_last_column_index;
private int field_2_first_column_index;
private int field_3_row_index;
private int field_1_last_column_index;
private int field_2_first_column_index;
private int field_3_row_index;
private Object[] field_4_constant_values;

public CRNRecord() {
throw new RuntimeException("incomplete code");
private CRNRecord() {
// incomplete code
}

public int getNumberOfCRNs() {
return field_1_last_column_index;
public CRNRecord(CRNRecord other) {
super(other);
field_1_last_column_index = other.field_1_last_column_index;
field_2_first_column_index = other.field_2_first_column_index;
field_3_row_index = other.field_3_row_index;
// field_4_constant_values are instances of Double, Boolean, String, ErrorCode,
// i.e. they are immutable and can their references can be simply cloned
field_4_constant_values = (other.field_4_constant_values == null) ? null : other.field_4_constant_values.clone();
}


public CRNRecord(RecordInputStream in) {
field_1_last_column_index = in.readUByte();
field_2_first_column_index = in.readUByte();
@@ -50,6 +53,9 @@ public final class CRNRecord extends StandardRecord {
field_4_constant_values = ConstantValueParser.parse(in, nValues);
}

public int getNumberOfCRNs() {
return field_1_last_column_index;
}

public String toString() {
StringBuilder sb = new StringBuilder();
@@ -77,4 +83,9 @@ public final class CRNRecord extends StandardRecord {
public short getSid() {
return sid;
}

@Override
public CRNRecord copy() {
return new CRNRecord(this);
}
}

+ 28
- 19
src/java/org/apache/poi/hssf/record/CalcCountRecord.java View File

@@ -15,34 +15,37 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Calc Count Record
* Description: Specifies the maximum times the gui should perform a formula
* recalculation. For instance: in the case a formula includes
* cells that are themselves a result of a formula and a value
* changes. This is essentially a failsafe against an infinate
* loop in the event the formulas are not independant. <P>
* REFERENCE: PG 292 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* Specifies the maximum times the gui should perform a formula recalculation.
* For instance: in the case a formula includes cells that are themselves a result of a formula and
* a value changes. This is essentially a failsafe against an infinite loop in the event the formulas
* are not independent.
*
* @version 2.0-pre
* @see org.apache.poi.hssf.record.CalcModeRecord
* @see CalcModeRecord
*/

public final class CalcCountRecord extends StandardRecord implements Cloneable {
public final static short sid = 0xC;
private short field_1_iterations;
public final class CalcCountRecord extends StandardRecord {
public static final short sid = 0xC;

public CalcCountRecord()
{
private short field_1_iterations;

public CalcCountRecord() {}

public CalcCountRecord(CalcCountRecord other) {
super(other);
field_1_iterations = other.field_1_iterations;
}

public CalcCountRecord(RecordInputStream in)
{
public CalcCountRecord(RecordInputStream in) {
field_1_iterations = in.readShort();
}

@@ -91,9 +94,15 @@ public final class CalcCountRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public CalcCountRecord clone() {
CalcCountRecord rec = new CalcCountRecord();
rec.field_1_iterations = field_1_iterations;
return rec;
return copy();
}

@Override
public CalcCountRecord copy() {
return new CalcCountRecord(this);
}
}

+ 28
- 32
src/java/org/apache/poi/hssf/record/CalcModeRecord.java View File

@@ -15,52 +15,42 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Calc Mode Record<P>
* Description: Tells the gui whether to calculate formulas
* automatically, manually or automatically
* except for tables.<P>
* REFERENCE: PG 292 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
* Tells the gui whether to calculate formulas automatically, manually or automatically except for tables.
*
* @version 2.0-pre
* @see org.apache.poi.hssf.record.CalcCountRecord
* @see CalcCountRecord
*/

public final class CalcModeRecord extends StandardRecord implements Cloneable {
public final static short sid = 0xD;
public final class CalcModeRecord extends StandardRecord {
public static final short sid = 0xD;

/**
* manually calculate formulas (0)
*/
/** manually calculate formulas (0) */
public static final short MANUAL = 0;

public final static short MANUAL = 0;
/** automatically calculate formulas (1) */
public static final short AUTOMATIC = 1;

/**
* automatically calculate formulas (1)
*/
/** automatically calculate formulas except for tables (-1) */
public static final short AUTOMATIC_EXCEPT_TABLES = -1;

public final static short AUTOMATIC = 1;
private short field_1_calcmode;

/**
* automatically calculate formulas except for tables (-1)
*/
public CalcModeRecord() {}

public final static short AUTOMATIC_EXCEPT_TABLES = -1;
private short field_1_calcmode;

public CalcModeRecord()
{
public CalcModeRecord(CalcModeRecord other) {
super(other);
field_1_calcmode = other.field_1_calcmode;
}

public CalcModeRecord(RecordInputStream in)
{
public CalcModeRecord(RecordInputStream in) {
field_1_calcmode = in.readShort();
}

@@ -119,9 +109,15 @@ public final class CalcModeRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public CalcModeRecord clone() {
CalcModeRecord rec = new CalcModeRecord();
rec.field_1_calcmode = field_1_calcmode;
return rec;
return copy();
}

@Override
public CalcModeRecord copy() {
return new CalcModeRecord(this);
}
}

+ 12
- 10
src/java/org/apache/poi/hssf/record/CellRecord.java View File

@@ -29,8 +29,13 @@ public abstract class CellRecord extends StandardRecord implements CellValueReco
private int _columnIndex;
private int _formatIndex;

protected CellRecord() {
// fields uninitialised
protected CellRecord() {}

protected CellRecord(CellRecord other) {
super(other);
_rowIndex = other.getRow();
_columnIndex = other.getColumn();
_formatIndex = other.getXFIndex();
}

protected CellRecord(RecordInputStream in) {
@@ -100,21 +105,21 @@ public abstract class CellRecord extends StandardRecord implements CellValueReco
* Append specific debug info (used by {@link #toString()} for the value
* contained in this record. Trailing new-line should not be appended
* (superclass does that).
*
*
* @param sb the StringBuilder to write to
*/
protected abstract void appendValueText(StringBuilder sb);

/**
* Gets the debug info BIFF record type name (used by {@link #toString()}.
*
*
* @return the record type name
*/
protected abstract String getRecordName();

/**
* writes out the value data for this cell record
*
*
* @param out the output
*/
protected abstract void serializeValue(LittleEndianOutput out);
@@ -137,9 +142,6 @@ public abstract class CellRecord extends StandardRecord implements CellValueReco
return 6 + getValueDataSize();
}

protected final void copyBaseFields(CellRecord rec) {
rec._rowIndex = _rowIndex;
rec._columnIndex = _columnIndex;
rec._formatIndex = _formatIndex;
}
@Override
public abstract CellRecord copy();
}

+ 21
- 16
src/java/org/apache/poi/hssf/record/CodepageRecord.java View File

@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

@@ -23,33 +23,33 @@ import org.apache.poi.util.CodePageUtil;
import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Codepage Record
* <p>Description: the default characterset. for the workbook</p>
* <p>REFERENCE: PG 293 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)</p>
* <p>Use {@link CodePageUtil} to turn these values into Java code pages
* to encode/decode strings.</p>
* The default characterset. for the workbook<p>
*
* Use {@link CodePageUtil} to turn these values into Java code pages to encode/decode strings.
*
* @version 2.0-pre
*/

public final class CodepageRecord
extends StandardRecord
{
public final static short sid = 0x42;
private short field_1_codepage; // = 0;
public final class CodepageRecord extends StandardRecord {
public static final short sid = 0x42;

/**
* Excel 97+ (Biff 8) should always store strings as UTF-16LE or
* compressed versions of that. As such, this should always be
* 0x4b0 = UTF_16, except for files coming from older versions.
*/
public final static short CODEPAGE = ( short ) 0x4b0;
public static final short CODEPAGE = ( short ) 0x4b0;

public CodepageRecord()
{
private short field_1_codepage;

public CodepageRecord() {}

public CodepageRecord(CodepageRecord other) {
super(other);
field_1_codepage = other.field_1_codepage;
}

public CodepageRecord(RecordInputStream in)
{
public CodepageRecord(RecordInputStream in) {
field_1_codepage = in.readShort();
}

@@ -100,4 +100,9 @@ public final class CodepageRecord
{
return sid;
}

@Override
public CodepageRecord copy() {
return new CodepageRecord(this);
}
}

+ 29
- 18
src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java View File

@@ -17,27 +17,27 @@

package org.apache.poi.hssf.record;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: COLINFO Record (0x007D)<p>
* Description: Defines with width and formatting for a range of columns<p>
* REFERENCE: PG 293 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Defines with width and formatting for a range of columns
*/
public final class ColumnInfoRecord extends StandardRecord implements Cloneable {
public final class ColumnInfoRecord extends StandardRecord {
public static final short sid = 0x007D;

private static final BitField hidden = BitFieldFactory.getInstance(0x01);
private static final BitField outlevel = BitFieldFactory.getInstance(0x0700);
private static final BitField collapsed = BitFieldFactory.getInstance(0x1000);

private int _firstCol;
private int _lastCol;
private int _colWidth;
private int _xfIndex;
private int _options;
private static final BitField hidden = BitFieldFactory.getInstance(0x01);
private static final BitField outlevel = BitFieldFactory.getInstance(0x0700);
private static final BitField collapsed = BitFieldFactory.getInstance(0x1000);
// Excel seems write values 2, 10, and 260, even though spec says "must be zero"
private int field_6_reserved;

@@ -51,6 +51,16 @@ public final class ColumnInfoRecord extends StandardRecord implements Cloneable
field_6_reserved = 2; // seems to be the most common value
}

public ColumnInfoRecord(ColumnInfoRecord other) {
super(other);
_firstCol = other._firstCol;
_lastCol = other._lastCol;
_colWidth = other._colWidth;
_xfIndex = other._xfIndex;
_options = other._options;
field_6_reserved = other.field_6_reserved;
}

public ColumnInfoRecord(RecordInputStream in) {
_firstCol = in.readUShort();
_lastCol = in.readUShort();
@@ -196,7 +206,7 @@ public final class ColumnInfoRecord extends StandardRecord implements Cloneable

/**
* @param other the format to match with
*
*
* @return {@code true} if the format, options and column width match
*/
public boolean formatMatches(ColumnInfoRecord other) {
@@ -246,14 +256,15 @@ public final class ColumnInfoRecord extends StandardRecord implements Cloneable
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public ColumnInfoRecord clone() {
ColumnInfoRecord rec = new ColumnInfoRecord();
rec._firstCol = _firstCol;
rec._lastCol = _lastCol;
rec._colWidth = _colWidth;
rec._xfIndex = _xfIndex;
rec._options = _options;
rec.field_6_reserved = field_6_reserved;
return rec;
return copy();
}

@Override
public ColumnInfoRecord copy() {
return new ColumnInfoRecord(this);
}
}

+ 79
- 71
src/java/org/apache/poi/hssf/record/CommonObjectDataSubRecord.java View File

@@ -23,50 +23,51 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;

/**
* The common object data record is used to store all common preferences for an excel object.
*/
public final class CommonObjectDataSubRecord extends SubRecord implements Cloneable {
public final static short sid = 0x0015;
public final class CommonObjectDataSubRecord extends SubRecord {
public static final short sid = 0x0015;

private static final BitField locked = BitFieldFactory.getInstance(0x0001);
private static final BitField printable = BitFieldFactory.getInstance(0x0010);
private static final BitField autofill = BitFieldFactory.getInstance(0x2000);
private static final BitField autoline = BitFieldFactory.getInstance(0x4000);

public final static short OBJECT_TYPE_GROUP = 0;
public final static short OBJECT_TYPE_LINE = 1;
public final static short OBJECT_TYPE_RECTANGLE = 2;
public final static short OBJECT_TYPE_OVAL = 3;
public final static short OBJECT_TYPE_ARC = 4;
public final static short OBJECT_TYPE_CHART = 5;
public final static short OBJECT_TYPE_TEXT = 6;
public final static short OBJECT_TYPE_BUTTON = 7;
public final static short OBJECT_TYPE_PICTURE = 8;
public final static short OBJECT_TYPE_POLYGON = 9;
public final static short OBJECT_TYPE_RESERVED1 = 10;
public final static short OBJECT_TYPE_CHECKBOX = 11;
public final static short OBJECT_TYPE_OPTION_BUTTON = 12;
public final static short OBJECT_TYPE_EDIT_BOX = 13;
public final static short OBJECT_TYPE_LABEL = 14;
public final static short OBJECT_TYPE_DIALOG_BOX = 15;
public final static short OBJECT_TYPE_SPINNER = 16;
public final static short OBJECT_TYPE_SCROLL_BAR = 17;
public final static short OBJECT_TYPE_LIST_BOX = 18;
public final static short OBJECT_TYPE_GROUP_BOX = 19;
public final static short OBJECT_TYPE_COMBO_BOX = 20;
public final static short OBJECT_TYPE_RESERVED2 = 21;
public final static short OBJECT_TYPE_RESERVED3 = 22;
public final static short OBJECT_TYPE_RESERVED4 = 23;
public final static short OBJECT_TYPE_RESERVED5 = 24;
public final static short OBJECT_TYPE_COMMENT = 25;
public final static short OBJECT_TYPE_RESERVED6 = 26;
public final static short OBJECT_TYPE_RESERVED7 = 27;
public final static short OBJECT_TYPE_RESERVED8 = 28;
public final static short OBJECT_TYPE_RESERVED9 = 29;
public final static short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 30;
public static final short OBJECT_TYPE_GROUP = 0;
public static final short OBJECT_TYPE_LINE = 1;
public static final short OBJECT_TYPE_RECTANGLE = 2;
public static final short OBJECT_TYPE_OVAL = 3;
public static final short OBJECT_TYPE_ARC = 4;
public static final short OBJECT_TYPE_CHART = 5;
public static final short OBJECT_TYPE_TEXT = 6;
public static final short OBJECT_TYPE_BUTTON = 7;
public static final short OBJECT_TYPE_PICTURE = 8;
public static final short OBJECT_TYPE_POLYGON = 9;
public static final short OBJECT_TYPE_RESERVED1 = 10;
public static final short OBJECT_TYPE_CHECKBOX = 11;
public static final short OBJECT_TYPE_OPTION_BUTTON = 12;
public static final short OBJECT_TYPE_EDIT_BOX = 13;
public static final short OBJECT_TYPE_LABEL = 14;
public static final short OBJECT_TYPE_DIALOG_BOX = 15;
public static final short OBJECT_TYPE_SPINNER = 16;
public static final short OBJECT_TYPE_SCROLL_BAR = 17;
public static final short OBJECT_TYPE_LIST_BOX = 18;
public static final short OBJECT_TYPE_GROUP_BOX = 19;
public static final short OBJECT_TYPE_COMBO_BOX = 20;
public static final short OBJECT_TYPE_RESERVED2 = 21;
public static final short OBJECT_TYPE_RESERVED3 = 22;
public static final short OBJECT_TYPE_RESERVED4 = 23;
public static final short OBJECT_TYPE_RESERVED5 = 24;
public static final short OBJECT_TYPE_COMMENT = 25;
public static final short OBJECT_TYPE_RESERVED6 = 26;
public static final short OBJECT_TYPE_RESERVED7 = 27;
public static final short OBJECT_TYPE_RESERVED8 = 28;
public static final short OBJECT_TYPE_RESERVED9 = 29;
public static final short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 30;
private short field_1_objectType;
private int field_2_objectId;
private short field_3_option;
@@ -75,9 +76,16 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea
private int field_6_reserved3;


public CommonObjectDataSubRecord()
{
public CommonObjectDataSubRecord() {}

public CommonObjectDataSubRecord(CommonObjectDataSubRecord other) {
super(other);
field_1_objectType = other.field_1_objectType;
field_2_objectId = other.field_2_objectId;
field_3_option = other.field_3_option;
field_4_reserved1 = other.field_4_reserved1;
field_5_reserved2 = other.field_5_reserved2;
field_6_reserved3 = other.field_6_reserved3;
}

public CommonObjectDataSubRecord(LittleEndianInput in, int size) {
@@ -101,31 +109,31 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea
buffer.append(" .objectType = ")
.append("0x").append(HexDump.toHex( getObjectType ()))
.append(" (").append( getObjectType() ).append(" )");
buffer.append(System.getProperty("line.separator"));
buffer.append(System.getProperty("line.separator"));
buffer.append(" .objectId = ")
.append("0x").append(HexDump.toHex( getObjectId ()))
.append(" (").append( getObjectId() ).append(" )");
buffer.append(System.getProperty("line.separator"));
buffer.append(System.getProperty("line.separator"));
buffer.append(" .option = ")
.append("0x").append(HexDump.toHex( getOption ()))
.append(" (").append( getOption() ).append(" )");
buffer.append(System.getProperty("line.separator"));
buffer.append(" .locked = ").append(isLocked()).append('\n');
buffer.append(" .printable = ").append(isPrintable()).append('\n');
buffer.append(" .autofill = ").append(isAutofill()).append('\n');
buffer.append(" .autoline = ").append(isAutoline()).append('\n');
buffer.append(System.getProperty("line.separator"));
buffer.append(" .locked = ").append(isLocked()).append('\n');
buffer.append(" .printable = ").append(isPrintable()).append('\n');
buffer.append(" .autofill = ").append(isAutofill()).append('\n');
buffer.append(" .autoline = ").append(isAutoline()).append('\n');
buffer.append(" .reserved1 = ")
.append("0x").append(HexDump.toHex( getReserved1 ()))
.append(" (").append( getReserved1() ).append(" )");
buffer.append(System.getProperty("line.separator"));
buffer.append(System.getProperty("line.separator"));
buffer.append(" .reserved2 = ")
.append("0x").append(HexDump.toHex( getReserved2 ()))
.append(" (").append( getReserved2() ).append(" )");
buffer.append(System.getProperty("line.separator"));
buffer.append(System.getProperty("line.separator"));
buffer.append(" .reserved3 = ")
.append("0x").append(HexDump.toHex( getReserved3 ()))
.append(" (").append( getReserved3() ).append(" )");
buffer.append(System.getProperty("line.separator"));
buffer.append(System.getProperty("line.separator"));

buffer.append("[/ftCmo]\n");
return buffer.toString();
@@ -159,23 +167,23 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public CommonObjectDataSubRecord clone() {
CommonObjectDataSubRecord rec = new CommonObjectDataSubRecord();
rec.field_1_objectType = field_1_objectType;
rec.field_2_objectId = field_2_objectId;
rec.field_3_option = field_3_option;
rec.field_4_reserved1 = field_4_reserved1;
rec.field_5_reserved2 = field_5_reserved2;
rec.field_6_reserved3 = field_6_reserved3;
return rec;
return copy();
}

@Override
public CommonObjectDataSubRecord copy() {
return new CommonObjectDataSubRecord(this);
}


/**
* Get the object type field for the CommonObjectData record.
*
* @return One of
* @return One of
* OBJECT_TYPE_GROUP
* OBJECT_TYPE_LINE
* OBJECT_TYPE_RECTANGLE
@@ -217,7 +225,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea
* Set the object type field for the CommonObjectData record.
*
* @param field_1_objectType
* One of
* One of
* OBJECT_TYPE_GROUP
* OBJECT_TYPE_LINE
* OBJECT_TYPE_RECTANGLE
@@ -257,7 +265,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Get the object id field for the CommonObjectData record.
*
*
* @return the object id field
*/
public int getObjectId()
@@ -267,7 +275,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Set the object id field for the CommonObjectData record.
*
*
* @param field_2_objectId the object id field
*/
public void setObjectId(int field_2_objectId)
@@ -277,7 +285,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Get the option field for the CommonObjectData record.
*
*
* @return the option field
*/
public short getOption()
@@ -287,7 +295,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Set the option field for the CommonObjectData record.
*
*
* @param field_3_option the option field
*/
public void setOption(short field_3_option)
@@ -297,7 +305,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Get the reserved1 field for the CommonObjectData record.
*
*
* @return the reserved1 field
*/
public int getReserved1()
@@ -307,7 +315,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Set the reserved1 field for the CommonObjectData record.
*
*
* @param field_4_reserved1 the reserved1 field
*/
public void setReserved1(int field_4_reserved1)
@@ -317,7 +325,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Get the reserved2 field for the CommonObjectData record.
*
*
* @return the reserved2 field
*/
public int getReserved2()
@@ -327,7 +335,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Set the reserved2 field for the CommonObjectData record.
*
*
* @param field_5_reserved2 the reserved2 field
*/
public void setReserved2(int field_5_reserved2)
@@ -337,7 +345,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Get the reserved3 field for the CommonObjectData record.
*
*
* @return the reserved3 field
*/
public int getReserved3()
@@ -347,7 +355,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea

/**
* Set the reserved3 field for the CommonObjectData record.
*
*
* @param field_6_reserved3 the reserved3 field
*/
public void setReserved3(int field_6_reserved3)
@@ -358,7 +366,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea
/**
* Sets the locked field value.
* true if object is locked when sheet has been protected
*
*
* @param value {@code true} if object is locked when sheet has been protected
*/
public void setLocked(boolean value)
@@ -378,7 +386,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea
/**
* Sets the printable field value.
* object appears when printed
*
*
* @param value {@code true} if object appears when printed
*/
public void setPrintable(boolean value)
@@ -398,7 +406,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea
/**
* Sets the autofill field value.
* whether object uses an automatic fill style
*
*
* @param value {@code true} if object uses an automatic fill style
*/
public void setAutofill(boolean value)
@@ -418,7 +426,7 @@ public final class CommonObjectDataSubRecord extends SubRecord implements Clonea
/**
* Sets the autoline field value.
* whether object uses an automatic line style
*
*
* @param value {@code true} if object uses an automatic line style
*/
public void setAutoline(boolean value)

+ 20
- 9
src/java/org/apache/poi/hssf/record/ContinueRecord.java View File

@@ -19,23 +19,26 @@ package org.apache.poi.hssf.record;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Continue Record(0x003C) - Helper class used primarily for SST Records <P>
* Description: handles overflow for prior record in the input
* stream; content is tailored to that prior record<P>
* @author Marc Johnson (mjohnson at apache dot org)
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Csaba Nagy (ncsaba at yahoo dot com)
* Helper class used primarily for SST Records<p>
*
* handles overflow for prior record in the input stream; content is tailored to that prior record
*/
public final class ContinueRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x003C;
public final class ContinueRecord extends StandardRecord {
public static final short sid = 0x003C;
private byte[] _data;

public ContinueRecord(byte[] data) {
_data = data;
}

public ContinueRecord(ContinueRecord other) {
super(other);
_data = (other._data == null) ? null : other._data.clone();
}

protected int getDataSize() {
return _data.length;
}
@@ -70,7 +73,15 @@ public final class ContinueRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public ContinueRecord clone() {
return new ContinueRecord(_data);
return copy();
}

@Override
public ContinueRecord copy() {
return new ContinueRecord(this);
}
}

+ 20
- 16
src/java/org/apache/poi/hssf/record/CountryRecord.java View File

@@ -15,37 +15,36 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Country Record (aka WIN.INI country)<P>
* Description: used for localization. Currently HSSF always sets this to 1
* and it seems to work fine even in Germany. (es geht's auch fuer Deutschland)<P>
* Country Record (aka WIN.INI country) - used for localization<p>
*
* Currently HSSF always sets this to 1 and it seems to work fine even in Germany.
*
* REFERENCE: PG 298 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @version 2.0-pre
*/

public final class CountryRecord
extends StandardRecord
{
public final static short sid = 0x8c;
public final class CountryRecord extends StandardRecord {
public static final short sid = 0x8c;

// 1 for US
private short field_1_default_country;
private short field_2_current_country;
private short field_1_default_country;
private short field_2_current_country;

public CountryRecord()
{
public CountryRecord() {}

public CountryRecord(CountryRecord other) {
super(other);
field_1_default_country = other.field_1_default_country;
field_2_current_country = other.field_2_current_country;
}

public CountryRecord(RecordInputStream in)
{
public CountryRecord(RecordInputStream in) {
field_1_default_country = in.readShort();
field_2_current_country = in.readShort();
}
@@ -120,4 +119,9 @@ public final class CountryRecord
{
return sid;
}

@Override
public CountryRecord copy() {
return new CountryRecord(this);
}
}

+ 18
- 36
src/java/org/apache/poi/hssf/record/DBCellRecord.java View File

@@ -19,39 +19,15 @@ package org.apache.poi.hssf.record;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: DBCell Record (0x00D7)<p>
* Description: Used by Excel and other MS apps to quickly find rows in the sheets.<P>
* REFERENCE: PG 299/440 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Used by Excel and other MS apps to quickly find rows in the sheets.
*/
public final class DBCellRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x00D7;
public final static int BLOCK_SIZE = 32;
public static final class Builder {
private short[] _cellOffsets;
private int _nCellOffsets;
public Builder() {
_cellOffsets = new short[4];
}
public final class DBCellRecord extends StandardRecord {
public static final short sid = 0x00D7;
public static final int BLOCK_SIZE = 32;

public void addCellOffset(int cellRefOffset) {
if (_cellOffsets.length <= _nCellOffsets) {
short[] temp = new short[_nCellOffsets * 2];
System.arraycopy(_cellOffsets, 0, temp, 0, _nCellOffsets);
_cellOffsets = temp;
}
_cellOffsets[_nCellOffsets] = (short) cellRefOffset;
_nCellOffsets++;
}

public DBCellRecord build(int rowOffset) {
short[] cellOffsets = new short[_nCellOffsets];
System.arraycopy(_cellOffsets, 0, cellOffsets, 0, _nCellOffsets);
return new DBCellRecord(rowOffset, cellOffsets);
}
}
/**
* offset from the start of this DBCellRecord to the start of the first cell in
* the next DBCell block.
@@ -59,23 +35,21 @@ public final class DBCellRecord extends StandardRecord implements Cloneable {
private final int field_1_row_offset;
private final short[] field_2_cell_offsets;

DBCellRecord(int rowOffset, short[]cellOffsets) {
public DBCellRecord(int rowOffset, short[] cellOffsets) {
field_1_row_offset = rowOffset;
field_2_cell_offsets = cellOffsets;
}

public DBCellRecord(RecordInputStream in) {
field_1_row_offset = in.readUShort();
int size = in.remaining();
int size = in.remaining();
field_2_cell_offsets = new short[ size / 2 ];

for (int i=0;i<field_2_cell_offsets.length;i++)
{
for (int i=0;i<field_2_cell_offsets.length;i++) {
field_2_cell_offsets[ i ] = in.readShort();
}
}


public String toString() {
StringBuilder buffer = new StringBuilder();

@@ -91,8 +65,8 @@ public final class DBCellRecord extends StandardRecord implements Cloneable {

public void serialize(LittleEndianOutput out) {
out.writeInt(field_1_row_offset);
for (int k = 0; k < field_2_cell_offsets.length; k++) {
out.writeShort(field_2_cell_offsets[ k ]);
for (short field_2_cell_offset : field_2_cell_offsets) {
out.writeShort(field_2_cell_offset);
}
}
protected int getDataSize() {
@@ -104,7 +78,15 @@ public final class DBCellRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public DBCellRecord clone() {
return copy();
}

@Override
public DBCellRecord copy() {
// safe because immutable
return this;
}

+ 43
- 59
src/java/org/apache/poi/hssf/record/DConRefRecord.java View File

@@ -18,10 +18,10 @@
*/
package org.apache.poi.hssf.record;

import java.io.ByteArrayInputStream;
import java.util.Arrays;

import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.StringUtil;
@@ -67,8 +67,7 @@ import org.apache.poi.util.StringUtil;
*
* At the moment this class is read-only.
*/
public class DConRefRecord extends StandardRecord
{
public class DConRefRecord extends StandardRecord {

//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
@@ -108,54 +107,25 @@ public class DConRefRecord extends StandardRecord
*/
private byte[] _unused;

public DConRefRecord(DConRefRecord other) {
super(other);
firstCol = other.firstCol;
firstRow = other.firstRow;
lastCol = other.lastCol;
lastRow = other.lastRow;
charCount = other.charCount;
charType = other.charType;
path = (other.path == null) ? null : other.path.clone();
_unused = (other._unused == null) ? null : other._unused.clone();
}

/**
* Read constructor.
*
* @param data byte array containing a DConRef Record, including the header.
*/
public DConRefRecord(byte[] data)
{
int offset = 0;
if (!(LittleEndian.getShort(data, offset) == DConRefRecord.sid))
throw new RecordFormatException("incompatible sid.");
offset += LittleEndian.SHORT_SIZE;

//length = LittleEndian.getShort(data, offset);
offset += LittleEndian.SHORT_SIZE;

firstRow = LittleEndian.getUShort(data, offset);
offset += LittleEndian.SHORT_SIZE;
lastRow = LittleEndian.getUShort(data, offset);
offset += LittleEndian.SHORT_SIZE;
firstCol = LittleEndian.getUByte(data, offset);
offset += LittleEndian.BYTE_SIZE;
lastCol = LittleEndian.getUByte(data, offset);
offset += LittleEndian.BYTE_SIZE;
charCount = LittleEndian.getUShort(data, offset);
offset += LittleEndian.SHORT_SIZE;
if (charCount < 2)
throw new RecordFormatException("Character count must be >= 2");

charType = LittleEndian.getUByte(data, offset);
offset += LittleEndian.BYTE_SIZE; //7 bits reserved + 1 bit type

/*
* bytelength is the length of the string in bytes, which depends on whether the string is
* made of single- or double-byte chars. This is given by charType, which equals 0 if
* single-byte, 1 if double-byte.
*/
int byteLength = charCount * ((charType & 1) + 1);

path = LittleEndian.getByteArray(data, offset, byteLength, MAX_RECORD_LENGTH);
offset += byteLength;

/*
* If it's a self reference, the last one or two bytes (depending on char type) are the
* unused field. Not sure If i need to bother with this...
*/
if (path[0] == 0x02)
_unused = LittleEndian.getByteArray(data, offset, (charType + 1), MAX_RECORD_LENGTH);

public DConRefRecord(byte[] data) {
this(bytesToRIStream(data));
}

/**
@@ -163,10 +133,10 @@ public class DConRefRecord extends StandardRecord
*
* @param inStream RecordInputStream containing a DConRefRecord structure.
*/
public DConRefRecord(RecordInputStream inStream)
{
if (inStream.getSid() != sid)
public DConRefRecord(RecordInputStream inStream) {
if (inStream.getSid() != sid) {
throw new RecordFormatException("Wrong sid: " + inStream.getSid());
}

firstRow = inStream.readUShort();
lastRow = inStream.readUShort();
@@ -174,17 +144,23 @@ public class DConRefRecord extends StandardRecord
lastCol = inStream.readUByte();

charCount = inStream.readUShort();
charType = inStream.readUByte() & 0x01; //first bit only.

// byteLength depends on whether we are using single- or double-byte chars.
int byteLength = charCount * (charType + 1);
// 7 bits reserved + 1 bit type - first bit only
charType = inStream.readUByte() & 0x01;

// bytelength is the length of the string in bytes, which depends on whether the string is
// made of single- or double-byte chars. This is given by charType, which equals 0 if
// single-byte, 1 if double-byte.
final int byteLength = charCount * (charType + 1);

path = IOUtils.safelyAllocate(byteLength, MAX_RECORD_LENGTH);
inStream.readFully(path);

if (path[0] == 0x02)
// If it's a self reference, the last one or two bytes (depending on char type) are the
// unused field. Not sure If i need to bother with this...
if (path[0] == 0x02) {
_unused = inStream.readRemainder();

}
}

/*
@@ -291,8 +267,7 @@ public class DConRefRecord extends StandardRecord
//all of the path strings start with either 0x02 or 0x01 followed by zero or
//more of 0x01..0x08
int offset = 1;
while (path[offset] < 0x20 && offset < path.length)
{
while (offset < path.length && path[offset] < 0x20) {
offset++;
}
String out = new String(Arrays.copyOfRange(path, offset, path.length), StringUtil.UTF8);
@@ -310,8 +285,17 @@ public class DConRefRecord extends StandardRecord
*/
public boolean isExternalRef()
{
if (path[0] == 0x01)
return true;
return false;
return path[0] == 0x01;
}

@Override
public DConRefRecord copy() {
return new DConRefRecord(this);
}

private static RecordInputStream bytesToRIStream(byte[] data) {
RecordInputStream ric = new RecordInputStream(new ByteArrayInputStream(data));
ric.nextRecord();
return ric;
}
}

+ 15
- 5
src/java/org/apache/poi/hssf/record/DSFRecord.java View File

@@ -23,21 +23,26 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Double Stream Flag Record (0x0161)<p>
* Description: tells if this is a double stream file. (always no for HSSF generated files)<p>
* Double Stream files contain both BIFF8 and BIFF7 workbooks.<p>
* REFERENCE: PG 305 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Tells if this is a double stream file. (never applies to HSSF generated files)<p>
*
* Double Stream files contain both BIFF8 and BIFF7 workbooks.
*/
public final class DSFRecord extends StandardRecord {
public final static short sid = 0x0161;
public static final short sid = 0x0161;

private static final BitField biff5BookStreamFlag = BitFieldFactory.getInstance(0x0001);

private int _options;

private DSFRecord(DSFRecord other) {
super(other);
_options = other._options;
}

private DSFRecord(int options) {
_options = options;
}

public DSFRecord(boolean isBiff5BookStreamPresent) {
this(0);
_options = biff5BookStreamFlag.setBoolean(0, isBiff5BookStreamPresent);
@@ -71,4 +76,9 @@ public final class DSFRecord extends StandardRecord {
public short getSid() {
return sid;
}

@Override
public DSFRecord copy() {
return new DSFRecord(this);
}
}

+ 26
- 17
src/java/org/apache/poi/hssf/record/DVALRecord.java View File

@@ -18,14 +18,13 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: DATAVALIDATIONS Record (0x01B2)<p>
* Description: used in data validation ;
* This record is the list header of all data validation records (0x01BE) in the current sheet.
* This record is the list header of all data validation records (0x01BE) in the current sheet.
*/
public final class DVALRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x01B2;
public final class DVALRecord extends StandardRecord {
public static final short sid = 0x01B2;

/** Options of the DVAL */
private short field_1_options;
@@ -47,12 +46,21 @@ public final class DVALRecord extends StandardRecord implements Cloneable {
field_5_dv_no = 0x00000000;
}

public DVALRecord(DVALRecord other) {
super(other);
field_1_options = other.field_1_options;
field_2_horiz_pos = other.field_2_horiz_pos;
field_3_vert_pos = other.field_3_vert_pos;
field_cbo_id = other.field_cbo_id;
field_5_dv_no = other.field_5_dv_no;
}

public DVALRecord(RecordInputStream in) {
field_1_options = in.readShort();
field_2_horiz_pos = in.readInt();
field_3_vert_pos = in.readInt();
field_cbo_id = in.readInt();
field_5_dv_no = in.readInt();
field_cbo_id = in.readInt();
field_5_dv_no = in.readInt();
}

/**
@@ -142,7 +150,6 @@ public final class DVALRecord extends StandardRecord implements Cloneable {
}

public void serialize(LittleEndianOutput out) {
out.writeShort(getOptions());
out.writeInt(getHorizontalPos());
out.writeInt(getVerticalPos());
@@ -158,14 +165,16 @@ public final class DVALRecord extends StandardRecord implements Cloneable {
return sid;
}

@Override
public DVALRecord clone() {
DVALRecord rec = new DVALRecord();
rec.field_1_options = field_1_options;
rec.field_2_horiz_pos = field_2_horiz_pos;
rec.field_3_vert_pos = field_3_vert_pos;
rec.field_cbo_id = field_cbo_id;
rec.field_5_dv_no = field_5_dv_no;
return rec;
@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public DVALRecord clone() {
return copy();
}

@Override
public DVALRecord copy() {
return new DVALRecord(this);
}
}

+ 61
- 45
src/java/org/apache/poi/hssf/record/DVRecord.java View File

@@ -25,64 +25,77 @@ import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.util.BitField;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;
import org.apache.poi.util.StringUtil;

/**
* Title: DATAVALIDATION Record (0x01BE)<p>
* Description: This record stores data validation settings and a list of cell ranges
* which contain these settings. The data validation settings of a sheet
* are stored in a sequential list of DV records. This list is followed by
* DVAL record(s)
* This record stores data validation settings and a list of cell ranges which contain these settings.
* The data validation settings of a sheet are stored in a sequential list of DV records.
* This list is followed by DVAL record(s)
*/
public final class DVRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x01BE;
public final class DVRecord extends StandardRecord {
public static final short sid = 0x01BE;
/** the unicode string used for error/prompt title/text when not present */
private static final UnicodeString NULL_TEXT_STRING = new UnicodeString("\0");

/**
* Option flags field
*
* @see HSSFDataValidation utility class
*/
private static final BitField opt_data_type = new BitField(0x0000000F);
private static final BitField opt_error_style = new BitField(0x00000070);
private static final BitField opt_string_list_formula = new BitField(0x00000080);
private static final BitField opt_empty_cell_allowed = new BitField(0x00000100);
private static final BitField opt_suppress_dropdown_arrow = new BitField(0x00000200);
private static final BitField opt_show_prompt_on_cell_selected = new BitField(0x00040000);
private static final BitField opt_show_error_on_invalid_value = new BitField(0x00080000);
private static final BitField opt_condition_operator = new BitField(0x00700000);

/** Option flags */
private int _option_flags;
/** Title of the prompt box, cannot be longer than 32 chars */
private UnicodeString _promptTitle;
private final UnicodeString _promptTitle;
/** Title of the error box, cannot be longer than 32 chars */
private UnicodeString _errorTitle;
private final UnicodeString _errorTitle;
/** Text of the prompt box, cannot be longer than 255 chars */
private UnicodeString _promptText;
private final UnicodeString _promptText;
/** Text of the error box, cannot be longer than 255 chars */
private UnicodeString _errorText;
private final UnicodeString _errorText;
/** Not used - Excel seems to always write 0x3FE0 */
private short _not_used_1 = 0x3FE0;
/** Formula data for first condition (RPN token array without size field) */
private Formula _formula1;
private final Formula _formula1;
/** Not used - Excel seems to always write 0x0000 */
@SuppressWarnings("RedundantFieldInitialization")
private short _not_used_2 = 0x0000;
/** Formula data for second condition (RPN token array without size field) */
private Formula _formula2;
private final Formula _formula2;
/** Cell range address list with all affected ranges */
private CellRangeAddressList _regions;
/**
* Option flags field
*
* @see HSSFDataValidation utility class
*/
private static final BitField opt_data_type = new BitField(0x0000000F);
private static final BitField opt_error_style = new BitField(0x00000070);
private static final BitField opt_string_list_formula = new BitField(0x00000080);
private static final BitField opt_empty_cell_allowed = new BitField(0x00000100);
private static final BitField opt_suppress_dropdown_arrow = new BitField(0x00000200);
private static final BitField opt_show_prompt_on_cell_selected = new BitField(0x00040000);
private static final BitField opt_show_error_on_invalid_value = new BitField(0x00080000);
private static final BitField opt_condition_operator = new BitField(0x00700000);
private final CellRangeAddressList _regions;
public DVRecord(DVRecord other) {
super(other);
_option_flags = other._option_flags;
_promptTitle = other._promptTitle.copy();
_errorTitle = other._errorTitle.copy();
_promptText = other._promptText.copy();
_errorText = other._errorText.copy();
_not_used_1 = other._not_used_1;
_formula1 = (other._formula1 == null) ? null : other._formula1.copy();
_not_used_2 = other._not_used_2;
_formula2 = (other._formula2 == null) ? null : other._formula2.copy();
_regions = (other._regions == null) ? null : other._regions.copy();
}

public DVRecord(int validationType, int operator, int errorStyle, boolean emptyCellAllowed,
boolean suppressDropDownArrow, boolean isExplicitList,
boolean showPromptBox, String promptTitle, String promptText,
boolean showPromptBox, String promptTitle, String promptText,
boolean showErrorBox, String errorTitle, String errorText,
Ptg[] formula1, Ptg[] formula2,
CellRangeAddressList regions) {
// check length-limits
if(promptTitle != null && promptTitle.length() > 32) {
throw new IllegalStateException("Prompt-title cannot be longer than 32 characters, but had: " + promptTitle);
@@ -118,7 +131,6 @@ public final class DVRecord extends StandardRecord implements Cloneable {
}

public DVRecord(RecordInputStream in) {

_option_flags = in.readInt();

_promptTitle = readUnicodeString(in);
@@ -144,7 +156,6 @@ public final class DVRecord extends StandardRecord implements Cloneable {
_regions = new CellRangeAddressList(in);
}

// --> start option flags
/**
* @return the condition data type
* @see org.apache.poi.ss.usermodel.DataValidationConstraint.ValidationType
@@ -276,7 +287,7 @@ public final class DVRecord extends StandardRecord implements Cloneable {

private static void appendFormula(StringBuilder sb, String label, Formula f) {
sb.append(label);
if (f == null) {
sb.append("<empty>\n");
return;
@@ -291,7 +302,7 @@ public final class DVRecord extends StandardRecord implements Cloneable {
public void serialize(LittleEndianOutput out) {

out.writeInt(_option_flags);
serializeUnicodeString(_promptTitle, out);
serializeUnicodeString(_errorTitle, out);
serializeUnicodeString(_promptText, out);
@@ -299,19 +310,19 @@ public final class DVRecord extends StandardRecord implements Cloneable {
out.writeShort(_formula1.getEncodedTokenSize());
out.writeShort(_not_used_1);
_formula1.serializeTokens(out);
out.writeShort(_formula2.getEncodedTokenSize());
out.writeShort(_not_used_2);
_formula2.serializeTokens(out);
_regions.serialize(out);
}

/**
* When entered via the UI, Excel translates empty string into "\0"
* While it is possible to encode the title/text as empty string (Excel doesn't exactly crash),
* the resulting tool-tip text / message box looks wrong. It is best to do the same as the
* Excel UI and encode 'not present' as "\0".
* the resulting tool-tip text / message box looks wrong. It is best to do the same as the
* Excel UI and encode 'not present' as "\0".
*/
private static UnicodeString resolveTitleText(String str) {
if (str == null || str.length() < 1) {
@@ -354,13 +365,18 @@ public final class DVRecord extends StandardRecord implements Cloneable {
public short getSid() {
return sid;
}
/**
* Clones the object. Uses serialisation, as the
* contents are somewhat complex
*/

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public DVRecord clone() {
return (DVRecord)cloneViaReserialise();
return copy();
}

/** Clones the object. */
@Override
public DVRecord copy() {
return new DVRecord(this);
}
}

+ 18
- 15
src/java/org/apache/poi/hssf/record/DateWindow1904Record.java View File

@@ -15,33 +15,31 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Date Window 1904 Flag record <P>
* Description: Flag specifying whether 1904 date windowing is used.
* (tick toc tick toc...BOOM!) <P>
* REFERENCE: PG 280 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* Flag specifying whether 1904 date windowing is used.
*
* @version 2.0-pre
*/

public final class DateWindow1904Record
extends StandardRecord
{
public final static short sid = 0x22;
private short field_1_window;
public final class DateWindow1904Record extends StandardRecord {
public static final short sid = 0x22;

public DateWindow1904Record()
{
private short field_1_window;

public DateWindow1904Record() {}

public DateWindow1904Record(DateWindow1904Record other) {
super(other);
field_1_window = other.field_1_window;
}

public DateWindow1904Record(RecordInputStream in)
{
public DateWindow1904Record(RecordInputStream in) {
field_1_window = in.readShort();
}

@@ -88,4 +86,9 @@ public final class DateWindow1904Record
{
return sid;
}

@Override
public DateWindow1904Record copy() {
return new DateWindow1904Record(this);
}
}

+ 23
- 15
src/java/org/apache/poi/hssf/record/DefaultColWidthRecord.java View File

@@ -18,30 +18,32 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Default Column Width Record (0x0055) <P>
* Description: Specifies the default width for columns that have no specific
* width set.<P>
* REFERENCE: PG 302 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
* Specifies the default width for columns that have no specific width set.
*
* @version 2.0-pre
*/
public final class DefaultColWidthRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x0055;
private int field_1_col_width;
public final class DefaultColWidthRecord extends StandardRecord {
public static final short sid = 0x0055;

/**
* The default column width is 8 characters
*/
public final static int DEFAULT_COLUMN_WIDTH = 0x0008;
public static final int DEFAULT_COLUMN_WIDTH = 0x0008;

public DefaultColWidthRecord()
{
private int field_1_col_width;

public DefaultColWidthRecord() {
field_1_col_width = DEFAULT_COLUMN_WIDTH;
}

public DefaultColWidthRecord(DefaultColWidthRecord other) {
super(other);
field_1_col_width = other.field_1_col_width;
}

public DefaultColWidthRecord(RecordInputStream in)
{
field_1_col_width = in.readUShort();
@@ -92,9 +94,15 @@ public final class DefaultColWidthRecord extends StandardRecord implements Clone
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public DefaultColWidthRecord clone() {
DefaultColWidthRecord rec = new DefaultColWidthRecord();
rec.field_1_col_width = field_1_col_width;
return rec;
return copy();
}

@Override
public DefaultColWidthRecord copy() {
return new DefaultColWidthRecord(this);
}
}

+ 26
- 22
src/java/org/apache/poi/hssf/record/DefaultRowHeightRecord.java View File

@@ -1,4 +1,3 @@

/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -20,35 +19,35 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Default Row Height Record
* Description: Row height for rows with undefined or not explicitly defined
* heights.
* REFERENCE: PG 301 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
* Row height for rows with undefined or not explicitly defined heights.
*
* @version 2.0-pre
*/

public final class DefaultRowHeightRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x225;
private short field_1_option_flags;
private short field_2_row_height;
public final class DefaultRowHeightRecord extends StandardRecord {
public static final short sid = 0x225;

/**
* The default row height for empty rows is 255 twips (255 / 20 == 12.75 points)
*/
/** The default row height for empty rows is 255 twips (255 / 20 == 12.75 points) */
public static final short DEFAULT_ROW_HEIGHT = 0xFF;

public DefaultRowHeightRecord()
{
private short field_1_option_flags;
private short field_2_row_height;

public DefaultRowHeightRecord() {
field_1_option_flags = 0x0000;
field_2_row_height = DEFAULT_ROW_HEIGHT;
}

public DefaultRowHeightRecord(RecordInputStream in)
{
public DefaultRowHeightRecord(DefaultRowHeightRecord other) {
super(other);
field_1_option_flags = other.field_1_option_flags;
field_2_row_height = other.field_2_row_height;
}

public DefaultRowHeightRecord(RecordInputStream in) {
field_1_option_flags = in.readShort();
field_2_row_height = in.readShort();
}
@@ -121,10 +120,15 @@ public final class DefaultRowHeightRecord extends StandardRecord implements Clon
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public DefaultRowHeightRecord clone() {
DefaultRowHeightRecord rec = new DefaultRowHeightRecord();
rec.field_1_option_flags = field_1_option_flags;
rec.field_2_row_height = field_2_row_height;
return rec;
return copy();
}

@Override
public DefaultRowHeightRecord copy() {
return new DefaultRowHeightRecord(this);
}
}

+ 18
- 8
src/java/org/apache/poi/hssf/record/DeltaRecord.java View File

@@ -18,15 +18,12 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Delta Record (0x0010)<p>
* Description: controls the accuracy of the calculations<p>
* REFERENCE: PG 303 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
*/
public final class DeltaRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x0010;
public final static double DEFAULT_VALUE = 0.0010; // should be .001
/** Controls the accuracy of the calculations */
public final class DeltaRecord extends StandardRecord {
public static final short sid = 0x0010;
public static final double DEFAULT_VALUE = 0.0010;

// a double is an IEEE 8-byte float...damn IEEE and their goofy standards an
// ambiguous numeric identifiers
@@ -36,6 +33,11 @@ public final class DeltaRecord extends StandardRecord implements Cloneable {
field_1_max_change = maxChange;
}

public DeltaRecord(DeltaRecord other) {
super(other);
field_1_max_change = other.field_1_max_change;
}

public DeltaRecord(RecordInputStream in) {
field_1_max_change = in.readDouble();
}
@@ -70,7 +72,15 @@ public final class DeltaRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public DeltaRecord clone() {
return copy();
}

@Override
public DeltaRecord copy() {
// immutable
return this;
}

+ 25
- 20
src/java/org/apache/poi/hssf/record/DimensionsRecord.java View File

@@ -15,41 +15,44 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Removal;

/**
* Title: Dimensions Record<P>
* Description: provides the minumum and maximum bounds
* of a sheet.<P>
* REFERENCE: PG 303 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
* Provides the minumum and maximum bounds of a sheet.
*
* @version 2.0-pre
*/

public final class DimensionsRecord extends StandardRecord implements Cloneable {
public final class DimensionsRecord extends StandardRecord {

private static final POILogger logger = POILogFactory.getLogger(DimensionsRecord.class);

public final static short sid = 0x200;
public static final short sid = 0x200;
private int field_1_first_row;
private int field_2_last_row; // plus 1
private short field_3_first_col;
private short field_4_last_col;
private short field_5_zero; // must be 0 (reserved)

public DimensionsRecord()
{
public DimensionsRecord() {}

public DimensionsRecord(DimensionsRecord other) {
super(other);
field_1_first_row = other.field_1_first_row;
field_2_last_row = other.field_2_last_row;
field_3_first_col = other.field_3_first_col;
field_4_last_col = other.field_4_last_col;
field_5_zero = other.field_5_zero;
}

public DimensionsRecord(RecordInputStream in)
{
public DimensionsRecord(RecordInputStream in) {
field_1_first_row = in.readInt();
field_2_last_row = in.readInt();
field_3_first_col = in.readShort();
@@ -179,13 +182,15 @@ public final class DimensionsRecord extends StandardRecord implements Cloneable
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public DimensionsRecord clone() {
DimensionsRecord rec = new DimensionsRecord();
rec.field_1_first_row = field_1_first_row;
rec.field_2_last_row = field_2_last_row;
rec.field_3_first_col = field_3_first_col;
rec.field_4_last_col = field_4_last_col;
rec.field_5_zero = field_5_zero;
return rec;
return copy();
}

@Override
public DimensionsRecord copy() {
return new DimensionsRecord(this);
}
}

+ 13
- 7
src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java View File

@@ -17,13 +17,13 @@

package org.apache.poi.hssf.record;

import java.util.Iterator;
import java.util.List;

import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.NullEscherSerializationListener;
import org.apache.poi.util.LittleEndian;

import java.util.Iterator;
import java.util.List;


public final class DrawingGroupRecord extends AbstractEscherHolderRecord {
public static final short sid = 0xEB;
@@ -31,12 +31,13 @@ public final class DrawingGroupRecord extends AbstractEscherHolderRecord {
static final int MAX_RECORD_SIZE = 8228;
private static final int MAX_DATA_SIZE = MAX_RECORD_SIZE - 4;

public DrawingGroupRecord()
{
public DrawingGroupRecord() {}

public DrawingGroupRecord(DrawingGroupRecord other) {
super(other);
}

public DrawingGroupRecord( RecordInputStream in )
{
public DrawingGroupRecord( RecordInputStream in ) {
super( in );
}

@@ -136,4 +137,9 @@ public final class DrawingGroupRecord extends AbstractEscherHolderRecord {
LittleEndian.putShort(data, 0 + offset, ContinueRecord.sid);
LittleEndian.putShort(data, 2 + offset, (short) sizeExcludingHeader);
}

@Override
public DrawingGroupRecord copy() {
return new DrawingGroupRecord(this);
}
}

+ 20
- 13
src/java/org/apache/poi/hssf/record/DrawingRecord.java View File

@@ -18,10 +18,9 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
/**
* DrawingRecord (0x00EC)
*/
public final class DrawingRecord extends StandardRecord implements Cloneable {
import org.apache.poi.util.Removal;

public final class DrawingRecord extends StandardRecord {
public static final short sid = 0x00EC;

private static final byte[] EMPTY_BYTE_ARRAY = {};
@@ -33,6 +32,13 @@ public final class DrawingRecord extends StandardRecord implements Cloneable {
recordData = EMPTY_BYTE_ARRAY;
}

public DrawingRecord(DrawingRecord other) {
super(other);
recordData = (other.recordData == null) ? null : other.recordData.clone();
// TODO - this code probably never copies a contd array ...
contd = (other.contd == null) ? null : other.contd.clone();
}

public DrawingRecord(RecordInputStream in) {
recordData = in.readRemainder();
}
@@ -69,20 +75,21 @@ public final class DrawingRecord extends StandardRecord implements Cloneable {
recordData = thedata;
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public DrawingRecord clone() {
return copy();
}

/**
* Cloning of drawing records must be executed through HSSFPatriarch, because all id's must be changed
* @return cloned drawing records
*/
@Override
public DrawingRecord clone() {
DrawingRecord rec = new DrawingRecord();
rec.recordData = recordData.clone();
if (contd != null) {
// TODO - this code probably never executes
rec.contd = contd.clone();
}

return rec;
public DrawingRecord copy() {
return new DrawingRecord(this);
}

@Override

+ 9
- 2
src/java/org/apache/poi/hssf/record/DrawingRecordForBiffViewer.java View File

@@ -26,8 +26,10 @@ import java.io.ByteArrayInputStream;
public final class DrawingRecordForBiffViewer extends AbstractEscherHolderRecord {
public static final short sid = 0xEC;

public DrawingRecordForBiffViewer()
{
public DrawingRecordForBiffViewer() {}

public DrawingRecordForBiffViewer(DrawingRecordForBiffViewer other) {
super(other);
}

public DrawingRecordForBiffViewer( RecordInputStream in)
@@ -59,4 +61,9 @@ public final class DrawingRecordForBiffViewer extends AbstractEscherHolderRecord
{
return sid;
}

@Override
public DrawingRecordForBiffViewer copy() {
return new DrawingRecordForBiffViewer(this);
}
}

+ 21
- 7
src/java/org/apache/poi/hssf/record/DrawingSelectionRecord.java View File

@@ -20,13 +20,14 @@ package org.apache.poi.hssf.record;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* MsoDrawingSelection (0x00ED)<p>
* Reference:
* [MS-OGRAPH].pdf sec 2.4.69
*/
public final class DrawingSelectionRecord extends StandardRecord implements Cloneable {
public final class DrawingSelectionRecord extends StandardRecord {
public static final short sid = 0x00ED;

/**
@@ -44,6 +45,12 @@ public final class DrawingSelectionRecord extends StandardRecord implements Clon
private final int _type;
private final int _length;

public OfficeArtRecordHeader(OfficeArtRecordHeader other) {
_verAndInstance = other._verAndInstance;
_type = other._type;
_length = other._length;
}

public OfficeArtRecordHeader(LittleEndianInput in) {
_verAndInstance = in.readUShort();
_type = in.readUShort();
@@ -57,11 +64,10 @@ public final class DrawingSelectionRecord extends StandardRecord implements Clon
}

public String debugFormatAsString() {
StringBuilder sb = new StringBuilder(32);
sb.append("ver+inst=").append(HexDump.shortToHex(_verAndInstance));
sb.append(" type=").append(HexDump.shortToHex(_type));
sb.append(" len=").append(HexDump.intToHex(_length));
return sb.toString();
return
"ver+inst=" + HexDump.shortToHex(_verAndInstance) +
" type=" + HexDump.shortToHex(_type) +
" len=" + HexDump.intToHex(_length);
}
}

@@ -93,7 +99,7 @@ public final class DrawingSelectionRecord extends StandardRecord implements Clon
}

protected int getDataSize() {
return OfficeArtRecordHeader.ENCODED_SIZE
return OfficeArtRecordHeader.ENCODED_SIZE
+ 12 // 3 int fields
+ _shapeIds.length * 4;
}
@@ -109,7 +115,15 @@ public final class DrawingSelectionRecord extends StandardRecord implements Clon
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public DrawingSelectionRecord clone() {
return copy();
}

@Override
public DrawingSelectionRecord copy() {
// currently immutable
return this;
}

+ 16
- 16
src/java/org/apache/poi/hssf/record/EOFRecord.java View File

@@ -18,33 +18,25 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* End Of File record.
* <P>
* Description: Marks the end of records belonging to a particular object in the
* HSSF File<P>
* REFERENCE: PG 307 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
* Marks the end of records belonging to a particular object in the HSSF File
*
* @version 2.0-pre
*/
public final class EOFRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x0A;
public final class EOFRecord extends StandardRecord {
public static final short sid = 0x0A;
public static final int ENCODED_SIZE = 4;

public static final EOFRecord instance = new EOFRecord();
private EOFRecord() {
// no data fields
}

private EOFRecord() {}

/**
* @param in unused (since this record has no data)
*/
public EOFRecord(RecordInputStream in)
{
}
public EOFRecord(RecordInputStream in) {}

public String toString()
{
@@ -68,7 +60,15 @@ public final class EOFRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public EOFRecord clone() {
return copy();
}

@Override
public EOFRecord copy() {
return instance;
}
}

+ 28
- 7
src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java View File

@@ -33,6 +33,7 @@ import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;
import org.apache.poi.util.StringUtil;

/**
@@ -40,7 +41,7 @@ import org.apache.poi.util.StringUtil;
* A sub-record within the OBJ record which stores a reference to an object
* stored in a separate entry within the OLE2 compound file.
*/
public final class EmbeddedObjectRefSubRecord extends SubRecord implements Cloneable {
public final class EmbeddedObjectRefSubRecord extends SubRecord {
private static POILogger logger = POILogFactory.getLogger(EmbeddedObjectRefSubRecord.class);
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
@@ -73,8 +74,16 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord implements Clone
field_4_ole_classname = null;
}

public short getSid() {
return sid;
public EmbeddedObjectRefSubRecord(EmbeddedObjectRefSubRecord other) {
super(other);
field_1_unknown_int = other.field_1_unknown_int;
field_2_refPtg = (other.field_2_refPtg == null) ? null : other.field_2_refPtg.copy();
field_2_unknownFormulaData = (other.field_2_unknownFormulaData == null) ? null : other.field_2_unknownFormulaData.clone();
field_3_unicode_flag = other.field_3_unicode_flag;
field_4_ole_classname = other.field_4_ole_classname;
field_4_unknownByte = other.field_4_unknownByte;
field_5_stream_id = other.field_5_stream_id;
field_6_unknown = (other.field_6_unknown == null) ? null : other.field_6_unknown.clone();
}

public EmbeddedObjectRefSubRecord(LittleEndianInput in, int size) {
@@ -158,6 +167,10 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord implements Clone
field_6_unknown = readRawData(in, remaining);
}

public short getSid() {
return sid;
}

private static Ptg readRefPtg(byte[] formulaRawBytes) {
LittleEndianInput in = new LittleEndianInputStream(new ByteArrayInputStream(formulaRawBytes));
byte ptgSid = in.readByte();
@@ -310,8 +323,16 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord implements Clone
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public EmbeddedObjectRefSubRecord clone() {
return this; // TODO proper clone
return copy();
}

@Override
public EmbeddedObjectRefSubRecord copy() {
return new EmbeddedObjectRefSubRecord(this);
}

public String toString() {
@@ -339,15 +360,15 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord implements Clone
sb.append("[/ftPictFmla]");
return sb.toString();
}
public void setUnknownFormulaData(byte[] formularData) {
field_2_unknownFormulaData = formularData;
}
public void setOleClassname(String oleClassname) {
field_4_ole_classname = oleClassname;
}
public void setStorageId(int storageId) {
field_5_stream_id = storageId;
}

+ 13
- 8
src/java/org/apache/poi/hssf/record/EndSubRecord.java View File

@@ -14,27 +14,25 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;

/**
* ftEnd (0x0000)<p>
*
*
* The end data record is used to denote the end of the subrecords.
*/
public final class EndSubRecord extends SubRecord implements Cloneable {
public final class EndSubRecord extends SubRecord {
// Note - zero sid is somewhat unusual (compared to plain Records)
public final static short sid = 0x0000;
public static final short sid = 0x0000;
private static final int ENCODED_SIZE = 0;

public EndSubRecord()
{

}
public EndSubRecord() {}

/**
* @param in unused (since this record has no data)
@@ -76,8 +74,15 @@ public final class EndSubRecord extends SubRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public EndSubRecord clone() {
return copy();
}

@Override
public EndSubRecord copy() {
return new EndSubRecord();
}
}

+ 13
- 1
src/java/org/apache/poi/hssf/record/EscherAggregate.java View File

@@ -85,7 +85,7 @@ import org.apache.poi.util.RecordFormatException;

public final class EscherAggregate extends AbstractEscherHolderRecord {
public static final short sid = 9876; // not a real sid - dummy value
private static POILogger log = POILogFactory.getLogger(EscherAggregate.class);
private static final POILogger log = POILogFactory.getLogger(EscherAggregate.class);
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000_000;

@@ -317,6 +317,13 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
}
}

public EscherAggregate(EscherAggregate other) {
super(other);
// shallow copy, because the aggregates doesn't own the records
shapeToObj.putAll(other.shapeToObj);
tailRec.putAll(other.tailRec);
}

/**
* @return Returns the current sid.
*/
@@ -814,4 +821,9 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
public void removeTailRecord(NoteRecord note) {
tailRec.remove(note.getShapeId());
}

@Override
public EscherAggregate copy() {
return new EscherAggregate(this);
}
}

+ 32
- 16
src/java/org/apache/poi/hssf/record/ExtSSTRecord.java View File

@@ -17,28 +17,27 @@

package org.apache.poi.hssf.record;

import java.util.ArrayList;
import java.util.stream.Stream;

import org.apache.poi.hssf.record.cont.ContinuableRecord;
import org.apache.poi.hssf.record.cont.ContinuableRecordOutput;
import org.apache.poi.util.LittleEndianOutput;

import java.util.ArrayList;

/**
* Title: Extended Static String Table (0x00FF)<p>
* Description: This record is used for a quick lookup into the SST record. This
* record breaks the SST table into a set of buckets. The offsets
* to these buckets within the SST record are kept as well as the
* position relative to the start of the SST record.<p>
* REFERENCE: PG 313 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Extended Static String Table (0x00FF)<p>
* This record is used for a quick lookup into the SST record. This record breaks the SST table
* into a set of buckets. The offsets to these buckets within the SST record are kept as well as
* the position relative to the start of the SST record.
*/
public final class ExtSSTRecord extends ContinuableRecord {
public final static short sid = 0x00FF;
public static final short sid = 0x00FF;
public static final int DEFAULT_BUCKET_SIZE = 8;
//Can't seem to find this documented but from the biffviewer it is clear that
//Excel only records the indexes for the first 128 buckets.
public static final int MAX_BUCKETS = 128;
public static final class InfoSubRecord {
public static final int ENCODED_SIZE = 8;
private int field_1_stream_pos; // stream pointer to the SST record
@@ -48,7 +47,7 @@ public final class ExtSSTRecord extends ContinuableRecord {

/**
* Creates new ExtSSTInfoSubRecord
*
*
* @param streamPos stream pointer to the SST record
* @param bucketSstOffset ... don't really understand this yet
*/
@@ -57,6 +56,12 @@ public final class ExtSSTRecord extends ContinuableRecord {
field_2_bucket_sst_offset = bucketSstOffset;
}

public InfoSubRecord(InfoSubRecord other) {
field_1_stream_pos = other.field_1_stream_pos;
field_2_bucket_sst_offset = other.field_2_bucket_sst_offset;
field_3_zero = other.field_3_zero;
}

public InfoSubRecord(RecordInputStream in)
{
field_1_stream_pos = in.readInt();
@@ -78,8 +83,8 @@ public final class ExtSSTRecord extends ContinuableRecord {
out.writeShort(field_3_zero);
}
}
private short _stringsPerBucket;
private InfoSubRecord[] _sstInfos;

@@ -89,6 +94,12 @@ public final class ExtSSTRecord extends ContinuableRecord {
_sstInfos = new InfoSubRecord[0];
}

public ExtSSTRecord(ExtSSTRecord other) {
_stringsPerBucket = other._stringsPerBucket;
_sstInfos = (other._sstInfos == null) ? null
: Stream.of(other._sstInfos).map(InfoSubRecord::new).toArray(InfoSubRecord[]::new);
}

public ExtSSTRecord(RecordInputStream in) {
_stringsPerBucket = in.readShort();

@@ -161,9 +172,9 @@ public final class ExtSSTRecord extends ContinuableRecord {

/**
* Given a number of strings (in the sst), returns the size of the extsst record
*
*
* @param numStrings the number of strings
*
*
* @return the size of the extsst record
*/
public static int getRecordSizeForStrings(int numStrings) {
@@ -181,4 +192,9 @@ public final class ExtSSTRecord extends ContinuableRecord {
_sstInfos[i] = new InfoSubRecord(bucketAbsoluteOffsets[i], bucketRelativeOffsets[i]);
}
}

@Override
public ExtSSTRecord copy() {
return new ExtSSTRecord(this);
}
}

+ 130
- 141
src/java/org/apache/poi/hssf/record/ExtendedFormatRecord.java View File

@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

@@ -23,179 +23,164 @@ import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Extended Format Record
* Description: Probably one of the more complex records. There are two breeds:
* Style and Cell.
*<P>
* It should be noted that fields in the extended format record are
* somewhat arbitrary. Almost all of the fields are bit-level, but
* we name them as best as possible by functional group. In some
* places this is better than others.
*<P>
* Probably one of the more complex records.<p>
* There are two breeds: Style and Cell.<p>
* It should be noted that fields in the extended format record are somewhat arbitrary.
* Almost all of the fields are bit-level, but we name them as best as possible by functional group.
* In some places this is better than others.
*
* REFERENCE: PG 426 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @since 2.0-pre
*/

public final class ExtendedFormatRecord
extends StandardRecord
{
public static final short sid = 0xE0;
public final class ExtendedFormatRecord extends StandardRecord {
public static final short sid = 0xE0;

// null constant
public static final short NULL = (short)0xfff0;
public static final short NULL = (short)0xfff0;

// xf type
public static final short XF_STYLE = 1;
public static final short XF_CELL = 0;
public static final short XF_STYLE = 1;
public static final short XF_CELL = 0;

// borders
public static final short NONE = 0x0;
public static final short THIN = 0x1;
public static final short MEDIUM = 0x2;
public static final short DASHED = 0x3;
public static final short DOTTED = 0x4;
public static final short THICK = 0x5;
public static final short DOUBLE = 0x6;
public static final short HAIR = 0x7;
public static final short MEDIUM_DASHED = 0x8;
public static final short DASH_DOT = 0x9;
public static final short MEDIUM_DASH_DOT = 0xA;
public static final short DASH_DOT_DOT = 0xB;
public static final short MEDIUM_DASH_DOT_DOT = 0xC;
public static final short SLANTED_DASH_DOT = 0xD;
public static final short NONE = 0x0;
public static final short THIN = 0x1;
public static final short MEDIUM = 0x2;
public static final short DASHED = 0x3;
public static final short DOTTED = 0x4;
public static final short THICK = 0x5;
public static final short DOUBLE = 0x6;
public static final short HAIR = 0x7;
public static final short MEDIUM_DASHED = 0x8;
public static final short DASH_DOT = 0x9;
public static final short MEDIUM_DASH_DOT = 0xA;
public static final short DASH_DOT_DOT = 0xB;
public static final short MEDIUM_DASH_DOT_DOT = 0xC;
public static final short SLANTED_DASH_DOT = 0xD;

// alignment
public static final short GENERAL = 0x0;
public static final short LEFT = 0x1;
public static final short CENTER = 0x2;
public static final short RIGHT = 0x3;
public static final short FILL = 0x4;
public static final short JUSTIFY = 0x5;
public static final short CENTER_SELECTION = 0x6;
public static final short GENERAL = 0x0;
public static final short LEFT = 0x1;
public static final short CENTER = 0x2;
public static final short RIGHT = 0x3;
public static final short FILL = 0x4;
public static final short JUSTIFY = 0x5;
public static final short CENTER_SELECTION = 0x6;

// vertical alignment
public static final short VERTICAL_TOP = 0x0;
public static final short VERTICAL_CENTER = 0x1;
public static final short VERTICAL_BOTTOM = 0x2;
public static final short VERTICAL_JUSTIFY = 0x3;
public static final short VERTICAL_TOP = 0x0;
public static final short VERTICAL_CENTER = 0x1;
public static final short VERTICAL_BOTTOM = 0x2;
public static final short VERTICAL_JUSTIFY = 0x3;

// fill
public static final short NO_FILL = 0 ;
public static final short SOLID_FILL = 1 ;
public static final short FINE_DOTS = 2 ;
public static final short ALT_BARS = 3 ;
public static final short SPARSE_DOTS = 4 ;
public static final short THICK_HORZ_BANDS = 5 ;
public static final short THICK_VERT_BANDS = 6 ;
public static final short THICK_BACKWARD_DIAG = 7 ;
public static final short THICK_FORWARD_DIAG = 8 ;
public static final short BIG_SPOTS = 9 ;
public static final short BRICKS = 10 ;
public static final short THIN_HORZ_BANDS = 11 ;
public static final short THIN_VERT_BANDS = 12 ;
public static final short THIN_BACKWARD_DIAG = 13 ;
public static final short THIN_FORWARD_DIAG = 14 ;
public static final short SQUARES = 15 ;
public static final short DIAMONDS = 16 ;

// fields in BOTH style and Cell XF records
private short field_1_font_index; // not bit-mapped
private short field_2_format_index; // not bit-mapped
public static final short NO_FILL = 0;
public static final short SOLID_FILL = 1;
public static final short FINE_DOTS = 2;
public static final short ALT_BARS = 3;
public static final short SPARSE_DOTS = 4;
public static final short THICK_HORZ_BANDS = 5;
public static final short THICK_VERT_BANDS = 6;
public static final short THICK_BACKWARD_DIAG = 7;
public static final short THICK_FORWARD_DIAG = 8;
public static final short BIG_SPOTS = 9;
public static final short BRICKS = 10;
public static final short THIN_HORZ_BANDS = 11;
public static final short THIN_VERT_BANDS = 12;
public static final short THIN_BACKWARD_DIAG = 13;
public static final short THIN_FORWARD_DIAG = 14;
public static final short SQUARES = 15;
public static final short DIAMONDS = 16;

// field_3_cell_options bit map
private static final BitField _locked = BitFieldFactory.getInstance(0x0001);
private static final BitField _hidden = BitFieldFactory.getInstance(0x0002);
private static final BitField _xf_type = BitFieldFactory.getInstance(0x0004);
private static final BitField _123_prefix = BitFieldFactory.getInstance(0x0008);
private static final BitField _parent_index = BitFieldFactory.getInstance(0xFFF0);
private short field_3_cell_options;
private static final BitField _locked = bf(0x0001);
private static final BitField _hidden = bf(0x0002);
private static final BitField _xf_type = bf(0x0004);
private static final BitField _123_prefix = bf(0x0008);
private static final BitField _parent_index = bf(0xFFF0);

// field_4_alignment_options bit map
private static final BitField _alignment = BitFieldFactory.getInstance(0x0007);
private static final BitField _wrap_text = BitFieldFactory.getInstance(0x0008);
private static final BitField _vertical_alignment = BitFieldFactory.getInstance(0x0070);
private static final BitField _justify_last = BitFieldFactory.getInstance(0x0080);
private static final BitField _rotation = BitFieldFactory.getInstance(0xFF00);
private short field_4_alignment_options;
private static final BitField _alignment = bf(0x0007);
private static final BitField _wrap_text = bf(0x0008);
private static final BitField _vertical_alignment = bf(0x0070);
private static final BitField _justify_last = bf(0x0080);
private static final BitField _rotation = bf(0xFF00);

// field_5_indention_options
private static final BitField _indent =
BitFieldFactory.getInstance(0x000F);
private static final BitField _shrink_to_fit =
BitFieldFactory.getInstance(0x0010);
private static final BitField _merge_cells =
BitFieldFactory.getInstance(0x0020);
private static final BitField _reading_order =
BitFieldFactory.getInstance(0x00C0);
private static final BitField _indent = bf(0x000F);
private static final BitField _shrink_to_fit = bf(0x0010);
private static final BitField _merge_cells = bf(0x0020);
private static final BitField _reading_order = bf(0x00C0);

// apparently bits 8 and 9 are unused
private static final BitField _indent_not_parent_format =
BitFieldFactory.getInstance(0x0400);
private static final BitField _indent_not_parent_font =
BitFieldFactory.getInstance(0x0800);
private static final BitField _indent_not_parent_alignment =
BitFieldFactory.getInstance(0x1000);
private static final BitField _indent_not_parent_border =
BitFieldFactory.getInstance(0x2000);
private static final BitField _indent_not_parent_pattern =
BitFieldFactory.getInstance(0x4000);
private static final BitField _indent_not_parent_cell_options =
BitFieldFactory.getInstance(0x8000);
private short field_5_indention_options;
private static final BitField _indent_not_parent_format = bf(0x0400);
private static final BitField _indent_not_parent_font = bf(0x0800);
private static final BitField _indent_not_parent_alignment = bf(0x1000);
private static final BitField _indent_not_parent_border = bf(0x2000);
private static final BitField _indent_not_parent_pattern = bf(0x4000);
private static final BitField _indent_not_parent_cell_options = bf(0x8000);

// field_6_border_options bit map
private static final BitField _border_left = BitFieldFactory.getInstance(0x000F);
private static final BitField _border_right = BitFieldFactory.getInstance(0x00F0);
private static final BitField _border_top = BitFieldFactory.getInstance(0x0F00);
private static final BitField _border_bottom = BitFieldFactory.getInstance(0xF000);
private short field_6_border_options;
private static final BitField _border_left = bf(0x000F);
private static final BitField _border_right = bf(0x00F0);
private static final BitField _border_top = bf(0x0F00);
private static final BitField _border_bottom = bf(0xF000);

// all three of the following attributes are palette options
// field_7_palette_options bit map
private static final BitField _left_border_palette_idx =
BitFieldFactory.getInstance(0x007F);
private static final BitField _right_border_palette_idx =
BitFieldFactory.getInstance(0x3F80);
private static final BitField _diag =
BitFieldFactory.getInstance(0xC000);
private short field_7_palette_options;
private static final BitField _left_border_palette_idx = bf(0x007F);
private static final BitField _right_border_palette_idx = bf(0x3F80);
private static final BitField _diag = bf(0xC000);

// field_8_adtl_palette_options bit map
private static final BitField _top_border_palette_idx =
BitFieldFactory.getInstance(0x0000007F);
private static final BitField _bottom_border_palette_idx =
BitFieldFactory.getInstance(0x00003F80);
private static final BitField _adtl_diag =
BitFieldFactory.getInstance(0x001fc000);
private static final BitField _adtl_diag_line_style =
BitFieldFactory.getInstance(0x01e00000);
private static final BitField _top_border_palette_idx = bf(0x0000007F);
private static final BitField _bottom_border_palette_idx = bf(0x00003F80);
private static final BitField _adtl_diag = bf(0x001fc000);
private static final BitField _adtl_diag_line_style = bf(0x01e00000);

// apparently bit 25 is unused
private static final BitField _adtl_fill_pattern =
BitFieldFactory.getInstance(0xfc000000);
private int field_8_adtl_palette_options; // additional to avoid 2
private static final BitField _adtl_fill_pattern = bf(0xfc000000);

// field_9_fill_palette_options bit map
private static final BitField _fill_foreground = BitFieldFactory.getInstance(0x007F);
private static final BitField _fill_background = BitFieldFactory.getInstance(0x3f80);
private static final BitField _fill_foreground = bf(0x007F);
private static final BitField _fill_background = bf(0x3f80);

private static BitField bf(int i) {
return BitFieldFactory.getInstance(i);
}


// fields in BOTH style and Cell XF records
private short field_1_font_index; // not bit-mapped
private short field_2_format_index; // not bit-mapped

private short field_3_cell_options;
private short field_4_alignment_options;
private short field_5_indention_options;
private short field_6_border_options;
private short field_7_palette_options;
private int field_8_adtl_palette_options; // additional to avoid 2


// apparently bits 15 and 14 are unused
private short field_9_fill_palette_options;
private short field_9_fill_palette_options;

/**
* Constructor ExtendedFormatRecord
*
*
*/
public ExtendedFormatRecord() {}

public ExtendedFormatRecord()
{
public ExtendedFormatRecord(ExtendedFormatRecord other) {
super(other);
field_1_font_index = other.field_1_font_index;
field_2_format_index = other.field_2_format_index;
field_3_cell_options = other.field_3_cell_options;
field_4_alignment_options = other.field_4_alignment_options;
field_5_indention_options = other.field_5_indention_options;
field_6_border_options = other.field_6_border_options;
field_7_palette_options = other.field_7_palette_options;
field_8_adtl_palette_options = other.field_8_adtl_palette_options;
field_9_fill_palette_options = other.field_9_fill_palette_options;
}

public ExtendedFormatRecord(RecordInputStream in)
{
public ExtendedFormatRecord(RecordInputStream in) {
field_1_font_index = in.readShort();
field_2_format_index = in.readShort();
field_3_cell_options = in.readShort();
@@ -560,7 +545,7 @@ public final class ExtendedFormatRecord
/**
* <p>Sets whether or not to use the pattern in this XF instead of the
* parent XF (foreground/background).</p>
*
*
* @param pattern {@code true} if this XF has a different pattern
* value than its parent, {@code false} otherwise.
* @see #setIndentionOptions(short)
@@ -1788,16 +1773,16 @@ public final class ExtendedFormatRecord
{
return sid;
}
/**
* Clones all the style information from another
* ExtendedFormatRecord, onto this one. This
* ExtendedFormatRecord, onto this one. This
* will then hold all the same style options.
*
*
* If The source ExtendedFormatRecord comes from
* a different Workbook, you will need to sort
* out the font and format indices yourself!
*
*
* @param source the ExtendedFormatRecord to copy from
*/
public void cloneStyleFrom(ExtendedFormatRecord source) {
@@ -1863,11 +1848,15 @@ public final class ExtendedFormatRecord
}
return false;
}
public int[] stateSummary() {
return new int[] { field_1_font_index, field_2_format_index, field_3_cell_options, field_4_alignment_options,
field_5_indention_options, field_6_border_options, field_7_palette_options, field_8_adtl_palette_options, field_9_fill_palette_options };
}


@Override
public ExtendedFormatRecord copy() {
return new ExtendedFormatRecord(this);
}
}

+ 55
- 47
src/java/org/apache/poi/hssf/record/ExternSheetRecord.java View File

@@ -28,9 +28,9 @@ import org.apache.poi.util.LittleEndianOutput;
*/
public class ExternSheetRecord extends StandardRecord {

public final static short sid = 0x0017;
private final List<RefSubRecord> _list;
public static final short sid = 0x0017;
private final List<RefSubRecord> _list = new ArrayList<>();
private static final class RefSubRecord {
public static final int ENCODED_SIZE = 6;

@@ -38,26 +38,31 @@ public class ExternSheetRecord extends StandardRecord {
private final int _extBookIndex;
private int _firstSheetIndex; // may be -1 (0xFFFF)
private int _lastSheetIndex; // may be -1 (0xFFFF)
public void adjustIndex(int offset) {
_firstSheetIndex += offset;
_lastSheetIndex += offset;
}
/** a Constructor for making new sub record
*/

public RefSubRecord(int extBookIndex, int firstSheetIndex, int lastSheetIndex) {
_extBookIndex = extBookIndex;
_firstSheetIndex = firstSheetIndex;
_lastSheetIndex = lastSheetIndex;
}

public RefSubRecord(RefSubRecord other) {
_extBookIndex = other._extBookIndex;
_firstSheetIndex = other._firstSheetIndex;
_lastSheetIndex = other._lastSheetIndex;
}

/**
* @param in the RecordInputstream to read the record from
*/
public RefSubRecord(RecordInputStream in) {
this(in.readShort(), in.readShort(), in.readShort());
}

public void adjustIndex(int offset) {
_firstSheetIndex += offset;
_lastSheetIndex += offset;
}

public int getExtBookIndex(){
return _extBookIndex;
}
@@ -67,7 +72,7 @@ public class ExternSheetRecord extends StandardRecord {
public int getLastSheetIndex(){
return _lastSheetIndex;
}
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
@@ -76,55 +81,53 @@ public class ExternSheetRecord extends StandardRecord {
buffer.append(" lastSheet=").append(_lastSheetIndex);
return buffer.toString();
}
public void serialize(LittleEndianOutput out) {
out.writeShort(_extBookIndex);
out.writeShort(_firstSheetIndex);
out.writeShort(_lastSheetIndex);
}
}
public ExternSheetRecord() {
_list = new ArrayList<>();
}
public ExternSheetRecord() {}
public ExternSheetRecord(ExternSheetRecord other) {
other._list.stream().map(RefSubRecord::new).forEach(_list::add);
}

public ExternSheetRecord(RecordInputStream in) {
_list = new ArrayList<>();
int nItems = in.readShort();

for (int i = 0 ; i < nItems ; ++i) {
RefSubRecord rec = new RefSubRecord(in);
_list.add(rec);
}
}

/**

/**
* @return number of REF structures
*/
public int getNumOfRefs() {
return _list.size();
}
/**
/**
* adds REF struct (ExternSheetSubRecord)
* @param rec REF struct
*/
public void addREFRecord(RefSubRecord rec) {
_list.add(rec);
}
/** returns the number of REF Records, which is in model
* @return number of REF records
*/
public int getNumOfREFRecords() {
return _list.size();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -137,22 +140,22 @@ public class ExternSheetRecord extends StandardRecord {
sb.append('\n');
}
sb.append("[/EXTERNSHEET]\n");
return sb.toString();
}
@Override
protected int getDataSize() {
return 2 + _list.size() * RefSubRecord.ENCODED_SIZE;
}
@Override
public void serialize(LittleEndianOutput out) {
int nItems = _list.size();

out.writeShort(nItems);
for (int i = 0; i < nItems; i++) {
getRef(i).serialize(out);
}
@@ -161,22 +164,22 @@ public class ExternSheetRecord extends StandardRecord {
private RefSubRecord getRef(int i) {
return _list.get(i);
}
public void removeSheet(int sheetIdx) {
int nItems = _list.size();
for (int i = 0; i < nItems; i++) {
RefSubRecord refSubRecord = _list.get(i);
if(refSubRecord.getFirstSheetIndex() == sheetIdx &&
if(refSubRecord.getFirstSheetIndex() == sheetIdx &&
refSubRecord.getLastSheetIndex() == sheetIdx) {
// removing the entry would mess up the sheet index in Formula of NameRecord
_list.set(i, new RefSubRecord(refSubRecord.getExtBookIndex(), -1, -1));
} else if (refSubRecord.getFirstSheetIndex() > sheetIdx &&
} else if (refSubRecord.getFirstSheetIndex() > sheetIdx &&
refSubRecord.getLastSheetIndex() > sheetIdx) {
_list.set(i, new RefSubRecord(refSubRecord.getExtBookIndex(), refSubRecord.getFirstSheetIndex()-1, refSubRecord.getLastSheetIndex()-1));
}
}
}
/**
* return the non static version of the id for this record.
*/
@@ -187,7 +190,7 @@ public class ExternSheetRecord extends StandardRecord {

/**
* @param refIndex specifies the n-th refIndex
*
*
* @return the index of the SupBookRecord for this index
*/
public int getExtbookIndexFromRefIndex(int refIndex) {
@@ -197,7 +200,7 @@ public class ExternSheetRecord extends StandardRecord {

/**
* @param extBookIndex external sheet reference index
*
*
* @return -1 if not found
*/
public int findRefIndexFromExtBookIndex(int extBookIndex) {
@@ -214,9 +217,9 @@ public class ExternSheetRecord extends StandardRecord {
* Returns the first sheet that the reference applies to, or
* -1 if the referenced sheet can't be found, or -2 if the
* reference is workbook scoped.
*
*
* @param extRefIndex external sheet reference index
*
*
* @return the first sheet that the reference applies to, or
* -1 if the referenced sheet can't be found, or -2 if the
* reference is workbook scoped
@@ -231,9 +234,9 @@ public class ExternSheetRecord extends StandardRecord {
* reference is workbook scoped.
* For a single sheet reference, the first and last should be
* the same.
*
*
* @param extRefIndex external sheet reference index
*
*
* @return the last sheet that the reference applies to, or
* -1 if the referenced sheet can't be found, or -2 if the
* reference is workbook scoped.
@@ -258,7 +261,7 @@ public class ExternSheetRecord extends StandardRecord {
* see {@link org.apache.poi.hssf.record.SupBookRecord#getSheetNames()}.
* This referenced string specifies the name of the first sheet within the external workbook that is in scope.
* This sheet MUST be a worksheet or macro sheet.</p>
*
*
* <p>If the supporting link type is self-referencing, then this value specifies the zero-based index of a
* {@link org.apache.poi.hssf.record.BoundSheetRecord} record in the workbook stream that specifies
* the first sheet within the scope of this reference. This sheet MUST be a worksheet or a macro sheet.
@@ -283,7 +286,7 @@ public class ExternSheetRecord extends StandardRecord {
if (ref.getExtBookIndex() != externalBookIndex) {
continue;
}
if (ref.getFirstSheetIndex() == firstSheetIndex &&
if (ref.getFirstSheetIndex() == firstSheetIndex &&
ref.getLastSheetIndex() == lastSheetIndex) {
return i;
}
@@ -301,4 +304,9 @@ public class ExternSheetRecord extends StandardRecord {
}
return result;
}

@Override
public ExternSheetRecord copy() {
return new ExternSheetRecord(this);
}
}

+ 65
- 48
src/java/org/apache/poi/hssf/record/ExternalNameRecord.java View File

@@ -28,7 +28,7 @@ import org.apache.poi.util.StringUtil;
*/
public final class ExternalNameRecord extends StandardRecord {

public final static short sid = 0x0023; // as per BIFF8. (some old versions used 0x223)
public static final short sid = 0x0023; // as per BIFF8. (some old versions used 0x223)

private static final int OPT_BUILTIN_NAME = 0x0001;
private static final int OPT_AUTOMATIC_LINK = 0x0002; // m$ doc calls this fWantAdvise
@@ -39,11 +39,11 @@ public final class ExternalNameRecord extends StandardRecord {
private static final int OPT_ICONIFIED_PICTURE_LINK= 0x8000;


private short field_1_option_flag;
private short field_2_ixals;
private short field_3_not_used;
private short field_1_option_flag;
private short field_2_ixals;
private short field_3_not_used;
private String field_4_name;
private Formula field_5_name_definition;
private Formula field_5_name_definition;

/**
* 'rgoper' / 'Last received results of the DDE link'
@@ -60,6 +60,54 @@ public final class ExternalNameRecord extends StandardRecord {
*/
private int _nRows;

public ExternalNameRecord() {
field_2_ixals = 0;
}

public ExternalNameRecord(ExternalNameRecord other) {
super(other);
field_1_option_flag = other.field_1_option_flag;
field_2_ixals = other.field_2_ixals;
field_3_not_used = other.field_3_not_used;
field_4_name = other.field_4_name;
field_5_name_definition = (other.field_5_name_definition == null) ? null : other.field_5_name_definition.copy();
_ddeValues = (other._ddeValues == null) ? null : other._ddeValues.clone();
_nColumns = other._nColumns;
_nRows = other._nRows;
}

public ExternalNameRecord(RecordInputStream in) {
field_1_option_flag = in.readShort();
field_2_ixals = in.readShort();
field_3_not_used = in.readShort();

int numChars = in.readUByte();
field_4_name = StringUtil.readUnicodeString(in, numChars);

// the record body can take different forms.
// The form is dictated by the values of 3-th and 4-th bits in field_1_option_flag
if(!isOLELink() && !isStdDocumentNameIdentifier()){
// another switch: the fWantAdvise bit specifies whether the body describes
// an external defined name or a DDE data item
if(isAutomaticLink()){
if(in.available() > 0) {
//body specifies DDE data item
int nColumns = in.readUByte() + 1;
int nRows = in.readShort() + 1;

int totalCount = nRows * nColumns;
_ddeValues = ConstantValueParser.parse(in, totalCount);
_nColumns = nColumns;
_nRows = nRows;
}
} else {
//body specifies an external defined name
int formulaLen = in.readUShort();
field_5_name_definition = Formula.read(formulaLen, in);
}
}
}

/**
* @return {@code true} if the name is a built-in name
*/
@@ -68,7 +116,7 @@ public final class ExternalNameRecord extends StandardRecord {
}
/**
* For OLE and DDE, links can be either 'automatic' or 'manual'
*
*
* @return {@code true} if this is a automatic link
*/
public boolean isAutomaticLink() {
@@ -76,7 +124,7 @@ public final class ExternalNameRecord extends StandardRecord {
}
/**
* only for OLE and DDE
*
*
* @return {@code true} if this is a picture link
*/
public boolean isPicureLink() {
@@ -84,7 +132,7 @@ public final class ExternalNameRecord extends StandardRecord {
}
/**
* DDE links only. If <code>true</code>, this denotes the 'StdDocumentName'
*
*
* @return {@code true} if this denotes the 'StdDocumentName'
*/
public boolean isStdDocumentNameIdentifier() {
@@ -102,7 +150,7 @@ public final class ExternalNameRecord extends StandardRecord {
public String getText() {
return field_4_name;
}
public void setText(String str) {
field_4_name = str;
}
@@ -112,13 +160,13 @@ public final class ExternalNameRecord extends StandardRecord {
* index of the name of the Sheet this refers to, as
* defined in the preceding {@link SupBookRecord}.
* If it isn't a local name, then it must be zero.
*
*
* @return the index of the name of the Sheet this refers to
*/
public short getIx() {
return field_2_ixals;
}
public void setIx(short ix) {
field_2_ixals = ix;
}
@@ -134,7 +182,7 @@ public final class ExternalNameRecord extends StandardRecord {
@Override
protected int getDataSize(){
int result = 2 + 4; // short and int
result += StringUtil.getEncodedSize(field_4_name) - 1; //size is byte, not short
result += StringUtil.getEncodedSize(field_4_name) - 1; //size is byte, not short

if(!isOLELink() && !isStdDocumentNameIdentifier()){
if(isAutomaticLink()){
@@ -171,42 +219,6 @@ public final class ExternalNameRecord extends StandardRecord {
}
}

public ExternalNameRecord() {
field_2_ixals = 0;
}
public ExternalNameRecord(RecordInputStream in) {
field_1_option_flag = in.readShort();
field_2_ixals = in.readShort();
field_3_not_used = in.readShort();

int numChars = in.readUByte();
field_4_name = StringUtil.readUnicodeString(in, numChars);

// the record body can take different forms.
// The form is dictated by the values of 3-th and 4-th bits in field_1_option_flag
if(!isOLELink() && !isStdDocumentNameIdentifier()){
// another switch: the fWantAdvise bit specifies whether the body describes
// an external defined name or a DDE data item
if(isAutomaticLink()){
if(in.available() > 0) {
//body specifies DDE data item
int nColumns = in.readUByte() + 1;
int nRows = in.readShort() + 1;
int totalCount = nRows * nColumns;
_ddeValues = ConstantValueParser.parse(in, totalCount);
_nColumns = nColumns;
_nRows = nRows;
}
} else {
//body specifies an external defined name
int formulaLen = in.readUShort();
field_5_name_definition = Formula.read(formulaLen, in);
}
}
}

@Override
public short getSid() {
return sid;
@@ -228,4 +240,9 @@ public final class ExternalNameRecord extends StandardRecord {
sb.append("[/EXTERNALNAME]\n");
return sb.toString();
}

@Override
public ExternalNameRecord copy() {
return new ExternalNameRecord(this);
}
}

+ 40
- 22
src/java/org/apache/poi/hssf/record/FeatHdrRecord.java View File

@@ -19,29 +19,30 @@ package org.apache.poi.hssf.record;

import org.apache.poi.hssf.record.common.FtrHeader;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: FeatHdr (Feature Header) Record
* <P>
* This record specifies common information for Shared Features, and
* specifies the beginning of a collection of records to define them.
* The collection of data (Globals Substream ABNF, macro sheet substream
* This record specifies common information for Shared Features, and
* specifies the beginning of a collection of records to define them.
* The collection of data (Globals Substream ABNF, macro sheet substream
* ABNF or worksheet substream ABNF) specifies Shared Feature data.
*/
public final class FeatHdrRecord extends StandardRecord implements Cloneable {
public final class FeatHdrRecord extends StandardRecord {
/**
* Specifies the enhanced protection type. Used to protect a
* shared workbook by restricting access to some areas of it
* Specifies the enhanced protection type. Used to protect a
* shared workbook by restricting access to some areas of it
*/
public static final int SHAREDFEATURES_ISFPROTECTION = 0x02;
/**
* Specifies that formula errors should be ignored
* Specifies that formula errors should be ignored
*/
public static final int SHAREDFEATURES_ISFFEC2 = 0x03;
/**
* Specifies the smart tag type. Recognises certain
* types of entries (proper names, dates/times etc) and
* flags them for action
* flags them for action
*/
public static final int SHAREDFEATURES_ISFFACTOID = 0x04;
/**
@@ -50,13 +51,13 @@ public final class FeatHdrRecord extends StandardRecord implements Cloneable {
*/
public static final int SHAREDFEATURES_ISFLIST = 0x05;

public final static short sid = 0x0867;

private FtrHeader futureHeader;
public static final short sid = 0x0867;

private final FtrHeader futureHeader;
private int isf_sharedFeatureType; // See SHAREDFEATURES_
private byte reserved; // Should always be one
/**
/**
* 0x00000000 = rgbHdrData not present
* 0xffffffff = rgbHdrData present
*/
@@ -69,13 +70,18 @@ public final class FeatHdrRecord extends StandardRecord implements Cloneable {
futureHeader.setRecordType(sid);
}

public short getSid() {
return sid;
public FeatHdrRecord(FeatHdrRecord other) {
super(other);
futureHeader = other.futureHeader.copy();
isf_sharedFeatureType = other.isf_sharedFeatureType;
reserved = other.reserved;
cbHdrData = other.cbHdrData;
rgbHdrData = (other.rgbHdrData == null) ? null : other.rgbHdrData.clone();
}

public FeatHdrRecord(RecordInputStream in) {
futureHeader = new FtrHeader(in);
isf_sharedFeatureType = in.readShort();
reserved = in.readByte();
cbHdrData = in.readInt();
@@ -83,19 +89,23 @@ public final class FeatHdrRecord extends StandardRecord implements Cloneable {
rgbHdrData = in.readRemainder();
}

public short getSid() {
return sid;
}

public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append("[FEATURE HEADER]\n");
// TODO ...
buffer.append("[/FEATURE HEADER]\n");
return buffer.toString();
}

public void serialize(LittleEndianOutput out) {
futureHeader.serialize(out);
out.writeShort(isf_sharedFeatureType);
out.writeByte(reserved);
out.writeInt((int)cbHdrData);
@@ -105,12 +115,20 @@ public final class FeatHdrRecord extends StandardRecord implements Cloneable {
protected int getDataSize() {
return 12 + 2+1+4+rgbHdrData.length;
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FeatHdrRecord clone() {
return copy();
}

@Override
public FeatHdrRecord clone() {
public FeatHdrRecord copy() {
//HACK: do a "cheat" clone, see Record.java for more information
return (FeatHdrRecord)cloneViaReserialise();
return new FeatHdrRecord(this);
}

}

+ 49
- 31
src/java/org/apache/poi/hssf/record/FeatRecord.java View File

@@ -17,6 +17,8 @@

package org.apache.poi.hssf.record;

import java.util.stream.Stream;

import org.apache.poi.hssf.record.common.FeatFormulaErr2;
import org.apache.poi.hssf.record.common.FeatProtection;
import org.apache.poi.hssf.record.common.FeatSmartTag;
@@ -26,6 +28,7 @@ import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Removal;

/**
* Title: Feat (Feature) Record
@@ -33,19 +36,17 @@ import org.apache.poi.util.POILogger;
* This record specifies Shared Features data. It is normally paired
* up with a {@link FeatHdrRecord}.
*/
public final class FeatRecord extends StandardRecord implements Cloneable {
private static POILogger logger = POILogFactory.getLogger(FeatRecord.class);
public final static short sid = 0x0868;
public final class FeatRecord extends StandardRecord {
private static final POILogger logger = POILogFactory.getLogger(FeatRecord.class);
public static final short sid = 0x0868;
// SIDs from newer versions
public final static short v11_sid = 0x0872;
public final static short v12_sid = 0x0878;
private FtrHeader futureHeader;
/**
* See SHAREDFEATURES_* on {@link FeatHdrRecord}
*/
private int isf_sharedFeatureType;
public static final short v11_sid = 0x0872;
public static final short v12_sid = 0x0878;

private final FtrHeader futureHeader;

/** See SHAREDFEATURES_* on {@link FeatHdrRecord} */
private int isf_sharedFeatureType;
private byte reserved1; // Should always be zero
private long reserved2; // Should always be zero
/** Only matters if type is ISFFEC2 */
@@ -55,24 +56,33 @@ public final class FeatRecord extends StandardRecord implements Cloneable {

/**
* Contents depends on isf_sharedFeatureType :
* ISFPROTECTION -> FeatProtection
* ISFPROTECTION -> FeatProtection
* ISFFEC2 -> FeatFormulaErr2
* ISFFACTOID -> FeatSmartTag
*/
private SharedFeature sharedFeature;
private SharedFeature sharedFeature;
public FeatRecord() {
futureHeader = new FtrHeader();
futureHeader.setRecordType(sid);
}

public short getSid() {
return sid;
public FeatRecord(FeatRecord other) {
super(other);
futureHeader = other.futureHeader.copy();
isf_sharedFeatureType = other.isf_sharedFeatureType;
reserved1 = other.reserved1;
reserved2 = other.reserved2;
cbFeatData = other.cbFeatData;
reserved3 = other.reserved3;
cellRefs = (other.cellRefs == null) ? null :
Stream.of(other.cellRefs).map(CellRangeAddress::copy).toArray(CellRangeAddress[]::new);
sharedFeature = (other.sharedFeature == null) ? null : other.sharedFeature.copy();
}

public FeatRecord(RecordInputStream in) {
futureHeader = new FtrHeader(in);
isf_sharedFeatureType = in.readShort();
reserved1 = in.readByte();
reserved2 = in.readInt();
@@ -84,7 +94,7 @@ public final class FeatRecord extends StandardRecord implements Cloneable {
for(int i=0; i<cellRefs.length; i++) {
cellRefs[i] = new CellRangeAddress(in);
}
switch(isf_sharedFeatureType) {
case FeatHdrRecord.SHAREDFEATURES_ISFPROTECTION:
sharedFeature = new FeatProtection(in);
@@ -100,30 +110,34 @@ public final class FeatRecord extends StandardRecord implements Cloneable {
}
}

public short getSid() {
return sid;
}

public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append("[SHARED FEATURE]\n");
// TODO ...
buffer.append("[/SHARED FEATURE]\n");
return buffer.toString();
}

public void serialize(LittleEndianOutput out) {
futureHeader.serialize(out);
out.writeShort(isf_sharedFeatureType);
out.writeByte(reserved1);
out.writeInt((int)reserved2);
out.writeShort(cellRefs.length);
out.writeInt((int)cbFeatData);
out.writeShort(reserved3);
for(int i=0; i<cellRefs.length; i++) {
cellRefs[i].serialize(out);
}
sharedFeature.serialize(out);
}

@@ -156,7 +170,7 @@ public final class FeatRecord extends StandardRecord implements Cloneable {
}
public void setSharedFeature(SharedFeature feature) {
this.sharedFeature = feature;
if(feature instanceof FeatProtection) {
isf_sharedFeatureType = FeatHdrRecord.SHAREDFEATURES_ISFPROTECTION;
}
@@ -166,7 +180,7 @@ public final class FeatRecord extends StandardRecord implements Cloneable {
if(feature instanceof FeatSmartTag) {
isf_sharedFeatureType = FeatHdrRecord.SHAREDFEATURES_ISFFACTOID;
}
if(isf_sharedFeatureType == FeatHdrRecord.SHAREDFEATURES_ISFFEC2) {
cbFeatData = sharedFeature.getDataSize();
} else {
@@ -174,12 +188,16 @@ public final class FeatRecord extends StandardRecord implements Cloneable {
}
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FeatRecord clone() {
//HACK: do a "cheat" clone, see Record.java for more information
return (FeatRecord)cloneViaReserialise();
}
return copy();
}

@Override
public FeatRecord copy() {
return new FeatRecord(this);
}
}

+ 16
- 10
src/java/org/apache/poi/hssf/record/FilePassRecord.java View File

@@ -33,13 +33,14 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.LittleEndianOutputStream;
import org.apache.poi.util.Removal;

/**
* Title: File Pass Record (0x002F) <p>
* File Pass Record (0x002F) <p>
*
* Description: Indicates that the record after this record are encrypted.
* Indicates that the record after this record are encrypted.
*/
public final class FilePassRecord extends StandardRecord implements Cloneable {
public final class FilePassRecord extends StandardRecord {
public static final short sid = 0x002F;
private static final int ENCRYPTION_XOR = 0;
private static final int ENCRYPTION_OTHER = 1;
@@ -48,12 +49,9 @@ public final class FilePassRecord extends StandardRecord implements Cloneable {
private EncryptionInfo encryptionInfo;

private FilePassRecord(FilePassRecord other) {
super(other);
encryptionType = other.encryptionType;
try {
encryptionInfo = other.encryptionInfo.clone();
} catch (CloneNotSupportedException e) {
throw new EncryptedDocumentException(e);
}
encryptionInfo = other.encryptionInfo.copy();
}

public FilePassRecord(EncryptionMode encryptionMode) {
@@ -138,8 +136,16 @@ public final class FilePassRecord extends StandardRecord implements Cloneable {
return sid;
}

@Override
public FilePassRecord clone() {
@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FilePassRecord clone() {
return copy();
}

@Override
public FilePassRecord copy() {
return new FilePassRecord(this);
}


+ 25
- 14
src/java/org/apache/poi/hssf/record/FileSharingRecord.java View File

@@ -18,17 +18,16 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;
import org.apache.poi.util.StringUtil;

/**
* Title: FILESHARING (0x005B) <p>
* Description: stores the encrypted readonly for a workbook (write protect)
* This functionality is accessed from the options dialog box available when performing 'Save As'.<p>
* REFERENCE: PG 314 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Stores the encrypted readonly for a workbook (write protect).<p>
* This functionality is accessed from the options dialog box available when performing 'Save As'.
*/
public final class FileSharingRecord extends StandardRecord implements Cloneable {
public final class FileSharingRecord extends StandardRecord {

public final static short sid = 0x005B;
public static final short sid = 0x005B;
private short field_1_readonly;
private short field_2_password;
private byte field_3_username_unicode_options;
@@ -36,14 +35,22 @@ public final class FileSharingRecord extends StandardRecord implements Cloneable

public FileSharingRecord() {}

public FileSharingRecord(FileSharingRecord other) {
super(other);
field_1_readonly = other.field_1_readonly;
field_2_password = other.field_2_password;
field_3_username_unicode_options = other.field_3_username_unicode_options;
field_3_username_value = other.field_3_username_value;
}

public FileSharingRecord(RecordInputStream in) {
field_1_readonly = in.readShort();
field_2_password = in.readShort();
int nameLen = in.readShort();
if(nameLen > 0) {
// TODO - Current examples(3) from junits only have zero length username.
// TODO - Current examples(3) from junits only have zero length username.
field_3_username_unicode_options = in.readByte();
field_3_username_value = in.readCompressedUnicode(nameLen);
} else {
@@ -137,11 +144,15 @@ public final class FileSharingRecord extends StandardRecord implements Cloneable
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FileSharingRecord clone() {
FileSharingRecord clone = new FileSharingRecord();
clone.setReadOnly(field_1_readonly);
clone.setPassword(field_2_password);
clone.setUsername(field_3_username_value);
return clone;
return copy();
}

@Override
public FileSharingRecord copy() {
return new FileSharingRecord(this);
}
}

+ 16
- 14
src/java/org/apache/poi/hssf/record/FnGroupCountRecord.java View File

@@ -15,35 +15,32 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Function Group Count Record<P>
* Description: Number of built in function groups in the current version of the
* Spreadsheet (probably only used on Windoze)<P>
* REFERENCE: PG 315 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* umber of built in function groups in the current version of the Spreadsheet (probably only used on Windows)
*
* @version 2.0-pre
*/

public final class FnGroupCountRecord
extends StandardRecord
{
public final static short sid = 0x9c;
public final class FnGroupCountRecord extends StandardRecord {
public static final short sid = 0x9c;

/**
* suggested default (14 dec)
*/

public final static short COUNT = 14;
public static final short COUNT = 14;
private short field_1_count;

public FnGroupCountRecord()
{
public FnGroupCountRecord() {}

public FnGroupCountRecord(FnGroupCountRecord other) {
super(other);
field_1_count = other.field_1_count;
}

public FnGroupCountRecord(RecordInputStream in)
@@ -96,4 +93,9 @@ public final class FnGroupCountRecord
{
return sid;
}

@Override
public FnGroupCountRecord copy() {
return new FnGroupCountRecord(this);
}
}

+ 53
- 30
src/java/org/apache/poi/hssf/record/FontRecord.java View File

@@ -25,50 +25,68 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil;

/**
* Title: Font Record (0x0031) <p>
* - describes a font in the workbook (index = 0-3,5-infinity - skip 4)<P>
* Description: An element in the Font Table<p>
* REFERENCE: PG 315 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
*/
/** Describes a font in the workbook */
public final class FontRecord extends StandardRecord {
// docs are wrong (0x231 Microsoft Support site article Q184647)
public final static short sid = 0x0031;
public final static short SS_NONE = 0;
public final static short SS_SUPER = 1;
public final static short SS_SUB = 2;
public final static byte U_NONE = 0;
public final static byte U_SINGLE = 1;
public final static byte U_DOUBLE = 2;
public final static byte U_SINGLE_ACCOUNTING = 0x21;
public final static byte U_DOUBLE_ACCOUNTING = 0x22;
// in units of .05 of a point
private short field_1_font_height;
private short field_2_attributes;
public static final short sid = 0x0031;
public static final short SS_NONE = 0;
public static final short SS_SUPER = 1;
public static final short SS_SUB = 2;
public static final byte U_NONE = 0;
public static final byte U_SINGLE = 1;
public static final byte U_DOUBLE = 2;
public static final byte U_SINGLE_ACCOUNTING = 0x21;
public static final byte U_DOUBLE_ACCOUNTING = 0x22;

// 0 0x01 - Reserved bit must be 0
private static final BitField italic = BitFieldFactory.getInstance(0x02); // is this font in italics
// is this font in italics
private static final BitField italic = BitFieldFactory.getInstance(0x02);

// 2 0x04 - reserved bit must be 0
private static final BitField strikeout =BitFieldFactory.getInstance(0x08); // is this font has a line through the center
private static final BitField macoutline = BitFieldFactory.getInstance(0x10); // some weird macintosh thing....but who understands those mac people anyhow
private static final BitField macshadow = BitFieldFactory.getInstance(0x20); // some weird macintosh thing....but who understands those mac people anyhow
// is this font has a line through the center
private static final BitField strikeout = BitFieldFactory.getInstance(0x08);
// some weird macintosh thing....but who understands those mac people anyhow
private static final BitField macoutline = BitFieldFactory.getInstance(0x10);
private static final BitField macshadow = BitFieldFactory.getInstance(0x20);

// in units of .05 of a point
private short field_1_font_height;
private short field_2_attributes;

// 7-6 - reserved bits must be 0
// the rest is unused
private short field_3_color_palette_index;
private short field_4_bold_weight;
private short field_5_super_sub_script; // 00none/01super/02sub
private byte field_6_underline; // 00none/01single/02double/21singleaccounting/22doubleaccounting
private byte field_7_family; // ?? defined by windows api logfont structure?
private byte field_8_charset; // ?? defined by windows api logfont structure?
private byte field_9_zero; // must be 0
private short field_3_color_palette_index;
private short field_4_bold_weight;
// 00none/01super/02sub
private short field_5_super_sub_script;
// 00none/01single/02double/21singleaccounting/22doubleaccounting
private byte field_6_underline;
// ?? defined by windows api logfont structure?
private byte field_7_family;
// ?? defined by windows api logfont structure?
private byte field_8_charset;
// must be 0
private byte field_9_zero;
/** possibly empty string never <code>null</code> */
private String field_11_font_name;
private String field_11_font_name;

public FontRecord() {
}

public FontRecord(FontRecord other) {
super(other);
field_1_font_height = other.field_1_font_height;
field_2_attributes = other.field_2_attributes;
field_3_color_palette_index = other.field_3_color_palette_index;
field_4_bold_weight = other.field_4_bold_weight;
field_5_super_sub_script = other.field_5_super_sub_script;
field_6_underline = other.field_6_underline;
field_7_family = other.field_7_family;
field_8_charset = other.field_8_charset;
field_9_zero = other.field_9_zero;
field_11_font_name = other.field_11_font_name;
}

public FontRecord(RecordInputStream in) {
field_1_font_height = in.readShort();
field_2_attributes = in.readShort();
@@ -490,4 +508,9 @@ public final class FontRecord extends StandardRecord {
public boolean equals(Object o) {
return (o instanceof FontRecord) && sameProperties((FontRecord) o);
}

@Override
public FontRecord copy() {
return new FontRecord(this);
}
}

+ 18
- 6
src/java/org/apache/poi/hssf/record/FooterRecord.java View File

@@ -17,18 +17,22 @@

package org.apache.poi.hssf.record;

import org.apache.poi.util.Removal;

/**
* Title: Footer Record (0x0015)<p>
* Description: Specifies the footer for a sheet<p>
* REFERENCE: PG 317 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Specifies the footer for a sheet
*/
public final class FooterRecord extends HeaderFooterBase implements Cloneable {
public final static short sid = 0x0015;
public final class FooterRecord extends HeaderFooterBase {
public static final short sid = 0x0015;

public FooterRecord(String text) {
super(text);
}

public FooterRecord(FooterRecord other) {
super(other);
}

public FooterRecord(RecordInputStream in) {
super(in);
}
@@ -47,7 +51,15 @@ public final class FooterRecord extends HeaderFooterBase implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FooterRecord clone() {
return new FooterRecord(getText());
return copy();
}

@Override
public FooterRecord copy() {
return new FooterRecord(this);
}
}

+ 15
- 8
src/java/org/apache/poi/hssf/record/FormatRecord.java View File

@@ -22,30 +22,29 @@ import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Removal;
import org.apache.poi.util.StringUtil;

/**
* Title: Format Record (0x041E)<p>
* Description: describes a number format -- those goofy strings like $(#,###)<p>
*
* REFERENCE: PG 317 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Describes a number format -- those goofy strings like $(#,###)
*/
public final class FormatRecord extends StandardRecord implements Cloneable {
public final class FormatRecord extends StandardRecord {

private static final POILogger logger = POILogFactory.getLogger(FormatRecord.class);

public final static short sid = 0x041E;
public static final short sid = 0x041E;

private final int field_1_index_code;
private final boolean field_3_hasMultibyte;
private final String field_4_formatstring;

private FormatRecord(FormatRecord other) {
super(other);
field_1_index_code = other.field_1_index_code;
field_3_hasMultibyte = other.field_3_hasMultibyte;
field_4_formatstring = other.field_4_formatstring;
}
public FormatRecord(int indexCode, String fs) {
field_1_index_code = indexCode;
field_4_formatstring = fs;
@@ -114,9 +113,17 @@ public final class FormatRecord extends StandardRecord implements Cloneable {
public short getSid() {
return sid;
}
@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FormatRecord clone() {
return copy();
}

@Override
public FormatRecord copy() {
return new FormatRecord(this);
}


+ 38
- 169
src/java/org/apache/poi/hssf/record/FormulaRecord.java View File

@@ -18,168 +18,28 @@
package org.apache.poi.hssf.record;

import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.util.*;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Formula Record (0x0006).
* REFERENCE: PG 317/444 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class FormulaRecord extends CellRecord implements Cloneable {
public final class FormulaRecord extends CellRecord {

public static final short sid = 0x0006; // docs say 406...because of a bug Microsoft support site article #Q184647)
private static int FIXED_SIZE = 14; // double + short + int
// docs say 406...because of a bug Microsoft support site article #Q184647)
public static final short sid = 0x0006;
// double + short + int
private static final int FIXED_SIZE = 14;

private static final BitField alwaysCalc = BitFieldFactory.getInstance(0x0001);
private static final BitField calcOnLoad = BitFieldFactory.getInstance(0x0002);
private static final BitField sharedFormula = BitFieldFactory.getInstance(0x0008);

/**
* Manages the cached formula result values of other types besides numeric.
* Excel encodes the same 8 bytes that would be field_4_value with various NaN
* values that are decoded/encoded by this class.
*/
static final class SpecialCachedValue {
/** deliberately chosen by Excel in order to encode other values within Double NaNs */
private static final long BIT_MARKER = 0xFFFF000000000000L;
private static final int VARIABLE_DATA_LENGTH = 6;
private static final int DATA_INDEX = 2;

// FIXME: can these be merged with {@link CellType}?
// are the numbers specific to the HSSF formula record format or just a poor-man's enum?
public static final int STRING = 0;
public static final int BOOLEAN = 1;
public static final int ERROR_CODE = 2;
public static final int EMPTY = 3;

private final byte[] _variableData;

private SpecialCachedValue(byte[] data) {
_variableData = data;
}

public int getTypeCode() {
return _variableData[0];
}

/**
* @return <code>null</code> if the double value encoded by <tt>valueLongBits</tt>
* is a normal (non NaN) double value.
*/
public static SpecialCachedValue create(long valueLongBits) {
if ((BIT_MARKER & valueLongBits) != BIT_MARKER) {
return null;
}

byte[] result = new byte[VARIABLE_DATA_LENGTH];
long x = valueLongBits;
for (int i=0; i<VARIABLE_DATA_LENGTH; i++) {
result[i] = (byte) x;
x >>= 8;
}
switch (result[0]) {
case STRING:
case BOOLEAN:
case ERROR_CODE:
case EMPTY:
break;
default:
throw new org.apache.poi.util.RecordFormatException("Bad special value code (" + result[0] + ")");
}
return new SpecialCachedValue(result);
}

public void serialize(LittleEndianOutput out) {
out.write(_variableData);
out.writeShort(0xFFFF);
}

public String formatDebugString() {
return formatValue() + ' ' + HexDump.toHex(_variableData);
}

private String formatValue() {
int typeCode = getTypeCode();
switch (typeCode) {
case STRING:
return "<string>";
case BOOLEAN:
return getDataValue() == 0 ? "FALSE" : "TRUE";
case ERROR_CODE:
return ErrorEval.getText(getDataValue());
case EMPTY:
return "<empty>";
}
return "#error(type=" + typeCode + ")#";
}

private int getDataValue() {
return _variableData[DATA_INDEX];
}

public static SpecialCachedValue createCachedEmptyValue() {
return create(EMPTY, 0);
}

public static SpecialCachedValue createForString() {
return create(STRING, 0);
}

public static SpecialCachedValue createCachedBoolean(boolean b) {
return create(BOOLEAN, b ? 1 : 0);
}

public static SpecialCachedValue createCachedErrorCode(int errorCode) {
return create(ERROR_CODE, errorCode);
}

private static SpecialCachedValue create(int code, int data) {
byte[] vd = {
(byte) code,
0,
(byte) data,
0,
0,
0,
};
return new SpecialCachedValue(vd);
}

@Override
public String toString() {
return getClass().getName() + '[' + formatValue() + ']';
}

public int getValueType() {
int typeCode = getTypeCode();
switch (typeCode) {
case STRING: return CellType.STRING.getCode();
case BOOLEAN: return CellType.BOOLEAN.getCode();
case ERROR_CODE: return CellType.ERROR.getCode();
case EMPTY: return CellType.STRING.getCode(); // is this correct?
}
throw new IllegalStateException("Unexpected type id (" + typeCode + ")");
}

public boolean getBooleanValue() {
if (getTypeCode() != BOOLEAN) {
throw new IllegalStateException("Not a boolean cached value - " + formatValue());
}
return getDataValue() != 0;
}

public int getErrorValue() {
if (getTypeCode() != ERROR_CODE) {
throw new IllegalStateException("Not an error cached value - " + formatValue());
}
return getDataValue();
}
}

private double field_4_value;
private short field_5_options;
/**
@@ -193,19 +53,27 @@ public final class FormulaRecord extends CellRecord implements Cloneable {
/**
* Since the NaN support seems sketchy (different constants) we'll store and spit it out directly
*/
private SpecialCachedValue specialCachedValue;
private FormulaSpecialCachedValue specialCachedValue;

/** Creates new FormulaRecord */

public FormulaRecord() {
field_8_parsed_expr = Formula.create(Ptg.EMPTY_PTG_ARRAY);
}

public FormulaRecord(FormulaRecord other) {
super(other);
field_4_value = other.field_4_value;
field_5_options = other.field_5_options;
field_6_zero = other.field_6_zero;
field_8_parsed_expr = (other.field_8_parsed_expr == null) ? null : new Formula(other.field_8_parsed_expr);
specialCachedValue = (other.specialCachedValue == null) ? null : new FormulaSpecialCachedValue(other.specialCachedValue);
}

public FormulaRecord(RecordInputStream ris) {
super(ris);
long valueLongBits = ris.readLong();
field_5_options = ris.readShort();
specialCachedValue = SpecialCachedValue.create(valueLongBits);
specialCachedValue = FormulaSpecialCachedValue.create(valueLongBits);
if (specialCachedValue == null) {
field_4_value = Double.longBitsToDouble(valueLongBits);
}
@@ -228,16 +96,16 @@ public final class FormulaRecord extends CellRecord implements Cloneable {
}

public void setCachedResultTypeEmptyString() {
specialCachedValue = SpecialCachedValue.createCachedEmptyValue();
specialCachedValue = FormulaSpecialCachedValue.createCachedEmptyValue();
}
public void setCachedResultTypeString() {
specialCachedValue = SpecialCachedValue.createForString();
specialCachedValue = FormulaSpecialCachedValue.createForString();
}
public void setCachedResultErrorCode(int errorCode) {
specialCachedValue = SpecialCachedValue.createCachedErrorCode(errorCode);
specialCachedValue = FormulaSpecialCachedValue.createCachedErrorCode(errorCode);
}
public void setCachedResultBoolean(boolean value) {
specialCachedValue = SpecialCachedValue.createCachedBoolean(value);
specialCachedValue = FormulaSpecialCachedValue.createCachedBoolean(value);
}
/**
* @return <code>true</code> if this {@link FormulaRecord} is followed by a
@@ -246,7 +114,7 @@ public final class FormulaRecord extends CellRecord implements Cloneable {
*/
public boolean hasCachedResultString() {
return specialCachedValue != null &&
specialCachedValue.getTypeCode() == SpecialCachedValue.STRING;
specialCachedValue.getTypeCode() == FormulaSpecialCachedValue.STRING;
}

public int getCachedResultType() {
@@ -353,12 +221,12 @@ public final class FormulaRecord extends CellRecord implements Cloneable {
out.writeInt(field_6_zero); // may as well write original data back so as to minimise differences from original
field_8_parsed_expr.serialize(out);
}
@Override
protected String getRecordName() {
return "FORMULA";
}
@Override
protected void appendValueText(StringBuilder sb) {
sb.append(" .value = ");
@@ -385,15 +253,16 @@ public final class FormulaRecord extends CellRecord implements Cloneable {
}

@Override
public FormulaRecord clone() {
FormulaRecord rec = new FormulaRecord();
copyBaseFields(rec);
rec.field_4_value = field_4_value;
rec.field_5_options = field_5_options;
rec.field_6_zero = field_6_zero;
rec.field_8_parsed_expr = field_8_parsed_expr;
rec.specialCachedValue = specialCachedValue;
return rec;
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FormulaRecord clone() {
return copy();
}

@Override
public FormulaRecord copy() {
return new FormulaRecord(this);
}
}


+ 167
- 0
src/java/org/apache/poi/hssf/record/FormulaSpecialCachedValue.java View File

@@ -0,0 +1,167 @@
/* ====================================================================
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 org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianOutput;

/**
* Manages the cached formula result values of other types besides numeric.
* Excel encodes the same 8 bytes that would be field_4_value with various NaN
* values that are decoded/encoded by this class.
*/
@Internal
public final class FormulaSpecialCachedValue {
/** deliberately chosen by Excel in order to encode other values within Double NaNs */
private static final long BIT_MARKER = 0xFFFF000000000000L;
private static final int VARIABLE_DATA_LENGTH = 6;
private static final int DATA_INDEX = 2;

// FIXME: can these be merged with {@link CellType}?
// are the numbers specific to the HSSF formula record format or just a poor-man's enum?
public static final int STRING = 0;
public static final int BOOLEAN = 1;
public static final int ERROR_CODE = 2;
public static final int EMPTY = 3;

private final byte[] _variableData;

FormulaSpecialCachedValue(FormulaSpecialCachedValue other) {
_variableData = (other._variableData == null) ? null : other._variableData.clone();
}

private FormulaSpecialCachedValue(byte[] data) {
_variableData = data;
}

public int getTypeCode() {
return _variableData[0];
}

/**
* @return <code>null</code> if the double value encoded by <tt>valueLongBits</tt>
* is a normal (non NaN) double value.
*/
public static FormulaSpecialCachedValue create(long valueLongBits) {
if ((BIT_MARKER & valueLongBits) != BIT_MARKER) {
return null;
}

byte[] result = new byte[VARIABLE_DATA_LENGTH];
long x = valueLongBits;
for (int i=0; i<VARIABLE_DATA_LENGTH; i++) {
result[i] = (byte) x;
x >>= 8;
}
switch (result[0]) {
case STRING:
case BOOLEAN:
case ERROR_CODE:
case EMPTY:
break;
default:
throw new org.apache.poi.util.RecordFormatException("Bad special value code (" + result[0] + ")");
}
return new FormulaSpecialCachedValue(result);
}

public void serialize(LittleEndianOutput out) {
out.write(_variableData);
out.writeShort(0xFFFF);
}

public String formatDebugString() {
return formatValue() + ' ' + HexDump.toHex(_variableData);
}

private String formatValue() {
int typeCode = getTypeCode();
switch (typeCode) {
case STRING:
return "<string>";
case BOOLEAN:
return getDataValue() == 0 ? "FALSE" : "TRUE";
case ERROR_CODE:
return ErrorEval.getText(getDataValue());
case EMPTY:
return "<empty>";
}
return "#error(type=" + typeCode + ")#";
}

private int getDataValue() {
return _variableData[DATA_INDEX];
}

public static FormulaSpecialCachedValue createCachedEmptyValue() {
return create(EMPTY, 0);
}

public static FormulaSpecialCachedValue createForString() {
return create(STRING, 0);
}

public static FormulaSpecialCachedValue createCachedBoolean(boolean b) {
return create(BOOLEAN, b ? 1 : 0);
}

public static FormulaSpecialCachedValue createCachedErrorCode(int errorCode) {
return create(ERROR_CODE, errorCode);
}

private static FormulaSpecialCachedValue create(int code, int data) {
byte[] vd = { (byte) code, 0, (byte) data, 0, 0, 0, };
return new FormulaSpecialCachedValue(vd);
}

@Override
public String toString() {
return getClass().getName() + '[' + formatValue() + ']';
}

public int getValueType() {
int typeCode = getTypeCode();
switch (typeCode) {
case EMPTY: // is this correct?
case STRING:
return CellType.STRING.getCode();
case BOOLEAN:
return CellType.BOOLEAN.getCode();
case ERROR_CODE:
return CellType.ERROR.getCode();
}
throw new IllegalStateException("Unexpected type id (" + typeCode + ")");
}

public boolean getBooleanValue() {
if (getTypeCode() != BOOLEAN) {
throw new IllegalStateException("Not a boolean cached value - " + formatValue());
}
return getDataValue() != 0;
}

public int getErrorValue() {
if (getTypeCode() != ERROR_CODE) {
throw new IllegalStateException("Not an error cached value - " + formatValue());
}
return getDataValue();
}
}

+ 19
- 12
src/java/org/apache/poi/hssf/record/FtCblsSubRecord.java View File

@@ -22,28 +22,31 @@ import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;


/**
* This structure appears as part of an Obj record that represents a checkbox or radio button.
*
* @author Yegor Kozlov
*/
public final class FtCblsSubRecord extends SubRecord implements Cloneable {
public final static short sid = 0x0C;
public final class FtCblsSubRecord extends SubRecord {
public static final short sid = 0x0C;
private static final int ENCODED_SIZE = 20;

private byte[] reserved;
private final byte[] reserved;

/**
* Construct a new <code>FtCblsSubRecord</code> and
* fill its data with the default values
*/
public FtCblsSubRecord()
{
public FtCblsSubRecord() {
reserved = new byte[ENCODED_SIZE];
}

public FtCblsSubRecord(FtCblsSubRecord other) {
super(other);
reserved = other.reserved.clone();
}

public FtCblsSubRecord(LittleEndianInput in, int size) {
if (size != ENCODED_SIZE) {
throw new RecordFormatException("Unexpected size (" + size + ")");
@@ -93,12 +96,16 @@ public final class FtCblsSubRecord extends SubRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FtCblsSubRecord clone() {
FtCblsSubRecord rec = new FtCblsSubRecord();
byte[] recdata = new byte[reserved.length];
System.arraycopy(reserved, 0, recdata, 0, recdata.length);
rec.reserved = recdata;
return rec;
return copy();
}

@Override
public FtCblsSubRecord copy() {
return new FtCblsSubRecord(this);
}

}

+ 21
- 10
src/java/org/apache/poi/hssf/record/FtCfSubRecord.java View File

@@ -21,15 +21,16 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;


/**
* The FtCf structure specifies the clipboard format of the picture-type Obj record containing this FtCf.
*/
public final class FtCfSubRecord extends SubRecord implements Cloneable {
public final static short sid = 0x07;
public final static short length = 0x02;
public final class FtCfSubRecord extends SubRecord {
public static final short sid = 0x07;
public static final short length = 0x02;
/**
* Specifies the format of the picture is an enhanced metafile.
*/
@@ -39,20 +40,24 @@ public final class FtCfSubRecord extends SubRecord implements Cloneable {
* Specifies the format of the picture is a bitmap.
*/
public static final short BITMAP_BIT = (short)0x0009;
/**
* Specifies the picture is in an unspecified format that is
* neither and enhanced metafile nor a bitmap.
*/
public static final short UNSPECIFIED_BIT = (short)0xFFFF;
private short flags;

/**
* Construct a new <code>FtPioGrbitSubRecord</code> and
* fill its data with the default values
*/
public FtCfSubRecord() {
public FtCfSubRecord() {}

public FtCfSubRecord(FtCfSubRecord other) {
super(other);
flags = other.flags;
}

public FtCfSubRecord(LittleEndianInput in, int size) {
@@ -99,10 +104,16 @@ public final class FtCfSubRecord extends SubRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FtCfSubRecord clone() {
FtCfSubRecord rec = new FtCfSubRecord();
rec.flags = this.flags;
return rec;
return copy();
}

@Override
public FtCfSubRecord copy() {
return new FtCfSubRecord(this);
}

public short getFlags() {

+ 31
- 20
src/java/org/apache/poi/hssf/record/FtPioGrbitSubRecord.java View File

@@ -21,27 +21,28 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;


/**
* This structure appears as part of an Obj record that represents image display properties.
*/
public final class FtPioGrbitSubRecord extends SubRecord implements Cloneable {
public final static short sid = 0x08;
public final static short length = 0x02;
public final class FtPioGrbitSubRecord extends SubRecord {
public static final short sid = 0x08;
public static final short length = 0x02;
/**
* A bit that specifies whether the picture's aspect ratio is preserved when rendered in
* A bit that specifies whether the picture's aspect ratio is preserved when rendered in
* different views (Normal view, Page Break Preview view, Page Layout view and printing).
*/
public static final int AUTO_PICT_BIT = 1 << 0;

/**
* A bit that specifies whether the pictFmla field of the Obj record that contains
* A bit that specifies whether the pictFmla field of the Obj record that contains
* this FtPioGrbit specifies a DDE reference.
*/
public static final int DDE_BIT = 1 << 1;
/**
* A bit that specifies whether this object is expected to be updated on print to
* reflect the values in the cell associated with the object.
@@ -52,44 +53,48 @@ public final class FtPioGrbitSubRecord extends SubRecord implements Cloneable {
* A bit that specifies whether the picture is displayed as an icon.
*/
public static final int ICON_BIT = 1 << 3;
/**
* A bit that specifies whether this object is an ActiveX control.
* It MUST NOT be the case that both fCtl and fDde are equal to 1.
*/
public static final int CTL_BIT = 1 << 4;
/**
* A bit that specifies whether the object data are stored in an
* embedding storage (= 0) or in the controls stream (ctls) (= 1).
*/
public static final int PRSTM_BIT = 1 << 5;
/**
* A bit that specifies whether this is a camera picture.
*/
public static final int CAMERA_BIT = 1 << 7;
/**
* A bit that specifies whether this picture's size has been explicitly set.
* 0 = picture size has been explicitly set, 1 = has not been set
*/
public static final int DEFAULT_SIZE_BIT = 1 << 8;
/**
* A bit that specifies whether the OLE server for the object is called
* to load the object's data automatically when the parent workbook is opened.
*/
public static final int AUTO_LOAD_BIT = 1 << 9;

private short flags;

/**
* Construct a new <code>FtPioGrbitSubRecord</code> and
* fill its data with the default values
*/
public FtPioGrbitSubRecord() {
public FtPioGrbitSubRecord() {}

public FtPioGrbitSubRecord(FtPioGrbitSubRecord other) {
super(other);
flags = other.flags;
}

public FtPioGrbitSubRecord(LittleEndianInput in, int size) {
@@ -110,12 +115,12 @@ public final class FtPioGrbitSubRecord extends SubRecord implements Cloneable {
} else {
flags &= (0xFFFF ^ bitmask);
}
}
}
public boolean getFlagByBit(int bitmask) {
return ((flags & bitmask) != 0);
}
/**
* Convert this record to string.
* Used by BiffViewer and other utilities.
@@ -153,10 +158,16 @@ public final class FtPioGrbitSubRecord extends SubRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public FtPioGrbitSubRecord clone() {
FtPioGrbitSubRecord rec = new FtPioGrbitSubRecord();
rec.flags = this.flags;
return rec;
return copy();
}

@Override
public FtPioGrbitSubRecord copy() {
return new FtPioGrbitSubRecord(this);
}

public short getFlags() {

+ 19
- 16
src/java/org/apache/poi/hssf/record/GridsetRecord.java View File

@@ -18,28 +18,25 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Gridset Record.<P>
* Description: flag denoting whether the user specified that gridlines are used when
* printing.<P>
* REFERENCE: PG 320 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
*
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Glen Stampoultzis (glens at apache.org)
* @author Jason Height (jheight at chariot dot net dot au)
* Flag denoting whether the user specified that gridlines are used when printing.
*
* @version 2.0-pre
*/
public final class GridsetRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x82;
public final class GridsetRecord extends StandardRecord {
public static final short sid = 0x82;
public short field_1_gridset_flag;

public GridsetRecord() {
public GridsetRecord() {}

public GridsetRecord(GridsetRecord other) {
super(other);
field_1_gridset_flag = other.field_1_gridset_flag;
}

public GridsetRecord(RecordInputStream in)
{
public GridsetRecord(RecordInputStream in) {
field_1_gridset_flag = in.readShort();
}

@@ -87,9 +84,15 @@ public final class GridsetRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public GridsetRecord clone() {
GridsetRecord rec = new GridsetRecord();
rec.field_1_gridset_flag = field_1_gridset_flag;
return rec;
return copy();
}

@Override
public GridsetRecord copy() {
return new GridsetRecord(this);
}
}

+ 17
- 6
src/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java View File

@@ -21,13 +21,14 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* ftGmo (0x0006)<p>
* The group marker record is used as a position holder for groups.
*/
public final class GroupMarkerSubRecord extends SubRecord implements Cloneable {
public final static short sid = 0x0006;
public final class GroupMarkerSubRecord extends SubRecord {
public static final short sid = 0x0006;
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;

@@ -41,6 +42,11 @@ public final class GroupMarkerSubRecord extends SubRecord implements Cloneable {
reserved = EMPTY_BYTE_ARRAY;
}

public GroupMarkerSubRecord(GroupMarkerSubRecord other) {
super(other);
reserved = other.reserved.clone();
}

public GroupMarkerSubRecord(LittleEndianInput in, int size) {
byte[] buf = IOUtils.safelyAllocate(size, MAX_RECORD_LENGTH);
in.readFully(buf);
@@ -74,10 +80,15 @@ public final class GroupMarkerSubRecord extends SubRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public GroupMarkerSubRecord clone() {
GroupMarkerSubRecord rec = new GroupMarkerSubRecord();
rec.reserved = new byte[reserved.length];
System.arraycopy(reserved, 0, rec.reserved, 0, reserved.length);
return rec;
return copy();
}

@Override
public GroupMarkerSubRecord copy() {
return new GroupMarkerSubRecord(this);
}
}

+ 33
- 23
src/java/org/apache/poi/hssf/record/GutsRecord.java View File

@@ -15,34 +15,41 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Guts Record <P>
* Description: Row/column gutter sizes <P>
* REFERENCE: PG 320 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
* Row/column gutter sizes
*
* @version 2.0-pre
*/

public final class GutsRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x80;
private short field_1_left_row_gutter; // size of the row gutter to the left of the rows
private short field_2_top_col_gutter; // size of the column gutter above the columns
private short field_3_row_level_max; // maximum outline level for row gutters
private short field_4_col_level_max; // maximum outline level for column gutters

public GutsRecord()
{
public final class GutsRecord extends StandardRecord {
public static final short sid = 0x80;
/** size of the row gutter to the left of the rows */
private short field_1_left_row_gutter;
/** size of the column gutter above the columns */
private short field_2_top_col_gutter;
/** maximum outline level for row gutters */
private short field_3_row_level_max;
/** maximum outline level for column gutters */
private short field_4_col_level_max;

public GutsRecord() {}

public GutsRecord(GutsRecord other) {
super(other);
field_1_left_row_gutter = other.field_1_left_row_gutter;
field_2_top_col_gutter = other.field_2_top_col_gutter;
field_3_row_level_max = other.field_3_row_level_max;
field_4_col_level_max = other.field_4_col_level_max;
}

public GutsRecord(RecordInputStream in)
{
public GutsRecord(RecordInputStream in) {
field_1_left_row_gutter = in.readShort();
field_2_top_col_gutter = in.readShort();
field_3_row_level_max = in.readShort();
@@ -171,12 +178,15 @@ public final class GutsRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public GutsRecord clone() {
GutsRecord rec = new GutsRecord();
rec.field_1_left_row_gutter = field_1_left_row_gutter;
rec.field_2_top_col_gutter = field_2_top_col_gutter;
rec.field_3_row_level_max = field_3_row_level_max;
rec.field_4_col_level_max = field_4_col_level_max;
return rec;
return copy();
}
@Override
public GutsRecord copy() {
return new GutsRecord(this);
}
}

+ 22
- 19
src/java/org/apache/poi/hssf/record/HCenterRecord.java View File

@@ -17,24 +17,25 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: HCenter record (0x0083)<P>
* Description: whether to center between horizontal margins<P>
* REFERENCE: PG 320 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
* Whether to center between horizontal margins
*
* @version 2.0-pre
*/
public final class HCenterRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x0083;
private short field_1_hcenter;
public final class HCenterRecord extends StandardRecord {
public static final short sid = 0x0083;
private short field_1_hcenter;

public HCenterRecord() {
public HCenterRecord() {}

public HCenterRecord(HCenterRecord other) {
super(other);
field_1_hcenter = other.field_1_hcenter;
}

public HCenterRecord(RecordInputStream in)
{
public HCenterRecord(RecordInputStream in) {
field_1_hcenter = in.readShort();
}

@@ -43,11 +44,7 @@ public final class HCenterRecord extends StandardRecord implements Cloneable {
* @param hc center - t/f
*/
public void setHCenter(boolean hc) {
if (hc) {
field_1_hcenter = 1;
} else {
field_1_hcenter = 0;
}
field_1_hcenter = (short)(hc ? 1 : 0);
}

/**
@@ -80,9 +77,15 @@ public final class HCenterRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public HCenterRecord clone() {
HCenterRecord rec = new HCenterRecord();
rec.field_1_hcenter = field_1_hcenter;
return rec;
return copy();
}

@Override
public HCenterRecord copy() {
return new HCenterRecord(this);
}
}

+ 9
- 2
src/java/org/apache/poi/hssf/record/HeaderFooterBase.java View File

@@ -22,8 +22,6 @@ import org.apache.poi.util.StringUtil;

/**
* Common header/footer base class
*
* @author Josh Micich
*/
public abstract class HeaderFooterBase extends StandardRecord {
private boolean field_2_hasMultibyte;
@@ -33,6 +31,12 @@ public abstract class HeaderFooterBase extends StandardRecord {
setText(text);
}

protected HeaderFooterBase(HeaderFooterBase other) {
super(other);
field_2_hasMultibyte = other.field_2_hasMultibyte;
field_3_text = other.field_3_text;
}

protected HeaderFooterBase(RecordInputStream in) {
if (in.remaining() > 0) {
int field_1_footer_len = in.readShort();
@@ -107,4 +111,7 @@ public abstract class HeaderFooterBase extends StandardRecord {
}
return 3 + getTextLength() * (field_2_hasMultibyte ? 2 : 1);
}

@Override
public abstract HeaderFooterBase copy();
}

+ 24
- 14
src/java/org/apache/poi/hssf/record/HeaderFooterRecord.java View File

@@ -17,28 +17,31 @@

package org.apache.poi.hssf.record;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;

import java.util.Arrays;
import java.util.Locale;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* The HEADERFOOTER record stores information added in Office Excel 2007 for headers/footers.
*
* @author Yegor Kozlov
*/
public final class HeaderFooterRecord extends StandardRecord implements Cloneable {
public final class HeaderFooterRecord extends StandardRecord {
public static final short sid = 0x089C;
private static final byte[] BLANK_GUID = new byte[16];

public final static short sid = 0x089C;
private byte[] _rawData;

public HeaderFooterRecord(byte[] data) {
_rawData = data;
}

public HeaderFooterRecord(HeaderFooterRecord other) {
super(other);
_rawData = (other._rawData == null) ? null : other._rawData.clone();
}

/**
* construct a HeaderFooterRecord record. No fields are interpreted and the record will
* be serialized in its original form more or less
@@ -58,7 +61,7 @@ public final class HeaderFooterRecord extends StandardRecord implements Cloneabl
protected int getDataSize() {
return _rawData.length;
}
public short getSid()
{
return sid;
@@ -79,7 +82,7 @@ public final class HeaderFooterRecord extends StandardRecord implements Cloneabl
}

/**
* @return whether this record belongs to the current sheet
* @return whether this record belongs to the current sheet
*/
public boolean isCurrentSheet(){
return Arrays.equals(getGuid(), BLANK_GUID);
@@ -96,10 +99,17 @@ public final class HeaderFooterRecord extends StandardRecord implements Cloneabl
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public HeaderFooterRecord clone() {
//HACK: do a "cheat" clone, see Record.java for more information
return (HeaderFooterRecord)cloneViaReserialise();
return copy();
}

@Override
public HeaderFooterRecord copy() {
return new HeaderFooterRecord(this);
}


}

+ 18
- 9
src/java/org/apache/poi/hssf/record/HeaderRecord.java View File

@@ -17,21 +17,22 @@

package org.apache.poi.hssf.record;

import org.apache.poi.util.Removal;

/**
* Title: Header Record<P>
* Description: Specifies a header for a sheet<P>
* REFERENCE: PG 321 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Shawn Laubach (slaubach at apache dot org) Modified 3/14/02
* @author Jason Height (jheight at chariot dot net dot au)
* Specifies a header for a sheet
*/
public final class HeaderRecord extends HeaderFooterBase implements Cloneable {
public final static short sid = 0x0014;
public final class HeaderRecord extends HeaderFooterBase {
public static final short sid = 0x0014;

public HeaderRecord(String text) {
super(text);
}

public HeaderRecord(HeaderRecord other) {
super(other);
}

public HeaderRecord(RecordInputStream in) {
super(in);
}
@@ -50,7 +51,15 @@ public final class HeaderRecord extends HeaderFooterBase implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public HeaderRecord clone() {
return new HeaderRecord(getText());
return copy();
}

@Override
public HeaderRecord copy() {
return new HeaderRecord(this);
}
}

+ 20
- 17
src/java/org/apache/poi/hssf/record/HideObjRecord.java View File

@@ -15,35 +15,33 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Hide Object Record<P>
* Description: flag defines whether to hide placeholders and object<P>
* REFERENCE: PG 321 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* Flag defines whether to hide placeholders and object
*
* @version 2.0-pre
*/
public final class HideObjRecord extends StandardRecord {
public static final short sid = 0x8d;
public static final short HIDE_ALL = 2;
public static final short SHOW_PLACEHOLDERS = 1;
public static final short SHOW_ALL = 0;

public final class HideObjRecord
extends StandardRecord
{
public final static short sid = 0x8d;
public final static short HIDE_ALL = 2;
public final static short SHOW_PLACEHOLDERS = 1;
public final static short SHOW_ALL = 0;
private short field_1_hide_obj;
private short field_1_hide_obj;

public HideObjRecord()
{
public HideObjRecord() {}

public HideObjRecord(HideObjRecord other) {
super(other);
field_1_hide_obj = other.field_1_hide_obj;
}

public HideObjRecord(RecordInputStream in)
{
public HideObjRecord(RecordInputStream in) {
field_1_hide_obj = in.readShort();
}

@@ -98,4 +96,9 @@ public final class HideObjRecord
{
return sid;
}

@Override
public HideObjRecord copy() {
return new HideObjRecord(this);
}
}

+ 16
- 11
src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java View File

@@ -17,21 +17,24 @@

package org.apache.poi.hssf.record;

import java.util.Iterator;
import org.apache.poi.util.Removal;

/**
* HorizontalPageBreak (0x001B) record that stores page breaks at rows
*
*
* @see PageBreakRecord
*/
public final class HorizontalPageBreakRecord extends PageBreakRecord implements Cloneable {
public final class HorizontalPageBreakRecord extends PageBreakRecord {

public static final short sid = 0x001B;

/**
* Creates an empty horizontal page break record
*/
public HorizontalPageBreakRecord() {
public HorizontalPageBreakRecord() {}

public HorizontalPageBreakRecord(HorizontalPageBreakRecord other) {
super(other);
}

/**
@@ -46,13 +49,15 @@ public final class HorizontalPageBreakRecord extends PageBreakRecord implements
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public PageBreakRecord clone() {
PageBreakRecord result = new HorizontalPageBreakRecord();
Iterator<Break> iterator = getBreaksIterator();
while (iterator.hasNext()) {
Break original = iterator.next();
result.addBreak(original.main, original.subFrom, original.subTo);
}
return result;
return copy();
}

@Override
public HorizontalPageBreakRecord copy() {
return new HorizontalPageBreakRecord(this);
}
}

+ 60
- 41
src/java/org/apache/poi/hssf/record/HyperlinkRecord.java View File

@@ -27,6 +27,7 @@ import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;
import org.apache.poi.util.StringUtil;

/**
@@ -34,13 +35,14 @@ import org.apache.poi.util.StringUtil;
* from the Excel-97 format.
* Supports only external links for now (eg http://)
*/
public final class HyperlinkRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x01B8;
public final class HyperlinkRecord extends StandardRecord {
public static final short sid = 0x01B8;
private static POILogger logger = POILogFactory.getLogger(HyperlinkRecord.class);
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;


// TODO: replace with ClassID
static final class GUID {
/*
* this class is currently only used here, but could be moved to a
@@ -61,6 +63,13 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {
*/
private final long _d4;

public GUID(GUID other) {
_d1 = other._d1;
_d2 = other._d2;
_d3 = other._d3;
_d4 = other._d4;
}

public GUID(LittleEndianInput in) {
this(in.readInt(), in.readUShort(), in.readUShort(), in.readLong());
}
@@ -199,24 +208,24 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {
}
}

/**
/*
* Link flags
*/
static final int HLINK_URL = 0x01; // File link or URL.
static final int HLINK_ABS = 0x02; // Absolute path.
static final int HLINK_LABEL = 0x14; // Has label/description.
static final int HLINK_URL = 0x01; // File link or URL.
static final int HLINK_ABS = 0x02; // Absolute path.
static final int HLINK_LABEL = 0x14; // Has label/description.
/** Place in worksheet. If set, the {@link #_textMark} field will be present */
static final int HLINK_PLACE = 0x08;
static final int HLINK_PLACE = 0x08;
private static final int HLINK_TARGET_FRAME = 0x80; // has 'target frame'
private static final int HLINK_UNC_PATH = 0x100; // has UNC path

final static GUID STD_MONIKER = GUID.parse("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B");
final static GUID URL_MONIKER = GUID.parse("79EAC9E0-BAF9-11CE-8C82-00AA004BA90B");
final static GUID FILE_MONIKER = GUID.parse("00000303-0000-0000-C000-000000000046");
static final GUID STD_MONIKER = GUID.parse("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B");
static final GUID URL_MONIKER = GUID.parse("79EAC9E0-BAF9-11CE-8C82-00AA004BA90B");
static final GUID FILE_MONIKER = GUID.parse("00000303-0000-0000-C000-000000000046");
/** expected Tail of a URL link */
private final static byte[] URL_TAIL = HexRead.readFromString("79 58 81 F4 3B 1D 7F 48 AF 2C 82 5D C4 85 27 63 00 00 00 00 A5 AB 00 00");
private static final byte[] URL_TAIL = HexRead.readFromString("79 58 81 F4 3B 1D 7F 48 AF 2C 82 5D C4 85 27 63 00 00 00 00 A5 AB 00 00");
/** expected Tail of a file link */
private final static byte[] FILE_TAIL = HexRead.readFromString("FF FF AD DE 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
private static final byte[] FILE_TAIL = HexRead.readFromString("FF FF AD DE 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");

private static final int TAIL_SIZE = FILE_TAIL.length;

@@ -246,17 +255,31 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {
* This field is optional. If present, the {@link #HLINK_PLACE} must be set.
*/
private String _textMark;
private byte[] _uninterpretedTail;

/**
* Create a new hyperlink
*/
public HyperlinkRecord()
{
public HyperlinkRecord() {}


public HyperlinkRecord(HyperlinkRecord other) {
super(other);
_range = (other._range == null) ? null : other._range.copy();
_guid = (other._guid == null) ? null : new GUID(other._guid);
_fileOpts = other._fileOpts;
_linkOpts = other._linkOpts;
_label = other._label;
_targetFrame = other._targetFrame;
_moniker = (other._moniker == null) ? null : new GUID(other._moniker);
_shortFilename = other._shortFilename;
_address = other._address;
_textMark = other._textMark;
_uninterpretedTail = (other._uninterpretedTail == null) ? null : other._uninterpretedTail.clone();
}


/**
* @return the 0-based column of the first cell that contains this hyperlink
*/
@@ -266,7 +289,7 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {

/**
* Set the first column (zero-based) of the range that contains this hyperlink
*
*
* @param firstCol the first column (zero-based)
*/
public void setFirstColumn(int firstCol) {
@@ -282,7 +305,7 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {

/**
* Set the last column (zero-based) of the range that contains this hyperlink
*
*
* @param lastCol the last column (zero-based)
*/
public void setLastColumn(int lastCol) {
@@ -298,7 +321,7 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {

/**
* Set the first row (zero-based) of the range that contains this hyperlink
*
*
* @param firstRow the first row (zero-based)
*/
public void setFirstRow(int firstRow) {
@@ -314,7 +337,7 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {

/**
* Set the last row (zero-based) of the range that contains this hyperlink
*
*
* @param lastRow the last row (zero-based)
*/
public void setLastRow(int lastRow) {
@@ -423,7 +446,7 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {
/**
* Link options. Must be a combination of HLINK_* constants.
* For testing only
*
*
* @return Link options
*/
int getLinkOptions(){
@@ -541,7 +564,7 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {
}

if (in.remaining() > 0) {
logger.log(POILogger.WARN,
logger.log(POILogger.WARN,
"Hyperlink data remains: " + in.remaining() +
" : " +HexDump.toHex(in.readRemainder())
);
@@ -699,31 +722,31 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {

/**
* Based on the link options, is this a url?
*
*
* @return true, if this is a url link
*/
public boolean isUrlLink() {
return (_linkOpts & HLINK_URL) > 0
return (_linkOpts & HLINK_URL) > 0
&& (_linkOpts & HLINK_ABS) > 0;
}
/**
* Based on the link options, is this a file?
*
*
* @return true, if this is a file link
*/
public boolean isFileLink() {
return (_linkOpts & HLINK_URL) > 0
return (_linkOpts & HLINK_URL) > 0
&& (_linkOpts & HLINK_ABS) == 0;
}
/**
* Based on the link options, is this a document?
*
*
* @return true, if this is a docment link
*/
public boolean isDocumentLink() {
return (_linkOpts & HLINK_PLACE) > 0;
return (_linkOpts & HLINK_PLACE) > 0;
}
/**
* Initialize a new url link
*/
@@ -766,19 +789,15 @@ public final class HyperlinkRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public HyperlinkRecord clone() {
HyperlinkRecord rec = new HyperlinkRecord();
rec._range = _range.copy();
rec._guid = _guid;
rec._linkOpts = _linkOpts;
rec._fileOpts = _fileOpts;
rec._label = _label;
rec._address = _address;
rec._moniker = _moniker;
rec._shortFilename = _shortFilename;
rec._targetFrame = _targetFrame;
rec._textMark = _textMark;
rec._uninterpretedTail = _uninterpretedTail;
return rec;
return copy();
}

@Override
public HyperlinkRecord copy() {
return new HyperlinkRecord(this);
}
}

+ 26
- 22
src/java/org/apache/poi/hssf/record/IndexRecord.java View File

@@ -20,27 +20,29 @@ package org.apache.poi.hssf.record;
import org.apache.poi.util.IntList;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;

/**
* Title: Index Record (0x020B)<p>
* Description: Occurs right after BOF, tells you where the DBCELL records are for a sheet
* Important for locating cells<p>
*
* REFERENCE: PG 323 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Occurs right after BOF, tells you where the DBCELL records are for a sheet Important for locating cells
*/
public final class IndexRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x020B;
public final class IndexRecord extends StandardRecord {
public static final short sid = 0x020B;
private int field_2_first_row; // first row on the sheet
private int field_3_last_row_add1; // last row
private int field_4_zero; // supposed to be zero
private IntList field_5_dbcells; // array of offsets to DBCELL records

public IndexRecord()
{
public IndexRecord() {}

public IndexRecord(IndexRecord other) {
super(other);
field_2_first_row = other.field_2_first_row;
field_3_last_row_add1 = other.field_3_last_row_add1;
field_4_zero = other.field_4_zero;
field_5_dbcells = (other.field_5_dbcells == null) ? null : new IntList(other.field_5_dbcells);
}

public IndexRecord(RecordInputStream in)
{
public IndexRecord(RecordInputStream in) {
int field_1_zero = in.readInt();
if (field_1_zero != 0) {
throw new RecordFormatException("Expected zero for field 1 but got " + field_1_zero);
@@ -48,7 +50,7 @@ public final class IndexRecord extends StandardRecord implements Cloneable {
field_2_first_row = in.readInt();
field_3_last_row_add1 = in.readInt();
field_4_zero = in.readInt();
int nCells = in.remaining() / 4;
field_5_dbcells = new IntList(nCells);
for(int i=0; i<nCells; i++) {
@@ -139,14 +141,14 @@ public final class IndexRecord extends StandardRecord implements Cloneable {
return 16 // 4 ints
+ getNumDbcells() * 4;
}
/**
/**
* @param blockCount the number of blocks to be indexed
* @return the size of an IndexRecord when it needs to index the specified number of blocks
*/
public static int getRecordSizeForBlockCount(int blockCount) {
return 20 + 4 * blockCount;
}
}

@Override
public short getSid() {
@@ -154,13 +156,15 @@ public final class IndexRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public IndexRecord clone() {
IndexRecord rec = new IndexRecord();
rec.field_2_first_row = field_2_first_row;
rec.field_3_last_row_add1 = field_3_last_row_add1;
rec.field_4_zero = field_4_zero;
rec.field_5_dbcells = new IntList();
rec.field_5_dbcells.addAll(field_5_dbcells);
return rec;
return copy();
}

@Override
public IndexRecord copy() {
return new IndexRecord(this);
}
}

+ 6
- 5
src/java/org/apache/poi/hssf/record/InterfaceEndRecord.java View File

@@ -21,11 +21,7 @@ import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;

/**
* Title: Interface End Record (0x00E2)<P>
* Description: Shows where the Interface Records end (MMS)
* (has no fields)<P>
* REFERENCE: PG 324 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* Shows where the Interface Records ends (MMS)
*/
public final class InterfaceEndRecord extends StandardRecord {

@@ -61,4 +57,9 @@ public final class InterfaceEndRecord extends StandardRecord {
public short getSid() {
return sid;
}

@Override
public InterfaceEndRecord copy() {
return instance;
}
}

+ 15
- 7
src/java/org/apache/poi/hssf/record/InterfaceHdrRecord.java View File

@@ -21,19 +21,22 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;

/**
* Title: Interface Header Record (0x00E1)<P>
* Description: Defines the beginning of Interface records (MMS)<P>
* REFERENCE: PG 324 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* Defines the beginning of Interface records (MMS)
*/
public final class InterfaceHdrRecord extends StandardRecord {
public final static short sid = 0x00E1;
private final int _codepage;
public static final short sid = 0x00E1;

/**
* suggested (and probably correct) default
*/
public final static int CODEPAGE = 0x04B0;
public static final int CODEPAGE = 0x04B0;

private final int _codepage;

public InterfaceHdrRecord(InterfaceHdrRecord other) {
super(other);
_codepage = other._codepage;
}

public InterfaceHdrRecord(int codePage) {
_codepage = codePage;
@@ -63,4 +66,9 @@ public final class InterfaceHdrRecord extends StandardRecord {
public short getSid() {
return sid;
}

@Override
public InterfaceHdrRecord copy() {
return new InterfaceHdrRecord(this);
}
}

+ 21
- 11
src/java/org/apache/poi/hssf/record/IterationRecord.java View File

@@ -21,28 +21,30 @@ import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Iteration Record (0x0011)<p>
* Description: Tells whether to iterate over formula calculations or not
* (if a formula is dependent upon another formula's result)
* (odd feature for something that can only have 32 elements in
* a formula!)<p>
* REFERENCE: PG 325 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Tells whether to iterate over formula calculations or not.
* If a formula is dependent upon another formula's result.
* (odd feature for something that can only have 32 elements in a formula!)
*/
public final class IterationRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x0011;
public final class IterationRecord extends StandardRecord {
public static final short sid = 0x0011;

private static final BitField iterationOn = BitFieldFactory.getInstance(0x0001);

private int _flags;

public IterationRecord(IterationRecord other) {
super(other);
_flags = other._flags;
}

public IterationRecord(boolean iterateOn) {
_flags = iterationOn.setBoolean(0, iterateOn);
}

public IterationRecord(RecordInputStream in)
{
public IterationRecord(RecordInputStream in) {
_flags = in.readShort();
}

@@ -85,7 +87,15 @@ public final class IterationRecord extends StandardRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public IterationRecord clone() {
return new IterationRecord(getIteration());
return copy();
}

@Override
public IterationRecord copy() {
return new IterationRecord(this);
}
}

+ 32
- 24
src/java/org/apache/poi/hssf/record/LabelRecord.java View File

@@ -21,36 +21,43 @@ import org.apache.poi.util.HexDump;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;

/**
* Label Record (0x0204) - read only support for strings stored directly in the cell...
* Don't use this (except to read), use LabelSST instead <P>
* REFERENCE: PG 325 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
*
* Don't use this (except to read), use LabelSST instead
*
* @see org.apache.poi.hssf.record.LabelSSTRecord
*/
public final class LabelRecord extends Record implements CellValueRecordInterface, Cloneable {
private final static POILogger logger = POILogFactory.getLogger(LabelRecord.class);
public final class LabelRecord extends Record implements CellValueRecordInterface {
private static final POILogger logger = POILogFactory.getLogger(LabelRecord.class);

public final static short sid = 0x0204;
public static final short sid = 0x0204;

private int field_1_row;
private short field_2_column;
private short field_3_xf_index;
private short field_4_string_len;
private byte field_5_unicode_flag;
private String field_6_value;
private int field_1_row;
private short field_2_column;
private short field_3_xf_index;
private short field_4_string_len;
private byte field_5_unicode_flag;
private String field_6_value;

/** Creates new LabelRecord */
public LabelRecord()
{
public LabelRecord() {}

public LabelRecord(LabelRecord other) {
super(other);
field_1_row = other.field_1_row;
field_2_column = other.field_2_column;
field_3_xf_index = other.field_3_xf_index;
field_4_string_len = other.field_4_string_len;
field_5_unicode_flag = other.field_5_unicode_flag;
field_6_value = other.field_6_value;
}

/**
* @param in the RecordInputstream to read the record from
*/
public LabelRecord(RecordInputStream in)
{
public LabelRecord(RecordInputStream in) {
field_1_row = in.readUShort();
field_2_column = in.readShort();
field_3_xf_index = in.readShort();
@@ -182,14 +189,15 @@ public final class LabelRecord extends Record implements CellValueRecordInterfac
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public LabelRecord clone() {
LabelRecord rec = new LabelRecord();
rec.field_1_row = field_1_row;
rec.field_2_column = field_2_column;
rec.field_3_xf_index = field_3_xf_index;
rec.field_4_string_len = field_4_string_len;
rec.field_5_unicode_flag = field_5_unicode_flag;
rec.field_6_value = field_6_value;
return rec;
return copy();
}

@Override
public LabelRecord copy() {
return new LabelRecord(this);
}
}

+ 19
- 12
src/java/org/apache/poi/hssf/record/LabelSSTRecord.java View File

@@ -19,18 +19,20 @@ package org.apache.poi.hssf.record;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Label SST Record<P>
* Description: Refers to a string in the shared string table and is a column value.<P>
* REFERENCE: PG 325 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* Refers to a string in the shared string table and is a column value.
*/
public final class LabelSSTRecord extends CellRecord implements Cloneable {
public final static short sid = 0xfd;
public final class LabelSSTRecord extends CellRecord {
public static final short sid = 0xfd;
private int field_4_sst_index;

public LabelSSTRecord() {
// fields uninitialised
public LabelSSTRecord() {}

public LabelSSTRecord(LabelSSTRecord other) {
super(other);
field_4_sst_index = other.field_4_sst_index;
}

public LabelSSTRecord(RecordInputStream in) {
@@ -58,7 +60,7 @@ public final class LabelSSTRecord extends CellRecord implements Cloneable {
public int getSSTIndex() {
return field_4_sst_index;
}
@Override
protected String getRecordName() {
return "LABELSST";
@@ -85,10 +87,15 @@ public final class LabelSSTRecord extends CellRecord implements Cloneable {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public LabelSSTRecord clone() {
LabelSSTRecord rec = new LabelSSTRecord();
copyBaseFields(rec);
rec.field_4_sst_index = field_4_sst_index;
return rec;
return copy();
}

@Override
public LabelSSTRecord copy() {
return new LabelSSTRecord(this);
}
}

+ 48
- 12
src/java/org/apache/poi/hssf/record/LbsDataSubRecord.java View File

@@ -16,11 +16,13 @@
==================================================================== */
package org.apache.poi.hssf.record;

import org.apache.poi.common.Duplicatable;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Removal;
import org.apache.poi.util.StringUtil;

/**
@@ -89,6 +91,24 @@ public class LbsDataSubRecord extends SubRecord {
*/
private boolean[] _bsels;

LbsDataSubRecord() {}

public LbsDataSubRecord(LbsDataSubRecord other) {
super(other);
_cbFContinued = other._cbFContinued;
_unknownPreFormulaInt = other._unknownPreFormulaInt;
_linkPtg = (other._linkPtg == null) ? null : other._linkPtg.copy();
_unknownPostFormulaByte = other._unknownPostFormulaByte;
_cLines = other._cLines;
_iSel = other._iSel;
_flags = other._flags;
_idEdit = other._idEdit;
_dropData = (other._dropData == null) ? null : other._dropData.copy();
_rgLines = (other._rgLines == null) ? null : other._rgLines.clone();
_bsels = (other._bsels == null) ? null : other._bsels.clone();
}


/**
* @param in the stream to read data from
* @param cbFContinued the seconf short in the record header
@@ -154,10 +174,6 @@ public class LbsDataSubRecord extends SubRecord {

}

LbsDataSubRecord(){

}

/**
*
* @return a new instance of LbsDataSubRecord to construct auto-filters
@@ -259,9 +275,16 @@ public class LbsDataSubRecord extends SubRecord {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public LbsDataSubRecord clone() {
// TODO: is immutable ???
return this;
return copy();
}

@Override
public LbsDataSubRecord copy() {
return new LbsDataSubRecord(this);
}

@Override
@@ -303,7 +326,7 @@ public class LbsDataSubRecord extends SubRecord {
/**
* This structure specifies properties of the dropdown list control
*/
public static class LbsDropData {
public static class LbsDropData implements Duplicatable {
/**
* Combo dropdown control
*/
@@ -318,7 +341,7 @@ public class LbsDataSubRecord extends SubRecord {
public static final int STYLE_COMBO_SIMPLE_DROPDOWN = 2;

/**
* An unsigned integer that specifies the style of this dropdown.
* An unsigned integer that specifies the style of this dropdown.
*/
private int _wStyle;

@@ -343,12 +366,20 @@ public class LbsDataSubRecord extends SubRecord {
*/
private Byte _unused;

public LbsDropData(){
public LbsDropData() {
_str = "";
_unused = 0;
}

public LbsDropData(LittleEndianInput in){
public LbsDropData(LbsDropData other) {
_wStyle = other._wStyle;
_cLine = other._cLine;
_dxMin = other._dxMin;
_str = other._str;
_unused = other._unused;
}

public LbsDropData(LittleEndianInput in) {
_wStyle = in.readUShort();
_cLine = in.readUShort();
_dxMin = in.readUShort();
@@ -367,7 +398,7 @@ public class LbsDataSubRecord extends SubRecord {
* <li>1: Combo Edit dropdown control</li>
* <li>2: Simple dropdown control (just the dropdown button)</li>
* </ul>
*
*
* @param style the style - see possible values
*/
public void setStyle(int style){
@@ -376,7 +407,7 @@ public class LbsDataSubRecord extends SubRecord {

/**
* Set the number of lines to be displayed in the dropdown.
*
*
* @param num the number of lines to be displayed in the dropdown
*/
public void setNumLines(int num){
@@ -417,5 +448,10 @@ public class LbsDataSubRecord extends SubRecord {

return sb.toString();
}

@Override
public LbsDropData copy() {
return new LbsDropData(this);
}
}
}

+ 20
- 9
src/java/org/apache/poi/hssf/record/LeftMarginRecord.java View File

@@ -18,18 +18,23 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Record for the left margin.
*/
public final class LeftMarginRecord extends StandardRecord implements Margin, Cloneable {
public final static short sid = 0x0026;
public final class LeftMarginRecord extends StandardRecord implements Margin {
public static final short sid = 0x0026;
private double field_1_margin;

public LeftMarginRecord() { }
public LeftMarginRecord() {}

public LeftMarginRecord(RecordInputStream in)
{
public LeftMarginRecord(LeftMarginRecord other) {
super(other);
field_1_margin = other.field_1_margin;
}

public LeftMarginRecord(RecordInputStream in) {
field_1_margin = in.readDouble();
}

@@ -70,9 +75,15 @@ public final class LeftMarginRecord extends StandardRecord implements Margin, Cl
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public LeftMarginRecord clone() {
LeftMarginRecord rec = new LeftMarginRecord();
rec.field_1_margin = this.field_1_margin;
return rec;
return copy();
}

@Override
public LeftMarginRecord copy() {
return new LeftMarginRecord(this);
}
}
}

+ 20
- 17
src/java/org/apache/poi/hssf/record/MMSRecord.java View File

@@ -15,38 +15,36 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;

/**
* Title: MMS Record<P>
* Description: defines how many add menu and del menu options are stored
* in the file. Should always be set to 0 for HSSF workbooks<P>
* REFERENCE: PG 328 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
* defines how many add menu and del menu options are stored in the file.
* Should always be set to 0 for HSSF workbooks.
*
* @version 2.0-pre
*/

public final class MMSRecord
extends StandardRecord
{
public final static short sid = 0xC1;
private byte field_1_addMenuCount; // = 0;
private byte field_2_delMenuCount; // = 0;
public final class MMSRecord extends StandardRecord {
public static final short sid = 0xC1;
private byte field_1_addMenuCount;
private byte field_2_delMenuCount;

public MMSRecord()
{
public MMSRecord() {}

public MMSRecord(MMSRecord other) {
field_1_addMenuCount = other.field_1_addMenuCount;
field_2_delMenuCount = other.field_2_delMenuCount;
}

public MMSRecord(RecordInputStream in)
{
public MMSRecord(RecordInputStream in) {
if (in.remaining()==0) {
return;
}
field_1_addMenuCount = in.readByte();
field_2_delMenuCount = in.readByte();
}
@@ -117,4 +115,9 @@ public final class MMSRecord
{
return sid;
}

@Override
public MMSRecord copy() {
return new MMSRecord(this);
}
}

+ 27
- 13
src/java/org/apache/poi/hssf/record/MergeCellsRecord.java View File

@@ -17,22 +17,33 @@

package org.apache.poi.hssf.record;

import java.util.stream.Stream;

import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Merged Cells Record (0x00E5)<p>
*
* Description: Optional record defining a square area of cells to "merged" into one cell.
* Optional record defining a square area of cells to "merged" into one cell.
*/
public final class MergeCellsRecord extends StandardRecord implements Cloneable {
public final static short sid = 0x00E5;
/** sometimes the regions array is shared with other MergedCellsRecords */
public final class MergeCellsRecord extends StandardRecord {
public static final short sid = 0x00E5;

/** sometimes the regions array is shared with other MergedCellsRecords */
private final CellRangeAddress[] _regions;
private final int _startIndex;
private final int _numberOfRegions;

public MergeCellsRecord(MergeCellsRecord other) {
super(other);
_regions = (other._regions == null) ? null
: Stream.of(other._regions).map(CellRangeAddress::copy).toArray(CellRangeAddress[]::new);
_startIndex = other._startIndex;
_numberOfRegions = other._numberOfRegions;
}


public MergeCellsRecord(CellRangeAddress[] regions, int startIndex, int numberOfRegions) {
_regions = regions;
_startIndex = startIndex;
@@ -63,7 +74,7 @@ public final class MergeCellsRecord extends StandardRecord implements Cloneable

/**
* @param index the n-th MergedRegion
*
*
* @return MergedRegion at the given index representing the area that is Merged (r1,c1 - r2,c2)
*/
public CellRangeAddress getAreaAt(int index) {
@@ -107,12 +118,15 @@ public final class MergeCellsRecord extends StandardRecord implements Cloneable
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public MergeCellsRecord clone() {
int nRegions = _numberOfRegions;
CellRangeAddress[] clonedRegions = new CellRangeAddress[nRegions];
for (int i = 0; i < clonedRegions.length; i++) {
clonedRegions[i] = _regions[_startIndex + i].copy();
}
return new MergeCellsRecord(clonedRegions, 0, nRegions);
return copy();
}
@Override
public MergeCellsRecord copy() {
return new MergeCellsRecord(this);
}
}

+ 14
- 8
src/java/org/apache/poi/hssf/record/MulBlankRecord.java View File

@@ -18,17 +18,15 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.Removal;

/**
* Title: Multiple Blank cell record(0x00BE)<p>
* Description: Represents a set of columns in a row with no value but with styling.<p>
* Represents a set of columns in a row with no value but with styling.
*
* REFERENCE: PG 329 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
*
* @see BlankRecord
*/
public final class MulBlankRecord extends StandardRecord {
public final static short sid = 0x00BE;
public static final short sid = 0x00BE;

private final int _row;
private final int _firstCol;
@@ -55,7 +53,7 @@ public final class MulBlankRecord extends StandardRecord {
public int getFirstColumn() {
return _firstCol;
}
/**
* @return ending column (last cell this holds in the row). Zero based
*/
@@ -122,8 +120,8 @@ public final class MulBlankRecord extends StandardRecord {
out.writeShort(_row);
out.writeShort(_firstCol);
int nItems = _xfs.length;
for (int i = 0; i < nItems; i++) {
out.writeShort(_xfs[i]);
for (short xf : _xfs) {
out.writeShort(xf);
}
out.writeShort(_lastCol);
}
@@ -134,7 +132,15 @@ public final class MulBlankRecord extends StandardRecord {
}

@Override
@SuppressWarnings("squid:S2975")
@Deprecated
@Removal(version = "5.0.0")
public MulBlankRecord clone() {
return copy();
}

@Override
public MulBlankRecord copy() {
// immutable - so OK to return this
return this;
}

+ 14
- 11
src/java/org/apache/poi/hssf/record/MulRKRecord.java View File

@@ -23,18 +23,15 @@ import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;

/**
* MULRK (0x00BD)<p>
*
* Used to store multiple RK numbers on a row. 1 MulRk = Multiple Cell values.
* HSSF just converts this into multiple NUMBER records. READ-ONLY SUPPORT!<P>
* REFERENCE: PG 330 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
*
* HSSF just converts this into multiple NUMBER records. READ-ONLY SUPPORT!
*
* @since 2.0-pre
*/
public final class MulRKRecord extends StandardRecord {
public final static short sid = 0x00BD;
public static final short sid = 0x00BD;

private final int field_1_row;
private final int field_1_row;
private final short field_2_first_col;
private final RkRec[] field_3_rks;
private final short field_4_last_col;
@@ -69,9 +66,9 @@ public final class MulRKRecord extends StandardRecord {

/**
* returns the xf index for column (coffset = column - field_2_first_col)
*
*
* @param coffset the coffset = column - field_2_first_col
*
*
* @return the XF index for the column
*/
public short getXFAt(int coffset) {
@@ -80,9 +77,9 @@ public final class MulRKRecord extends StandardRecord {

/**
* returns the rk number for column (coffset = column - field_2_first_col)
*
*
* @param coffset the coffset = column - field_2_first_col
*
*
* @return the value (decoded into a double)
*/
public double getRKNumberAt(int coffset) {
@@ -151,4 +148,10 @@ public final class MulRKRecord extends StandardRecord {
return retval;
}
}

@Override
public MulRKRecord copy() {
// immutable - so OK to return this
return this;
}
}

+ 140
- 131
src/java/org/apache/poi/hssf/record/NameCommentRecord.java View File

@@ -18,145 +18,154 @@
package org.apache.poi.hssf.record;

import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil;

/**
* Title: NAMECMT Record (0x0894)<p>
*
* Description: Defines a comment associated with a specified name.
* Defines a comment associated with a specified name.
*/
public final class NameCommentRecord extends StandardRecord {
public final static short sid = 0x0894;

private final short field_1_record_type;
private final short field_2_frt_cell_ref_flag;
private final long field_3_reserved;
//private short field_4_name_length;
//private short field_5_comment_length;
private String field_6_name_text;
private String field_7_comment_text;

public NameCommentRecord(final String name, final String comment) {
field_1_record_type = 0;
field_2_frt_cell_ref_flag = 0;
field_3_reserved = 0;
field_6_name_text = name;
field_7_comment_text = comment;
}

@Override
public void serialize(final LittleEndianOutput out) {
final int field_4_name_length = field_6_name_text.length();
final int field_5_comment_length = field_7_comment_text.length();

out.writeShort(field_1_record_type);
out.writeShort(field_2_frt_cell_ref_flag);
out.writeLong(field_3_reserved);
out.writeShort(field_4_name_length);
out.writeShort(field_5_comment_length);

boolean isNameMultiByte = StringUtil.hasMultibyte(field_6_name_text);
out.writeByte(isNameMultiByte ? 1 : 0);
if (isNameMultiByte) {
StringUtil.putUnicodeLE(field_6_name_text, out);
} else {
StringUtil.putCompressedUnicode(field_6_name_text, out);
public static final short sid = 0x0894;

private final short field_1_record_type;
private final short field_2_frt_cell_ref_flag;
private final long field_3_reserved;
//private short field_4_name_length;
//private short field_5_comment_length;
private String field_6_name_text;
private String field_7_comment_text;

public NameCommentRecord(NameCommentRecord other) {
field_1_record_type = other.field_1_record_type;
field_2_frt_cell_ref_flag = other.field_2_frt_cell_ref_flag;
field_3_reserved = other.field_3_reserved;
field_6_name_text = other.field_6_name_text;
field_7_comment_text = other.field_7_comment_text;
}
boolean isCommentMultiByte = StringUtil.hasMultibyte(field_7_comment_text);
out.writeByte(isCommentMultiByte ? 1 : 0);
if (isCommentMultiByte) {
StringUtil.putUnicodeLE(field_7_comment_text, out);
} else {
StringUtil.putCompressedUnicode(field_7_comment_text, out);

public NameCommentRecord(final String name, final String comment) {
field_1_record_type = 0;
field_2_frt_cell_ref_flag = 0;
field_3_reserved = 0;
field_6_name_text = name;
field_7_comment_text = comment;
}

/**
* @param ris the RecordInputstream to read the record from
*/
public NameCommentRecord(final RecordInputStream ris) {
field_1_record_type = ris.readShort();
field_2_frt_cell_ref_flag = ris.readShort();
field_3_reserved = ris.readLong();
final int field_4_name_length = ris.readShort();
final int field_5_comment_length = ris.readShort();

if (ris.readByte() == 0) {
field_6_name_text = StringUtil.readCompressedUnicode(ris, field_4_name_length);
} else {
field_6_name_text = StringUtil.readUnicodeLE(ris, field_4_name_length);
}
if (ris.readByte() == 0) {
field_7_comment_text = StringUtil.readCompressedUnicode(ris, field_5_comment_length);
} else {
field_7_comment_text = StringUtil.readUnicodeLE(ris, field_5_comment_length);
}
}
}

@Override
protected int getDataSize() {
return 18 // 4 shorts + 1 long + 2 spurious 'nul's
+ (StringUtil.hasMultibyte(field_6_name_text) ? field_6_name_text.length()*2 : field_6_name_text.length())
+ (StringUtil.hasMultibyte(field_7_comment_text) ? field_7_comment_text.length()*2 : field_7_comment_text.length());
}

/**
* @param ris the RecordInputstream to read the record from
*/
public NameCommentRecord(final RecordInputStream ris) {
field_1_record_type = ris.readShort();
field_2_frt_cell_ref_flag = ris.readShort();
field_3_reserved = ris.readLong();
final int field_4_name_length = ris.readShort();
final int field_5_comment_length = ris.readShort();

if (ris.readByte() == 0) {
field_6_name_text = StringUtil.readCompressedUnicode(ris, field_4_name_length);
} else {
field_6_name_text = StringUtil.readUnicodeLE(ris, field_4_name_length);

@Override
public void serialize(final LittleEndianOutput out) {
final int field_4_name_length = field_6_name_text.length();
final int field_5_comment_length = field_7_comment_text.length();

out.writeShort(field_1_record_type);
out.writeShort(field_2_frt_cell_ref_flag);
out.writeLong(field_3_reserved);
out.writeShort(field_4_name_length);
out.writeShort(field_5_comment_length);

boolean isNameMultiByte = StringUtil.hasMultibyte(field_6_name_text);
out.writeByte(isNameMultiByte ? 1 : 0);
if (isNameMultiByte) {
StringUtil.putUnicodeLE(field_6_name_text, out);
} else {
StringUtil.putCompressedUnicode(field_6_name_text, out);
}
boolean isCommentMultiByte = StringUtil.hasMultibyte(field_7_comment_text);
out.writeByte(isCommentMultiByte ? 1 : 0);
if (isCommentMultiByte) {
StringUtil.putUnicodeLE(field_7_comment_text, out);
} else {
StringUtil.putCompressedUnicode(field_7_comment_text, out);
}
}

@Override
protected int getDataSize() {
return 18 // 4 shorts + 1 long + 2 spurious 'nul's
+ (StringUtil.hasMultibyte(field_6_name_text) ? field_6_name_text.length() * 2 : field_6_name_text.length())
+ (StringUtil.hasMultibyte(field_7_comment_text) ? field_7_comment_text.length() * 2 : field_7_comment_text.length());
}
if (ris.readByte() == 0) {
field_7_comment_text = StringUtil.readCompressedUnicode(ris, field_5_comment_length);
} else {
field_7_comment_text = StringUtil.readUnicodeLE(ris, field_5_comment_length);
}
}

/**
* return the non static version of the id for this record.
*/
@Override
public short getSid() {
return sid;
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder();

sb.append("[NAMECMT]\n");
sb.append(" .record type = ").append(HexDump.shortToHex(field_1_record_type)).append("\n");
sb.append(" .frt cell ref flag = ").append(HexDump.byteToHex(field_2_frt_cell_ref_flag)).append("\n");
sb.append(" .reserved = ").append(field_3_reserved).append("\n");
sb.append(" .name length = ").append(field_6_name_text.length()).append("\n");
sb.append(" .comment length = ").append(field_7_comment_text.length()).append("\n");
sb.append(" .name = ").append(field_6_name_text).append("\n");
sb.append(" .comment = ").append(field_7_comment_text).append("\n");
sb.append("[/NAMECMT]\n");

return sb.toString();
}

/**
* @return the name of the NameRecord to which this comment applies.
*/
public String getNameText() {
return field_6_name_text;
}
/**
* Updates the name we're associated with, normally used
* when renaming that Name
*
* @param newName the new name
*/
public void setNameText(String newName) {
field_6_name_text = newName;
}

/**
* @return the text of the comment.
*/
public String getCommentText() {
return field_7_comment_text;
}
public void setCommentText(String comment) {
field_7_comment_text = comment;
}

public short getRecordType() {
return field_1_record_type;
}

/**
* return the non static version of the id for this record.
*/
@Override
public short getSid() {
return sid;
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder();

sb.append("[NAMECMT]\n");
sb.append(" .record type = ").append(HexDump.shortToHex(field_1_record_type)).append("\n");
sb.append(" .frt cell ref flag = ").append(HexDump.byteToHex(field_2_frt_cell_ref_flag)).append("\n");
sb.append(" .reserved = ").append(field_3_reserved).append("\n");
sb.append(" .name length = ").append(field_6_name_text.length()).append("\n");
sb.append(" .comment length = ").append(field_7_comment_text.length()).append("\n");
sb.append(" .name = ").append(field_6_name_text).append("\n");
sb.append(" .comment = ").append(field_7_comment_text).append("\n");
sb.append("[/NAMECMT]\n");

return sb.toString();
}

/**
* @return the name of the NameRecord to which this comment applies.
*/
public String getNameText() {
return field_6_name_text;
}

/**
* Updates the name we're associated with, normally used
* when renaming that Name
*
* @param newName the new name
*/
public void setNameText(String newName) {
field_6_name_text = newName;
}

/**
* @return the text of the comment.
*/
public String getCommentText() {
return field_7_comment_text;
}

public void setCommentText(String comment) {
field_7_comment_text = comment;
}

public short getRecordType() {
return field_1_record_type;
}

@Override
public NameCommentRecord copy() {
return new NameCommentRecord(this);
}
}

+ 43
- 20
src/java/org/apache/poi/hssf/record/NameRecord.java View File

@@ -19,44 +19,46 @@ package org.apache.poi.hssf.record;

import org.apache.poi.hssf.record.cont.ContinuableRecord;
import org.apache.poi.hssf.record.cont.ContinuableRecordOutput;
import org.apache.poi.ss.formula.Formula;
import org.apache.poi.ss.formula.ptg.Area3DPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
import org.apache.poi.ss.formula.Formula;
import org.apache.poi.util.*;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianInput;
import org.apache.poi.util.StringUtil;

/**
* Title: DEFINEDNAME Record (0x0018)<p>
* Description: Defines a named range within a workbook.
* Defines a named range within a workbook.
*/
public final class NameRecord extends ContinuableRecord {
public final static short sid = 0x0018;
public static final short sid = 0x0018;
/**Included for completeness sake, not implemented */
public final static byte BUILTIN_CONSOLIDATE_AREA = 1;
public static final byte BUILTIN_CONSOLIDATE_AREA = 1;
/**Included for completeness sake, not implemented */
public final static byte BUILTIN_AUTO_OPEN = 2;
public static final byte BUILTIN_AUTO_OPEN = 2;
/**Included for completeness sake, not implemented */
public final static byte BUILTIN_AUTO_CLOSE = 3;
public static final byte BUILTIN_AUTO_CLOSE = 3;
/**Included for completeness sake, not implemented */
public final static byte BUILTIN_DATABASE = 4;
public static final byte BUILTIN_DATABASE = 4;
/**Included for completeness sake, not implemented */
public final static byte BUILTIN_CRITERIA = 5;
public static final byte BUILTIN_CRITERIA = 5;

public final static byte BUILTIN_PRINT_AREA = 6;
public final static byte BUILTIN_PRINT_TITLE = 7;
public static final byte BUILTIN_PRINT_AREA = 6;
public static final byte BUILTIN_PRINT_TITLE = 7;

/**Included for completeness sake, not implemented */
public final static byte BUILTIN_RECORDER = 8;
public static final byte BUILTIN_RECORDER = 8;
/**Included for completeness sake, not implemented */
public final static byte BUILTIN_DATA_FORM = 9;
public static final byte BUILTIN_DATA_FORM = 9;
/**Included for completeness sake, not implemented */
public final static byte BUILTIN_AUTO_ACTIVATE = 10;
public static final byte BUILTIN_AUTO_ACTIVATE = 10;
/**Included for completeness sake, not implemented */
public final static byte BUILTIN_AUTO_DEACTIVATE = 11;
public static final byte BUILTIN_AUTO_DEACTIVATE = 11;
/**Included for completeness sake, not implemented */
public final static byte BUILTIN_SHEET_TITLE = 12;
public static final byte BUILTIN_SHEET_TITLE = 12;

public final static byte BUILTIN_FILTER_DB = 13;
public static final byte BUILTIN_FILTER_DB = 13;

private static final class Option {
public static final int OPT_HIDDEN_NAME = 0x0001;
@@ -98,10 +100,26 @@ public final class NameRecord extends ContinuableRecord {
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
* @param sheetNumber the sheet which the name applies to
*/
public NameRecord(byte builtin, int sheetNumber)
{
@@ -276,7 +294,7 @@ public final class NameRecord extends ContinuableRecord {

/**
* 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()
@@ -590,4 +608,9 @@ public final class NameRecord extends ContinuableRecord {

return "Unknown";
}

@Override
public NameRecord copy() {
return new NameRecord(this);
}
}

+ 0
- 0
src/java/org/apache/poi/hssf/record/NoteRecord.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save