diff --git a/build.gradle b/build.gradle
index 162048ab72..5c9487d40b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -185,6 +185,7 @@ project('main') {
compile 'com.sun.xml.bind:jaxb-impl:2.3.2'
compile 'com.sun.xml.bind:jaxb-core:2.3.0.1'
compile 'javax.activation:activation:1.1.1'
+ compile 'com.zaxxer:SparseBitSet:1.2'
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:3.0.0'
@@ -236,6 +237,7 @@ project('ooxml') {
compile 'org.apache.santuario:xmlsec:2.1.2'
compile 'org.bouncycastle:bcpkix-jdk15on:1.62'
compile 'com.github.virtuald:curvesapi:1.06'
+ compile 'com.zaxxer:SparseBitSet:1.2'
// compile only, don't add it to our dist as it blows up the size
compile 'org.apache.xmlgraphics:batik-all:1.11'
diff --git a/build.xml b/build.xml
index e165daf01f..0ac0854150 100644
--- a/build.xml
+++ b/build.xml
@@ -218,6 +218,9 @@ under the License.
+
+
@@ -378,6 +381,7 @@ under the License.
+
@@ -752,6 +756,7 @@ under the License.
+
@@ -788,6 +793,7 @@ under the License.
+
@@ -2038,6 +2044,7 @@ under the License.
+
@@ -2320,6 +2327,7 @@ under the License.
+
diff --git a/maven/poi.pom b/maven/poi.pom
index d0cdf9baf5..a3d15a8b0b 100644
--- a/maven/poi.pom
+++ b/maven/poi.pom
@@ -88,6 +88,11 @@
commons-math3
3.6.1
+
+ com.zaxxer
+ SparseBitSet
+ 1.2
+
org.hamcrest
diff --git a/sonar/main/pom.xml b/sonar/main/pom.xml
index 23c9b961ab..5a4a8287b7 100644
--- a/sonar/main/pom.xml
+++ b/sonar/main/pom.xml
@@ -125,6 +125,11 @@
commons-codec
1.13
+
+ com.zaxxer
+ SparseBitSet
+ 1.2
+
commons-logging
commons-logging
diff --git a/src/java/org/apache/poi/ddf/EscherDggRecord.java b/src/java/org/apache/poi/ddf/EscherDggRecord.java
index f1e3cc75cc..b4705ad383 100644
--- a/src/java/org/apache/poi/ddf/EscherDggRecord.java
+++ b/src/java/org/apache/poi/ddf/EscherDggRecord.java
@@ -19,11 +19,11 @@ package org.apache.poi.ddf;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
+import com.zaxxer.sparsebits.SparseBitSet;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
@@ -301,7 +301,7 @@ public final class EscherDggRecord extends EscherRecord {
* @return the next available drawing group id
*/
public short findNewDrawingGroupId() {
- BitSet bs = new BitSet();
+ SparseBitSet bs = new SparseBitSet();
bs.set(0);
for (FileIdCluster fic : field_5_fileIdClusters) {
bs.set(fic.getDrawingGroupId());
diff --git a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
index b98e229d8e..e00b1c2bac 100644
--- a/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
+++ b/src/java/org/apache/poi/poifs/crypt/ChunkedCipherOutputStream.java
@@ -25,13 +25,13 @@ import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
-import java.util.BitSet;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.ShortBufferException;
+import com.zaxxer.sparsebits.SparseBitSet;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSWriterEvent;
@@ -56,7 +56,7 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
private final int chunkBits;
private final byte[] chunk;
- private final BitSet plainByteFlags;
+ private final SparseBitSet plainByteFlags;
private final File fileOut;
private final DirectoryNode dir;
@@ -74,7 +74,7 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
this.chunkSize = chunkSize;
int cs = chunkSize == STREAMING ? 4096 : chunkSize;
this.chunk = IOUtils.safelyAllocate(cs, MAX_RECORD_LENGTH);
- this.plainByteFlags = new BitSet(cs);
+ this.plainByteFlags = new SparseBitSet(cs);
this.chunkBits = Integer.bitCount(cs-1);
this.fileOut = TempFile.createTempFile("encrypted_package", "crypt");
this.fileOut.deleteOnExit();
@@ -88,7 +88,7 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
this.chunkSize = chunkSize;
int cs = chunkSize == STREAMING ? 4096 : chunkSize;
this.chunk = IOUtils.safelyAllocate(cs, MAX_RECORD_LENGTH);
- this.plainByteFlags = new BitSet(cs);
+ this.plainByteFlags = new SparseBitSet(cs);
this.chunkBits = Integer.bitCount(cs-1);
this.fileOut = null;
this.dir = null;
@@ -283,7 +283,7 @@ public abstract class ChunkedCipherOutputStream extends FilterOutputStream {
return chunk;
}
- protected BitSet getPlainByteFlags() {
+ protected SparseBitSet getPlainByteFlags() {
return plainByteFlags;
}
diff --git a/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptor.java b/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptor.java
index 3b180b20d4..0c1cbf4932 100644
--- a/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptor.java
+++ b/src/java/org/apache/poi/poifs/crypt/xor/XOREncryptor.java
@@ -21,11 +21,11 @@ import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
-import java.util.BitSet;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
+import com.zaxxer.sparsebits.SparseBitSet;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.crypt.ChunkedCipherOutputStream;
import org.apache.poi.poifs.crypt.CryptoFunctions;
@@ -139,7 +139,7 @@ public class XOREncryptor extends Encryptor {
final int start = Math.max(posInChunk-(recordEnd-recordStart), 0);
- final BitSet plainBytes = getPlainByteFlags();
+ final SparseBitSet plainBytes = getPlainByteFlags();
final byte[] xorArray = getEncryptionInfo().getEncryptor().getSecretKey().getEncoded();
final byte[] chunk = getChunk();
final byte[] plain = (plainBytes.isEmpty()) ? null : chunk.clone();
diff --git a/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java b/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
index 7173c24e97..b99994bc12 100644
--- a/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
+++ b/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
@@ -25,6 +25,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
+import com.zaxxer.sparsebits.SparseBitSet;
import org.apache.poi.extractor.POITextExtractor;
import org.apache.poi.sl.usermodel.MasterSheet;
import org.apache.poi.sl.usermodel.Notes;
@@ -382,7 +383,9 @@ public class SlideShowExtractor<
* @param bold use {@code true} for bold TextRuns, {@code false} for non-bold ones and
* {@code null} if it doesn't matter
* @return a bitset with the marked/used codepoints
+ * @deprecated use {@link #getCodepointsInSparseBitSet(String, Boolean, Boolean)}
*/
+ @Deprecated
public BitSet getCodepoints(String typeface, Boolean italic, Boolean bold) {
final BitSet glyphs = new BitSet();
@@ -399,6 +402,30 @@ public class SlideShowExtractor<
return glyphs;
}
+ /**
+ * Extract the used codepoints for font embedding / subsetting
+ * @param typeface the typeface/font family of the textruns to examine
+ * @param italic use {@code true} for italic TextRuns, {@code false} for non-italic ones and
+ * {@code null} if it doesn't matter
+ * @param bold use {@code true} for bold TextRuns, {@code false} for non-bold ones and
+ * {@code null} if it doesn't matter
+ * @return a bitset with the marked/used codepoints
+ */
+ public SparseBitSet getCodepointsInSparseBitSet(String typeface, Boolean italic, Boolean bold) {
+ final SparseBitSet glyphs = new SparseBitSet();
+
+ Predicate