mirror of https://github.com/apache/poi.git
Apply some IDE suggestions, JavaDoc and GitHub PR
Update assertion-message Adjust JavaDoc Add tests Reformat class DirectoryNode, adjust/move some comments Closes #730 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1921980 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
83384ccf90
commit
c1f018f79c
|
@ -26,7 +26,6 @@ import java.security.GeneralSecurityException;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.Provider;
|
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
|
@ -52,14 +51,11 @@ import javax.xml.crypto.URIDereferencer;
|
||||||
import javax.xml.crypto.dsig.CanonicalizationMethod;
|
import javax.xml.crypto.dsig.CanonicalizationMethod;
|
||||||
import javax.xml.crypto.dsig.DigestMethod;
|
import javax.xml.crypto.dsig.DigestMethod;
|
||||||
import javax.xml.crypto.dsig.Transform;
|
import javax.xml.crypto.dsig.Transform;
|
||||||
import javax.xml.crypto.dsig.XMLSignatureFactory;
|
|
||||||
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.poi.EncryptedDocumentException;
|
import org.apache.poi.EncryptedDocumentException;
|
||||||
import org.apache.poi.hpsf.ClassID;
|
import org.apache.poi.hpsf.ClassID;
|
||||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
|
||||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
|
import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
|
||||||
import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet;
|
import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet;
|
||||||
|
@ -73,7 +69,6 @@ import org.apache.poi.poifs.crypt.dsig.services.TimeStampHttpClient;
|
||||||
import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
|
import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
|
||||||
import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator;
|
import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator;
|
||||||
import org.apache.poi.poifs.crypt.dsig.services.TimeStampSimpleHttpClient;
|
import org.apache.poi.poifs.crypt.dsig.services.TimeStampSimpleHttpClient;
|
||||||
import org.apache.poi.util.Internal;
|
|
||||||
import org.apache.poi.util.LocaleUtil;
|
import org.apache.poi.util.LocaleUtil;
|
||||||
import org.apache.poi.util.Removal;
|
import org.apache.poi.util.Removal;
|
||||||
import org.apache.xml.security.signature.XMLSignature;
|
import org.apache.xml.security.signature.XMLSignature;
|
||||||
|
@ -382,7 +377,7 @@ public class SignatureConfig {
|
||||||
* @since POI 4.0.0
|
* @since POI 4.0.0
|
||||||
*/
|
*/
|
||||||
public void setExecutionTime(String executionTime) {
|
public void setExecutionTime(String executionTime) {
|
||||||
if (executionTime != null && !"".equals(executionTime)){
|
if (executionTime != null && !executionTime.isEmpty()){
|
||||||
final DateFormat fmt = new SimpleDateFormat(SIGNATURE_TIME_FORMAT, Locale.ROOT);
|
final DateFormat fmt = new SimpleDateFormat(SIGNATURE_TIME_FORMAT, Locale.ROOT);
|
||||||
fmt.setTimeZone(LocaleUtil.TIMEZONE_UTC);
|
fmt.setTimeZone(LocaleUtil.TIMEZONE_UTC);
|
||||||
try {
|
try {
|
||||||
|
@ -992,12 +987,12 @@ public class SignatureConfig {
|
||||||
* <li>the JDK xmlsec provider</li>
|
* <li>the JDK xmlsec provider</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*
|
*
|
||||||
* @return a list of possible XMLSEC provider class names
|
* @return an array of possible XMLSEC provider class names
|
||||||
*/
|
*/
|
||||||
public static String[] getProviderNames() {
|
public static String[] getProviderNames() {
|
||||||
// need to check every time, as the system property might have been changed in the meantime
|
// need to check every time, as the system property might have been changed in the meantime
|
||||||
String sysProp = System.getProperty("jsr105Provider");
|
String sysProp = System.getProperty("jsr105Provider");
|
||||||
return (sysProp == null || "".equals(sysProp))
|
return (sysProp == null || sysProp.isEmpty())
|
||||||
? new String[]{XMLSEC_SANTUARIO, XMLSEC_JDK}
|
? new String[]{XMLSEC_SANTUARIO, XMLSEC_JDK}
|
||||||
: new String[]{sysProp, XMLSEC_SANTUARIO, XMLSEC_JDK};
|
: new String[]{sysProp, XMLSEC_SANTUARIO, XMLSEC_JDK};
|
||||||
}
|
}
|
||||||
|
@ -1031,7 +1026,7 @@ public class SignatureConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The signature config can be updated if a document is succesful validated.
|
* The signature config can be updated if a document is succesful validated.
|
||||||
* This flag is used for activating this modifications.
|
* This flag is used for activating these modifications.
|
||||||
* Defaults to {@code false}
|
* Defaults to {@code false}
|
||||||
*
|
*
|
||||||
* @param updateConfigOnValidate if true, update config on validate
|
* @param updateConfigOnValidate if true, update config on validate
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.poi.xslf.usermodel;
|
||||||
import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
|
import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
@ -467,21 +468,21 @@ class TestXSLFTextParagraph {
|
||||||
attributes = iterator.getAttributes();
|
attributes = iterator.getAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("This is a".equals(sb.toString())) {
|
if ("This is a".contentEquals(sb)) {
|
||||||
// Should be no background.
|
// Should be no background.
|
||||||
assertNotNull(attributes);
|
assertNotNull(attributes);
|
||||||
Object background = attributes.get(TextAttribute.BACKGROUND);
|
Object background = attributes.get(TextAttribute.BACKGROUND);
|
||||||
assertNull(background);
|
assertNull(background);
|
||||||
}
|
}
|
||||||
if ("highlight".equals(sb.toString())) {
|
if ("highlight".contentEquals(sb)) {
|
||||||
// Should be yellow background.
|
// Should be yellow background.
|
||||||
assertNotNull(attributes);
|
assertNotNull(attributes);
|
||||||
Object background = attributes.get(TextAttribute.BACKGROUND);
|
Object background = attributes.get(TextAttribute.BACKGROUND);
|
||||||
assertNotNull(background);
|
assertNotNull(background);
|
||||||
assertTrue(background instanceof Color);
|
assertInstanceOf(Color.class, background);
|
||||||
assertEquals(Color.yellow, background);
|
assertEquals(Color.yellow, background);
|
||||||
}
|
}
|
||||||
if (" test".equals(sb.toString())) {
|
if (" test".contentEquals(sb)) {
|
||||||
// Should be no background.
|
// Should be no background.
|
||||||
assertNotNull(attributes);
|
assertNotNull(attributes);
|
||||||
Object background = attributes.get(TextAttribute.BACKGROUND);
|
Object background = attributes.get(TextAttribute.BACKGROUND);
|
||||||
|
@ -494,5 +495,4 @@ class TestXSLFTextParagraph {
|
||||||
ppt.getSlides().get(0).draw(dgfx);
|
ppt.getSlides().get(0).draw(dgfx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3331,7 +3331,7 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues {
|
||||||
LOG.atInfo().log(between(start, now()));
|
LOG.atInfo().log(between(start, now()));
|
||||||
|
|
||||||
assertTrue(between(start, now()).getSeconds() < 25,
|
assertTrue(between(start, now()).getSeconds() < 25,
|
||||||
"Had start: " + start + ", now: " + now() +
|
"Expected to have less than 25s duration for test, but had start: " + start + ", now: " + now() +
|
||||||
", diff: " + Duration.between(start, now()).getSeconds());
|
", diff: " + Duration.between(start, now()).getSeconds());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -447,8 +447,9 @@ public abstract class PropertiesChunk extends Chunk {
|
||||||
/**
|
/**
|
||||||
* Writes out pre-calculated raw values which assume any variable length property `data`
|
* Writes out pre-calculated raw values which assume any variable length property `data`
|
||||||
* field to already have size, reserved and manually written header
|
* field to already have size, reserved and manually written header
|
||||||
* @param out
|
*
|
||||||
* @throws IOException
|
* @param out The OutputStream to write the data to
|
||||||
|
* @throws IOException If an I/O error occurs while writing data
|
||||||
*/
|
*/
|
||||||
private void writeVariableLengthPreCalculatedValue(OutputStream out, PropertyValue value) throws IOException {
|
private void writeVariableLengthPreCalculatedValue(OutputStream out, PropertyValue value) throws IOException {
|
||||||
// variable length header
|
// variable length header
|
||||||
|
|
|
@ -291,7 +291,7 @@ public final class HWPFDocument extends HWPFDocumentCore {
|
||||||
_text = _tpt.getText();
|
_text = _tpt.getText();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in this mode we preserving PAPX/CHPX structure from file, so text may
|
* in this mode we are preserving PAPX/CHPX structure from file, so text may
|
||||||
* miss from output, and text order may be corrupted
|
* miss from output, and text order may be corrupted
|
||||||
*/
|
*/
|
||||||
boolean preserveBinTables = false;
|
boolean preserveBinTables = false;
|
||||||
|
|
|
@ -173,7 +173,7 @@ public final class RecordFactory {
|
||||||
*
|
*
|
||||||
* @param in the InputStream from which the records will be obtained
|
* @param in the InputStream from which the records will be obtained
|
||||||
*
|
*
|
||||||
* @return an array of Records created from the InputStream
|
* @return a list of Records created from the InputStream
|
||||||
*
|
*
|
||||||
* @throws org.apache.poi.util.RecordFormatException on error processing the InputStream
|
* @throws org.apache.poi.util.RecordFormatException on error processing the InputStream
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,16 +16,13 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.poifs.filesystem;
|
package org.apache.poi.poifs.filesystem;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -44,8 +41,7 @@ import org.apache.poi.poifs.property.Property;
|
||||||
*/
|
*/
|
||||||
public class DirectoryNode
|
public class DirectoryNode
|
||||||
extends EntryNode
|
extends EntryNode
|
||||||
implements DirectoryEntry, POIFSViewable, Iterable<Entry>
|
implements DirectoryEntry, POIFSViewable, Iterable<Entry> {
|
||||||
{
|
|
||||||
|
|
||||||
// Map of Entry instances, keyed by their literal names as stored
|
// Map of Entry instances, keyed by their literal names as stored
|
||||||
private final Map<String,Entry> _byname = new HashMap<>();
|
private final Map<String,Entry> _byname = new HashMap<>();
|
||||||
|
@ -72,36 +68,25 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
DirectoryNode(final DirectoryProperty property,
|
DirectoryNode(final DirectoryProperty property,
|
||||||
final POIFSFileSystem filesystem,
|
final POIFSFileSystem filesystem,
|
||||||
final DirectoryNode parent)
|
final DirectoryNode parent) {
|
||||||
{
|
|
||||||
super(property, parent);
|
super(property, parent);
|
||||||
this._filesystem = filesystem;
|
this._filesystem = filesystem;
|
||||||
|
|
||||||
if (parent == null)
|
if (parent == null) {
|
||||||
{
|
|
||||||
_path = new POIFSDocumentPath();
|
_path = new POIFSDocumentPath();
|
||||||
}
|
} else {
|
||||||
else
|
_path = new POIFSDocumentPath(parent._path, new String[] { property.getName() });
|
||||||
{
|
|
||||||
_path = new POIFSDocumentPath(parent._path, new String[]
|
|
||||||
{
|
|
||||||
property.getName()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Iterator<Property> iter = property.getChildren();
|
Iterator<Property> iter = property.getChildren();
|
||||||
|
|
||||||
while (iter.hasNext())
|
while (iter.hasNext()) {
|
||||||
{
|
Property child = iter.next();
|
||||||
Property child = iter.next();
|
Entry childNode;
|
||||||
Entry childNode;
|
|
||||||
|
|
||||||
if (child.isDirectory())
|
if (child.isDirectory()) {
|
||||||
{
|
|
||||||
DirectoryProperty childDir = (DirectoryProperty) child;
|
DirectoryProperty childDir = (DirectoryProperty) child;
|
||||||
childNode = new DirectoryNode(childDir, _filesystem, this);
|
childNode = new DirectoryNode(childDir, _filesystem, this);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
childNode = new DocumentNode((DocumentProperty) child, this);
|
childNode = new DocumentNode((DocumentProperty) child, this);
|
||||||
}
|
}
|
||||||
_entries.add(childNode);
|
_entries.add(childNode);
|
||||||
|
@ -113,17 +98,14 @@ public class DirectoryNode
|
||||||
/**
|
/**
|
||||||
* @return this directory's path representation
|
* @return this directory's path representation
|
||||||
*/
|
*/
|
||||||
|
public POIFSDocumentPath getPath() {
|
||||||
public POIFSDocumentPath getPath()
|
|
||||||
{
|
|
||||||
return _path;
|
return _path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the filesystem that this belongs to
|
* @return the filesystem that this belongs to
|
||||||
*/
|
*/
|
||||||
public POIFSFileSystem getFileSystem()
|
public POIFSFileSystem getFileSystem() {
|
||||||
{
|
|
||||||
return _filesystem;
|
return _filesystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,8 +121,7 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
public DocumentInputStream createDocumentInputStream(
|
public DocumentInputStream createDocumentInputStream(
|
||||||
final String documentName)
|
final String documentName)
|
||||||
throws IOException
|
throws IOException {
|
||||||
{
|
|
||||||
return createDocumentInputStream(getEntryCaseInsensitive(documentName));
|
return createDocumentInputStream(getEntryCaseInsensitive(documentName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +137,7 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
public DocumentInputStream createDocumentInputStream(
|
public DocumentInputStream createDocumentInputStream(
|
||||||
final Entry document)
|
final Entry document)
|
||||||
throws IOException
|
throws IOException {
|
||||||
{
|
|
||||||
if (!document.isDocumentEntry()) {
|
if (!document.isDocumentEntry()) {
|
||||||
throw new IOException("Entry '" + document.getName()
|
throw new IOException("Entry '" + document.getName()
|
||||||
+ "' is not a DocumentEntry");
|
+ "' is not a DocumentEntry");
|
||||||
|
@ -177,10 +157,9 @@ public class DirectoryNode
|
||||||
* @throws IOException if the document can't be created
|
* @throws IOException if the document can't be created
|
||||||
*/
|
*/
|
||||||
DocumentEntry createDocument(final POIFSDocument document)
|
DocumentEntry createDocument(final POIFSDocument document)
|
||||||
throws IOException
|
throws IOException {
|
||||||
{
|
|
||||||
DocumentProperty property = document.getDocumentProperty();
|
DocumentProperty property = document.getDocumentProperty();
|
||||||
DocumentNode rval = new DocumentNode(property, this);
|
DocumentNode rval = new DocumentNode(property, this);
|
||||||
|
|
||||||
(( DirectoryProperty ) getProperty()).addChild(property);
|
(( DirectoryProperty ) getProperty()).addChild(property);
|
||||||
_filesystem.addDocument(document);
|
_filesystem.addDocument(document);
|
||||||
|
@ -199,17 +178,14 @@ public class DirectoryNode
|
||||||
*
|
*
|
||||||
* @return true if the operation succeeded, else false
|
* @return true if the operation succeeded, else false
|
||||||
*/
|
*/
|
||||||
boolean changeName(final String oldName, final String newName)
|
boolean changeName(final String oldName, final String newName) {
|
||||||
{
|
boolean rval = false;
|
||||||
boolean rval = false;
|
|
||||||
EntryNode child = ( EntryNode ) _byUCName.get(oldName.toUpperCase(Locale.ROOT));
|
EntryNode child = ( EntryNode ) _byUCName.get(oldName.toUpperCase(Locale.ROOT));
|
||||||
|
|
||||||
if (child != null)
|
if (child != null) {
|
||||||
{
|
|
||||||
rval = (( DirectoryProperty ) getProperty())
|
rval = (( DirectoryProperty ) getProperty())
|
||||||
.changeName(child.getProperty(), newName);
|
.changeName(child.getProperty(), newName);
|
||||||
if (rval)
|
if (rval) {
|
||||||
{
|
|
||||||
_byname.remove(oldName);
|
_byname.remove(oldName);
|
||||||
_byname.put(child.getProperty().getName(), child);
|
_byname.put(child.getProperty().getName(), child);
|
||||||
_byUCName.remove(oldName.toUpperCase(Locale.ROOT));
|
_byUCName.remove(oldName.toUpperCase(Locale.ROOT));
|
||||||
|
@ -227,14 +203,12 @@ public class DirectoryNode
|
||||||
* @return true if the entry was deleted, else false
|
* @return true if the entry was deleted, else false
|
||||||
*/
|
*/
|
||||||
|
|
||||||
boolean deleteEntry(final EntryNode entry)
|
boolean deleteEntry(final EntryNode entry) {
|
||||||
{
|
|
||||||
boolean rval =
|
boolean rval =
|
||||||
(( DirectoryProperty ) getProperty())
|
(( DirectoryProperty ) getProperty())
|
||||||
.deleteChild(entry.getProperty());
|
.deleteChild(entry.getProperty());
|
||||||
|
|
||||||
if (rval)
|
if (rval) {
|
||||||
{
|
|
||||||
_entries.remove(entry);
|
_entries.remove(entry);
|
||||||
_byname.remove(entry.getName());
|
_byname.remove(entry.getName());
|
||||||
_byUCName.remove(entry.getName().toUpperCase(Locale.ROOT));
|
_byUCName.remove(entry.getName().toUpperCase(Locale.ROOT));
|
||||||
|
@ -263,8 +237,7 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Entry> getEntries()
|
public Iterator<Entry> getEntries() {
|
||||||
{
|
|
||||||
return _entries.iterator();
|
return _entries.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,8 +251,7 @@ public class DirectoryNode
|
||||||
* DirectoryEntry is empty)
|
* DirectoryEntry is empty)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getEntryNames()
|
public Set<String> getEntryNames() {
|
||||||
{
|
|
||||||
return _byname.keySet();
|
return _byname.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,8 +262,7 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty()
|
public boolean isEmpty() {
|
||||||
{
|
|
||||||
return _entries.isEmpty();
|
return _entries.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,32 +275,29 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getEntryCount()
|
public int getEntryCount() {
|
||||||
{
|
|
||||||
return _entries.size();
|
return _entries.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for a specific entry in a case-sensitive way.
|
* Checks for a specific entry in a case-sensitive way.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name the name of the Entry to check
|
||||||
* @return whether or not an entry exists for that name (case-sensitive)
|
* @return whether or not an entry exists for that name (case-sensitive)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean hasEntry(String name )
|
public boolean hasEntry(String name ) {
|
||||||
{
|
|
||||||
return name != null && _byname.containsKey(name);
|
return name != null && _byname.containsKey(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for a specific entry in a case-insensitive way.
|
* Checks for a specific entry in a case-insensitive way.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name the name of the Entry to check
|
||||||
* @return whether or not an entry exists for that name (case-insensitive)
|
* @return whether or not an entry exists for that name (case-insensitive)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean hasEntryCaseInsensitive(String name )
|
public boolean hasEntryCaseInsensitive(String name ) {
|
||||||
{
|
|
||||||
return name != null && _byUCName.containsKey(name.toUpperCase(Locale.ROOT));
|
return name != null && _byUCName.containsKey(name.toUpperCase(Locale.ROOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,6 +319,7 @@ public class DirectoryNode
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
rval = _byname.get(name);
|
rval = _byname.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rval == null) {
|
if (rval == null) {
|
||||||
// throw more useful exceptions for known wrong file-extensions
|
// throw more useful exceptions for known wrong file-extensions
|
||||||
if(_byname.containsKey("Workbook")) {
|
if(_byname.containsKey("Workbook")) {
|
||||||
|
@ -386,6 +355,7 @@ public class DirectoryNode
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
rval = _byUCName.get(name.toUpperCase(Locale.ROOT));
|
rval = _byUCName.get(name.toUpperCase(Locale.ROOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rval == null) {
|
if (rval == null) {
|
||||||
// throw more useful exceptions for known wrong file-extensions
|
// throw more useful exceptions for known wrong file-extensions
|
||||||
if(_byname.containsKey("Workbook")) {
|
if(_byname.containsKey("Workbook")) {
|
||||||
|
@ -414,12 +384,9 @@ public class DirectoryNode
|
||||||
*
|
*
|
||||||
* @throws IOException if the document can't be created
|
* @throws IOException if the document can't be created
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DocumentEntry createDocument(final String name,
|
public DocumentEntry createDocument(final String name,
|
||||||
final InputStream stream)
|
final InputStream stream) throws IOException {
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return createDocument(new POIFSDocument(name, _filesystem, stream));
|
return createDocument(new POIFSDocument(name, _filesystem, stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,12 +401,9 @@ public class DirectoryNode
|
||||||
*
|
*
|
||||||
* @throws IOException if the document can't be created
|
* @throws IOException if the document can't be created
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DocumentEntry createDocument(final String name, final int size,
|
public DocumentEntry createDocument(final String name, final int size,
|
||||||
final POIFSWriterListener writer)
|
final POIFSWriterListener writer) throws IOException {
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return createDocument(new POIFSDocument(name, size, _filesystem, writer));
|
return createDocument(new POIFSDocument(name, size, _filesystem, writer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,11 +416,8 @@ public class DirectoryNode
|
||||||
*
|
*
|
||||||
* @throws IOException if the directory can't be created
|
* @throws IOException if the directory can't be created
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DirectoryEntry createDirectory(final String name)
|
public DirectoryEntry createDirectory(final String name) throws IOException {
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
DirectoryProperty property = new DirectoryProperty(name);
|
DirectoryProperty property = new DirectoryProperty(name);
|
||||||
|
|
||||||
DirectoryNode rval = new DirectoryNode(property, _filesystem, this);
|
DirectoryNode rval = new DirectoryNode(property, _filesystem, this);
|
||||||
|
@ -482,9 +443,7 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public DocumentEntry createOrUpdateDocument(final String name,
|
public DocumentEntry createOrUpdateDocument(final String name,
|
||||||
final InputStream stream)
|
final InputStream stream) throws IOException {
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (! hasEntryCaseInsensitive(name)) {
|
if (! hasEntryCaseInsensitive(name)) {
|
||||||
return createDocument(name, stream);
|
return createDocument(name, stream);
|
||||||
} else {
|
} else {
|
||||||
|
@ -501,8 +460,7 @@ public class DirectoryNode
|
||||||
* @return storage Class ID
|
* @return storage Class ID
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ClassID getStorageClsid()
|
public ClassID getStorageClsid() {
|
||||||
{
|
|
||||||
return getProperty().getStorageClsid();
|
return getProperty().getStorageClsid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,8 +470,7 @@ public class DirectoryNode
|
||||||
* @param clsidStorage storage Class ID
|
* @param clsidStorage storage Class ID
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setStorageClsid(ClassID clsidStorage)
|
public void setStorageClsid(ClassID clsidStorage) {
|
||||||
{
|
|
||||||
getProperty().setStorageClsid(clsidStorage);
|
getProperty().setStorageClsid(clsidStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,8 +484,7 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirectoryEntry()
|
public boolean isDirectoryEntry() {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,9 +500,7 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isDeleteOK()
|
protected boolean isDeleteOK() {
|
||||||
{
|
|
||||||
|
|
||||||
// if this directory is empty, we can delete it
|
// if this directory is empty, we can delete it
|
||||||
return isEmpty();
|
return isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -562,8 +516,7 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object [] getViewableArray()
|
public Object [] getViewableArray() {
|
||||||
{
|
|
||||||
return new Object[ 0 ];
|
return new Object[ 0 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,8 +545,7 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preferArray()
|
public boolean preferArray() {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,11 +557,12 @@ public class DirectoryNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getShortDescription()
|
public String getShortDescription() {
|
||||||
{
|
|
||||||
return getName();
|
return getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ********** END begin implementation of POIFSViewable ********** */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an Iterator over all the entries
|
* Returns an Iterator over all the entries
|
||||||
*/
|
*/
|
||||||
|
@ -627,7 +580,4 @@ public class DirectoryNode
|
||||||
public Spliterator<Entry> spliterator() {
|
public Spliterator<Entry> spliterator() {
|
||||||
return _entries.spliterator();
|
return _entries.spliterator();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* ********** END begin implementation of POIFSViewable ********** */
|
|
||||||
} // end public class DirectoryNode
|
|
||||||
|
|
||||||
|
|
|
@ -47,20 +47,20 @@ import org.apache.poi.util.StringUtil;
|
||||||
/**
|
/**
|
||||||
* Evaluates Data Validation constraints.<p>
|
* Evaluates Data Validation constraints.<p>
|
||||||
*
|
*
|
||||||
* For performance reasons, this class keeps a cache of all previously retrieved {@link DataValidation} instances.
|
* For performance reasons, this class keeps a cache of all previously retrieved {@link DataValidation} instances.
|
||||||
* Be sure to call {@link #clearAllCachedValues()} if any workbook validation definitions are
|
* Be sure to call {@link #clearAllCachedValues()} if any workbook validation definitions are
|
||||||
* added, modified, or deleted.
|
* added, modified, or deleted.
|
||||||
* <p>
|
* <p>
|
||||||
* Changing cell values should be fine, as long as the corresponding {@link WorkbookEvaluator#clearAllCachedResultValues()}
|
* Changing cell values should be fine, as long as the corresponding {@link WorkbookEvaluator#clearAllCachedResultValues()}
|
||||||
* is called as well.
|
* is called as well.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class DataValidationEvaluator {
|
public class DataValidationEvaluator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expensive to compute, so cache them as they are retrieved.
|
* Expensive to compute, so cache them as they are retrieved.
|
||||||
* <p>
|
* <p>
|
||||||
* Sheets don't implement equals, and since its an interface,
|
* Sheets don't implement equals, and since its an interface,
|
||||||
* there's no guarantee instances won't be recreated on the fly by some implementation.
|
* there's no guarantee instances won't be recreated on the fly by some implementation.
|
||||||
* So we use sheet name.
|
* So we use sheet name.
|
||||||
*/
|
*/
|
||||||
|
@ -79,14 +79,14 @@ public class DataValidationEvaluator {
|
||||||
this.workbook = wb;
|
this.workbook = wb;
|
||||||
this.workbookEvaluator = provider._getWorkbookEvaluator();
|
this.workbookEvaluator = provider._getWorkbookEvaluator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return evaluator
|
* @return evaluator
|
||||||
*/
|
*/
|
||||||
protected WorkbookEvaluator getWorkbookEvaluator() {
|
protected WorkbookEvaluator getWorkbookEvaluator() {
|
||||||
return workbookEvaluator;
|
return workbookEvaluator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this whenever validation structures change,
|
* Call this whenever validation structures change,
|
||||||
* so future results stay in sync with the Workbook state.
|
* so future results stay in sync with the Workbook state.
|
||||||
|
@ -94,7 +94,7 @@ public class DataValidationEvaluator {
|
||||||
public void clearAllCachedValues() {
|
public void clearAllCachedValues() {
|
||||||
validations.clear();
|
validations.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lazy load validations by sheet, since reading the CT* types is expensive
|
* Lazy load validations by sheet, since reading the CT* types is expensive
|
||||||
*
|
*
|
||||||
|
@ -109,14 +109,14 @@ public class DataValidationEvaluator {
|
||||||
}
|
}
|
||||||
return dvs;
|
return dvs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds and returns the {@link DataValidation} for the cell, if there is
|
* Finds and returns the {@link DataValidation} for the cell, if there is
|
||||||
* one. Lookup is based on the first match from
|
* one. Lookup is based on the first match from
|
||||||
* {@link DataValidation#getRegions()} for the cell's sheet. DataValidation
|
* {@link DataValidation#getRegions()} for the cell's sheet. DataValidation
|
||||||
* regions must be in the same sheet as the DataValidation. Allowed values
|
* regions must be in the same sheet as the DataValidation. Allowed values
|
||||||
* expressions may reference other sheets, however.
|
* expressions may reference other sheets, however.
|
||||||
*
|
*
|
||||||
* @param cell reference to check - use this in case the cell does not actually exist yet
|
* @param cell reference to check - use this in case the cell does not actually exist yet
|
||||||
* @return the DataValidation applicable to the given cell, or null if no
|
* @return the DataValidation applicable to the given cell, or null if no
|
||||||
* validation applies
|
* validation applies
|
||||||
|
@ -132,7 +132,7 @@ public class DataValidationEvaluator {
|
||||||
* {@link DataValidation#getRegions()} for the cell's sheet. DataValidation
|
* {@link DataValidation#getRegions()} for the cell's sheet. DataValidation
|
||||||
* regions must be in the same sheet as the DataValidation. Allowed values
|
* regions must be in the same sheet as the DataValidation. Allowed values
|
||||||
* expressions may reference other sheets, however.
|
* expressions may reference other sheets, however.
|
||||||
*
|
*
|
||||||
* @param cell reference to check
|
* @param cell reference to check
|
||||||
* @return the DataValidationContext applicable to the given cell, or null if no
|
* @return the DataValidationContext applicable to the given cell, or null if no
|
||||||
* validation applies
|
* validation applies
|
||||||
|
@ -166,7 +166,7 @@ public class DataValidationEvaluator {
|
||||||
* This method could throw an exception if the validation type is not LIST,
|
* This method could throw an exception if the validation type is not LIST,
|
||||||
* but since this method is mostly useful in UI contexts, null seems the
|
* but since this method is mostly useful in UI contexts, null seems the
|
||||||
* easier path.
|
* easier path.
|
||||||
*
|
*
|
||||||
* @param cell reference to check - use this in case the cell does not actually exist yet
|
* @param cell reference to check - use this in case the cell does not actually exist yet
|
||||||
* @return returns an unmodifiable {@link List} of {@link ValueEval}s if applicable, or
|
* @return returns an unmodifiable {@link List} of {@link ValueEval}s if applicable, or
|
||||||
* null
|
* null
|
||||||
|
@ -175,7 +175,7 @@ public class DataValidationEvaluator {
|
||||||
DataValidationContext context = getValidationContextForCell(cell);
|
DataValidationContext context = getValidationContextForCell(cell);
|
||||||
|
|
||||||
if (context == null) return null;
|
if (context == null) return null;
|
||||||
|
|
||||||
return getValidationValuesForConstraint(context);
|
return getValidationValuesForConstraint(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,11 +186,11 @@ public class DataValidationEvaluator {
|
||||||
protected static List<ValueEval> getValidationValuesForConstraint(DataValidationContext context) {
|
protected static List<ValueEval> getValidationValuesForConstraint(DataValidationContext context) {
|
||||||
final DataValidationConstraint val = context.getValidation().getValidationConstraint();
|
final DataValidationConstraint val = context.getValidation().getValidationConstraint();
|
||||||
if (val.getValidationType() != ValidationType.LIST) return null;
|
if (val.getValidationType() != ValidationType.LIST) return null;
|
||||||
|
|
||||||
String formula = val.getFormula1();
|
String formula = val.getFormula1();
|
||||||
|
|
||||||
final List<ValueEval> values = new ArrayList<>();
|
final List<ValueEval> values = new ArrayList<>();
|
||||||
|
|
||||||
if (val.getExplicitListValues() != null && val.getExplicitListValues().length > 0) {
|
if (val.getExplicitListValues() != null && val.getExplicitListValues().length > 0) {
|
||||||
// assumes parsing interprets the overloaded property right for XSSF
|
// assumes parsing interprets the overloaded property right for XSSF
|
||||||
for (String s : val.getExplicitListValues()) {
|
for (String s : val.getExplicitListValues()) {
|
||||||
|
@ -221,7 +221,7 @@ public class DataValidationEvaluator {
|
||||||
* Note that to properly apply some validations, care must be taken to
|
* Note that to properly apply some validations, care must be taken to
|
||||||
* offset the base validation formula by the relative position of the
|
* offset the base validation formula by the relative position of the
|
||||||
* current cell, or the wrong value is checked.
|
* current cell, or the wrong value is checked.
|
||||||
*
|
*
|
||||||
* @param cellRef The reference of the cell to evaluate
|
* @param cellRef The reference of the cell to evaluate
|
||||||
* @return true if the cell has no validation or the cell value passes the
|
* @return true if the cell has no validation or the cell value passes the
|
||||||
* defined validation, false if it fails
|
* defined validation, false if it fails
|
||||||
|
@ -230,23 +230,23 @@ public class DataValidationEvaluator {
|
||||||
final DataValidationContext context = getValidationContextForCell(cellRef);
|
final DataValidationContext context = getValidationContextForCell(cellRef);
|
||||||
|
|
||||||
if (context == null) return true;
|
if (context == null) return true;
|
||||||
|
|
||||||
final Cell cell = SheetUtil.getCell(workbook.getSheet(cellRef.getSheetName()), cellRef.getRow(), cellRef.getCol());
|
final Cell cell = SheetUtil.getCell(workbook.getSheet(cellRef.getSheetName()), cellRef.getRow(), cellRef.getCol());
|
||||||
|
|
||||||
// now we can validate the cell
|
// now we can validate the cell
|
||||||
|
|
||||||
// if empty, return not allowed flag
|
// if empty, return not allowed flag
|
||||||
if ( cell == null
|
if ( cell == null
|
||||||
|| isType(cell, CellType.BLANK)
|
|| isType(cell, CellType.BLANK)
|
||||||
|| (isType(cell,CellType.STRING)
|
|| (isType(cell,CellType.STRING)
|
||||||
&& (cell.getStringCellValue() == null || cell.getStringCellValue().isEmpty())
|
&& (cell.getStringCellValue() == null || cell.getStringCellValue().isEmpty())
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return context.getValidation().getEmptyCellAllowed();
|
return context.getValidation().getEmptyCellAllowed();
|
||||||
}
|
}
|
||||||
|
|
||||||
// cell has a value
|
// cell has a value
|
||||||
|
|
||||||
return ValidationEnum.isValid(cell, context);
|
return ValidationEnum.isValid(cell, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,18 +259,18 @@ public class DataValidationEvaluator {
|
||||||
*/
|
*/
|
||||||
public static boolean isType(Cell cell, CellType type) {
|
public static boolean isType(Cell cell, CellType type) {
|
||||||
final CellType cellType = cell.getCellType();
|
final CellType cellType = cell.getCellType();
|
||||||
return cellType == type
|
return cellType == type
|
||||||
|| (cellType == CellType.FORMULA
|
|| (cellType == CellType.FORMULA
|
||||||
&& cell.getCachedFormulaResultType() == type
|
&& cell.getCachedFormulaResultType() == type
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Not calling it ValidationType to avoid confusion for now with DataValidationConstraint.ValidationType.
|
* Not calling it ValidationType to avoid confusion for now with DataValidationConstraint.ValidationType.
|
||||||
* Definition order matches OOXML type ID indexes
|
* Definition order matches OOXML type ID indexes
|
||||||
*/
|
*/
|
||||||
public static enum ValidationEnum {
|
public enum ValidationEnum {
|
||||||
ANY {
|
ANY {
|
||||||
public boolean isValidValue(Cell cell, DataValidationContext context) {
|
public boolean isValidValue(Cell cell, DataValidationContext context) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -291,11 +291,11 @@ public class DataValidationEvaluator {
|
||||||
public boolean isValidValue(Cell cell, DataValidationContext context) {
|
public boolean isValidValue(Cell cell, DataValidationContext context) {
|
||||||
final List<ValueEval> valueList = getValidationValuesForConstraint(context);
|
final List<ValueEval> valueList = getValidationValuesForConstraint(context);
|
||||||
if (valueList == null) return true; // special case
|
if (valueList == null) return true; // special case
|
||||||
|
|
||||||
// compare cell value to each item
|
// compare cell value to each item
|
||||||
for (ValueEval listVal : valueList) {
|
for (ValueEval listVal : valueList) {
|
||||||
ValueEval comp = listVal instanceof RefEval ? ((RefEval) listVal).getInnerValueEval(context.getSheetIndex()) : listVal;
|
ValueEval comp = listVal instanceof RefEval ? ((RefEval) listVal).getInnerValueEval(context.getSheetIndex()) : listVal;
|
||||||
|
|
||||||
// any value is valid if the list contains a blank value per Excel help
|
// any value is valid if the list contains a blank value per Excel help
|
||||||
if (comp instanceof BlankEval) return true;
|
if (comp instanceof BlankEval) return true;
|
||||||
if (comp instanceof ErrorEval) continue; // nothing to check
|
if (comp instanceof ErrorEval) continue; // nothing to check
|
||||||
|
@ -310,7 +310,7 @@ public class DataValidationEvaluator {
|
||||||
// could this have trouble with double precision/rounding errors and date/time values?
|
// could this have trouble with double precision/rounding errors and date/time values?
|
||||||
// do we need to allow a "close enough" double fractional range?
|
// do we need to allow a "close enough" double fractional range?
|
||||||
// I see 17 digits after the decimal separator in XSSF files, and for time values,
|
// I see 17 digits after the decimal separator in XSSF files, and for time values,
|
||||||
// there are sometimes discrepancies in the final decimal place.
|
// there are sometimes discrepancies in the final decimal place.
|
||||||
// I don't have a validation test case yet though. - GW
|
// I don't have a validation test case yet though. - GW
|
||||||
if (isType(cell, CellType.NUMERIC) && ((NumberEval) comp).getNumberValue() == cell.getNumericCellValue()) {
|
if (isType(cell, CellType.NUMERIC) && ((NumberEval) comp).getNumberValue() == cell.getNumericCellValue()) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -319,7 +319,7 @@ public class DataValidationEvaluator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (comp instanceof StringEval) {
|
if (comp instanceof StringEval) {
|
||||||
// interestingly, in testing, a validation value of the string "TRUE" or "true"
|
// interestingly, in testing, a validation value of the string "TRUE" or "true"
|
||||||
// did not match a boolean cell value of TRUE - so apparently cell type matters
|
// did not match a boolean cell value of TRUE - so apparently cell type matters
|
||||||
// also, Excel validation is case insensitive - "true" is valid for the list value "TRUE"
|
// also, Excel validation is case insensitive - "true" is valid for the list value "TRUE"
|
||||||
if (isType(cell, CellType.STRING) && ((StringEval) comp).getStringValue().equalsIgnoreCase(cell.getStringCellValue())) {
|
if (isType(cell, CellType.STRING) && ((StringEval) comp).getStringValue().equalsIgnoreCase(cell.getStringCellValue())) {
|
||||||
|
@ -368,16 +368,16 @@ public class DataValidationEvaluator {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
;
|
;
|
||||||
|
|
||||||
public boolean isValidValue(Cell cell, DataValidationContext context) {
|
public boolean isValidValue(Cell cell, DataValidationContext context) {
|
||||||
return isValidNumericCell(cell, context);
|
return isValidNumericCell(cell, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses the cell value, which may be the cached formula result value.
|
* Uses the cell value, which may be the cached formula result value.
|
||||||
* We won't re-evaluate cells here. This validation would be after the cell value was updated externally.
|
* We won't re-evaluate cells here. This validation would be after the cell value was updated externally.
|
||||||
* Excel allows invalid values through methods like copy/paste, and only validates them when the user
|
* Excel allows invalid values through methods like copy/paste, and only validates them when the user
|
||||||
* interactively edits the cell.
|
* interactively edits the cell.
|
||||||
* @return if the cell is a valid numeric cell for the validation or not
|
* @return if the cell is a valid numeric cell for the validation or not
|
||||||
*/
|
*/
|
||||||
protected boolean isValidNumericCell(Cell cell, DataValidationContext context) {
|
protected boolean isValidNumericCell(Cell cell, DataValidationContext context) {
|
||||||
|
@ -394,12 +394,12 @@ public class DataValidationEvaluator {
|
||||||
try {
|
try {
|
||||||
Double t1 = evalOrConstant(context.getFormula1(), context);
|
Double t1 = evalOrConstant(context.getFormula1(), context);
|
||||||
// per Excel, a blank value for a numeric validation constraint formula validates true
|
// per Excel, a blank value for a numeric validation constraint formula validates true
|
||||||
if (t1 == null) return true;
|
if (t1 == null) return true;
|
||||||
Double t2 = null;
|
Double t2 = null;
|
||||||
if (context.getOperator() == OperatorType.BETWEEN || context.getOperator() == OperatorType.NOT_BETWEEN) {
|
if (context.getOperator() == OperatorType.BETWEEN || context.getOperator() == OperatorType.NOT_BETWEEN) {
|
||||||
t2 = evalOrConstant(context.getFormula2(), context);
|
t2 = evalOrConstant(context.getFormula2(), context);
|
||||||
// per Excel, a blank value for a numeric validation constraint formula validates true
|
// per Excel, a blank value for a numeric validation constraint formula validates true
|
||||||
if (t2 == null) return true;
|
if (t2 == null) return true;
|
||||||
}
|
}
|
||||||
return OperatorEnum.values()[context.getOperator()].isValid(value, t1, t2);
|
return OperatorEnum.values()[context.getOperator()].isValid(value, t1, t2);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
|
@ -407,7 +407,7 @@ public class DataValidationEvaluator {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate a numeric formula value as either a constant or numeric expression.
|
* Evaluate a numeric formula value as either a constant or numeric expression.
|
||||||
* Note that Excel treats validations with constraint formulas that evaluate to null as valid,
|
* Note that Excel treats validations with constraint formulas that evaluate to null as valid,
|
||||||
|
@ -435,12 +435,12 @@ public class DataValidationEvaluator {
|
||||||
if (eval instanceof StringEval) {
|
if (eval instanceof StringEval) {
|
||||||
final String value = ((StringEval) eval).getStringValue();
|
final String value = ((StringEval) eval).getStringValue();
|
||||||
if (StringUtil.isBlank(value)) return null;
|
if (StringUtil.isBlank(value)) return null;
|
||||||
// try to parse the cell value as a double and return it
|
// try to parse the cell value as a double and return it
|
||||||
return Double.valueOf(value);
|
return Double.valueOf(value);
|
||||||
}
|
}
|
||||||
throw new NumberFormatException("Formula '" + formula + "' evaluates to something other than a number");
|
throw new NumberFormatException("Formula '" + formula + "' evaluates to something other than a number");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates against the type defined in context, as an index of the enum values array.
|
* Validates against the type defined in context, as an index of the enum values array.
|
||||||
* @param cell Cell to check validity of
|
* @param cell Cell to check validity of
|
||||||
|
@ -451,14 +451,14 @@ public class DataValidationEvaluator {
|
||||||
public static boolean isValid(Cell cell, DataValidationContext context) {
|
public static boolean isValid(Cell cell, DataValidationContext context) {
|
||||||
return values()[context.getValidation().getValidationConstraint().getValidationType()].isValidValue(cell, context);
|
return values()[context.getValidation().getValidationConstraint().getValidationType()].isValidValue(cell, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Not calling it OperatorType to avoid confusion for now with DataValidationConstraint.OperatorType.
|
* Not calling it OperatorType to avoid confusion for now with DataValidationConstraint.OperatorType.
|
||||||
* Definition order matches OOXML type ID indexes
|
* Definition order matches OOXML type ID indexes
|
||||||
*/
|
*/
|
||||||
public static enum OperatorEnum {
|
public enum OperatorEnum {
|
||||||
BETWEEN {
|
BETWEEN {
|
||||||
public boolean isValid(Double cellValue, Double v1, Double v2) {
|
public boolean isValid(Double cellValue, Double v1, Double v2) {
|
||||||
return cellValue.compareTo(v1) >= 0 && cellValue.compareTo(v2) <= 0;
|
return cellValue.compareTo(v1) >= 0 && cellValue.compareTo(v2) <= 0;
|
||||||
|
@ -500,9 +500,9 @@ public class DataValidationEvaluator {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
;
|
;
|
||||||
|
|
||||||
public static final OperatorEnum IGNORED = BETWEEN;
|
public static final OperatorEnum IGNORED = BETWEEN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates comparison using operator instance rules
|
* Evaluates comparison using operator instance rules
|
||||||
* @param cellValue won't be null, assumption is previous checks handled that
|
* @param cellValue won't be null, assumption is previous checks handled that
|
||||||
|
@ -512,7 +512,7 @@ public class DataValidationEvaluator {
|
||||||
*/
|
*/
|
||||||
public abstract boolean isValid(Double cellValue, Double v1, Double v2);
|
public abstract boolean isValid(Double cellValue, Double v1, Double v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class organizes and encapsulates all the pieces of information related to a single
|
* This class organizes and encapsulates all the pieces of information related to a single
|
||||||
* data validation configuration for a single cell. It cleanly separates the validation region,
|
* data validation configuration for a single cell. It cleanly separates the validation region,
|
||||||
|
@ -524,7 +524,7 @@ public class DataValidationEvaluator {
|
||||||
private final DataValidationEvaluator dve;
|
private final DataValidationEvaluator dve;
|
||||||
private final CellRangeAddressBase region;
|
private final CellRangeAddressBase region;
|
||||||
private final CellReference target;
|
private final CellReference target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate the context with the necessary values.
|
* Populate the context with the necessary values.
|
||||||
*/
|
*/
|
||||||
|
@ -558,30 +558,30 @@ public class DataValidationEvaluator {
|
||||||
public CellReference getTarget() {
|
public CellReference getTarget() {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOffsetColumns() {
|
public int getOffsetColumns() {
|
||||||
return target.getCol() - region.getFirstColumn();
|
return target.getCol() - region.getFirstColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOffsetRows() {
|
public int getOffsetRows() {
|
||||||
return target.getRow() - region.getFirstRow();
|
return target.getRow() - region.getFirstRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSheetIndex() {
|
public int getSheetIndex() {
|
||||||
return dve.getWorkbookEvaluator().getSheetIndex(target.getSheetName());
|
return dve.getWorkbookEvaluator().getSheetIndex(target.getSheetName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFormula1() {
|
public String getFormula1() {
|
||||||
return dv.getValidationConstraint().getFormula1();
|
return dv.getValidationConstraint().getFormula1();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFormula2() {
|
public String getFormula2() {
|
||||||
return dv.getValidationConstraint().getFormula2();
|
return dv.getValidationConstraint().getFormula2();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOperator() {
|
public int getOperator() {
|
||||||
return dv.getValidationConstraint().getOperator();
|
return dv.getValidationConstraint().getOperator();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.apache.poi.hssf.record;
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.poi.util.HexRead;
|
import org.apache.poi.util.HexRead;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
@ -53,9 +55,8 @@ final class TestRecordInputStream {
|
||||||
+ "1A 59 00 8A 9E 8A " // 3 uncompressed unicode chars
|
+ "1A 59 00 8A 9E 8A " // 3 uncompressed unicode chars
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testChangeOfCompressionFlag_bug25866() {
|
void testChangeOfCompressionFlag_bug25866() throws IOException {
|
||||||
byte[] changingFlagSimpleData = HexRead.readFromString(""
|
byte[] changingFlagSimpleData = HexRead.readFromString(""
|
||||||
+ "AA AA " // fake SID
|
+ "AA AA " // fake SID
|
||||||
+ "06 00 " // first rec len 6
|
+ "06 00 " // first rec len 6
|
||||||
|
@ -66,10 +67,13 @@ final class TestRecordInputStream {
|
||||||
// bug 45866 - compressByte in continue records must be 1 while reading unicode LE string
|
// bug 45866 - compressByte in continue records must be 1 while reading unicode LE string
|
||||||
String actual = in.readUnicodeLEString(18);
|
String actual = in.readUnicodeLEString(18);
|
||||||
assertEquals("\u591A\u8A00\u8A9E - Multilingual", actual);
|
assertEquals("\u591A\u8A00\u8A9E - Multilingual", actual);
|
||||||
|
|
||||||
|
in.mark(10);
|
||||||
|
in.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testChangeFromUnCompressedToCompressed() {
|
void testChangeFromUnCompressedToCompressed() throws IOException {
|
||||||
byte[] changingFlagSimpleData = HexRead.readFromString(""
|
byte[] changingFlagSimpleData = HexRead.readFromString(""
|
||||||
+ "AA AA " // fake SID
|
+ "AA AA " // fake SID
|
||||||
+ "0F 00 " // first rec len 15
|
+ "0F 00 " // first rec len 15
|
||||||
|
@ -78,10 +82,13 @@ final class TestRecordInputStream {
|
||||||
RecordInputStream in = TestcaseRecordInputStream.create(changingFlagSimpleData);
|
RecordInputStream in = TestcaseRecordInputStream.create(changingFlagSimpleData);
|
||||||
String actual = in.readCompressedUnicode(18);
|
String actual = in.readCompressedUnicode(18);
|
||||||
assertEquals("Multilingual - \u591A\u8A00\u8A9E", actual);
|
assertEquals("Multilingual - \u591A\u8A00\u8A9E", actual);
|
||||||
|
|
||||||
|
in.mark(10);
|
||||||
|
in.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testReadString() {
|
void testReadString() throws IOException {
|
||||||
byte[] changingFlagFullData = HexRead.readFromString(""
|
byte[] changingFlagFullData = HexRead.readFromString(""
|
||||||
+ "AA AA " // fake SID
|
+ "AA AA " // fake SID
|
||||||
+ "12 00 " // first rec len 18 (15 + next 3 bytes)
|
+ "12 00 " // first rec len 18 (15 + next 3 bytes)
|
||||||
|
@ -92,6 +99,9 @@ final class TestRecordInputStream {
|
||||||
RecordInputStream in = TestcaseRecordInputStream.create(changingFlagFullData);
|
RecordInputStream in = TestcaseRecordInputStream.create(changingFlagFullData);
|
||||||
String actual = in.readString();
|
String actual = in.readString();
|
||||||
assertEquals("Multilingual - \u591A\u8A00\u8A9E", actual);
|
assertEquals("Multilingual - \u591A\u8A00\u8A9E", actual);
|
||||||
|
|
||||||
|
in.mark(10);
|
||||||
|
in.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
|
|
|
@ -537,6 +537,7 @@ public abstract class BaseTestWorkbook {
|
||||||
/**
|
/**
|
||||||
* Tests that all the unicode capable string fields can be set, written and then read back
|
* Tests that all the unicode capable string fields can be set, written and then read back
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||||
@Test
|
@Test
|
||||||
protected void unicodeInAll() throws IOException {
|
protected void unicodeInAll() throws IOException {
|
||||||
try (Workbook wb1 = _testDataProvider.createWorkbook()) {
|
try (Workbook wb1 = _testDataProvider.createWorkbook()) {
|
||||||
|
@ -850,7 +851,7 @@ public abstract class BaseTestWorkbook {
|
||||||
wb.removeSheetAt(0);
|
wb.removeSheetAt(0);
|
||||||
wb.removeSheetAt(2);
|
wb.removeSheetAt(2);
|
||||||
|
|
||||||
// ensure that sheets are moved up and removed sheets are not found any more
|
// ensure that sheets are moved up and removed sheets are not found anymore
|
||||||
assertEquals(-1, wb.getSheetIndex(sheet1));
|
assertEquals(-1, wb.getSheetIndex(sheet1));
|
||||||
assertEquals(0, wb.getSheetIndex(sheet2));
|
assertEquals(0, wb.getSheetIndex(sheet2));
|
||||||
assertEquals(1, wb.getSheetIndex(sheet3));
|
assertEquals(1, wb.getSheetIndex(sheet3));
|
||||||
|
@ -936,4 +937,20 @@ public abstract class BaseTestWorkbook {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSheetNameDifferOnlyLowercaseUppercase() throws IOException {
|
||||||
|
try (Workbook wb = _testDataProvider.createWorkbook()) {
|
||||||
|
wb.createSheet("abc");
|
||||||
|
assertEquals(1, wb.getNumberOfSheets());
|
||||||
|
|
||||||
|
assertThrows(IllegalArgumentException.class,
|
||||||
|
() -> wb.createSheet("ABC"));
|
||||||
|
assertEquals(1, wb.getNumberOfSheets());
|
||||||
|
|
||||||
|
Sheet sheet = wb.getSheet("abc");
|
||||||
|
assertNotNull(sheet);
|
||||||
|
assertEquals("abc", sheet.getSheetName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue