Skip to content

Commit 9d22e1a

Browse files
committed
TIKA-4831 - sort slide ids without parsing them as int
A crafted _slide id with more digits than an int holds threw an uncaught NumberFormatException out of the sort comparator; compare the digit strings by length then lexicographically instead. The regression test builds a two-slide container with an oversized id.
1 parent 34997b9 commit 9d22e1a

2 files changed

Lines changed: 44 additions & 3 deletions

File tree

  • tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src

tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/geogebra/GeoGebraParser.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,15 @@ private List<String> getSlideIds(ZipFile zipFile) {
192192
numericallySorted.add(m.group(1));
193193
}
194194
}
195-
numericallySorted.sort((a, b) -> Integer.compare(
196-
Integer.parseInt(a.substring("_slide".length())),
197-
Integer.parseInt(b.substring("_slide".length()))));
195+
//compare the digit suffixes numerically without parsing them: a shorter
196+
//digit string is the smaller number, equal lengths compare lexicographically.
197+
//Parsing would throw for a crafted id with more digits than an int holds.
198+
numericallySorted.sort((a, b) -> {
199+
String da = a.substring("_slide".length());
200+
String db = b.substring("_slide".length());
201+
return da.length() != db.length()
202+
? Integer.compare(da.length(), db.length()) : da.compareTo(db);
203+
});
198204

199205
ZipArchiveEntry structure = zipFile.getEntry(STRUCTURE_JSON);
200206
if (structure == null || numericallySorted.isEmpty()) {

tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/geogebra/GeoGebraParserTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,21 @@
2020
import static org.junit.jupiter.api.Assertions.assertNull;
2121
import static org.junit.jupiter.api.Assertions.assertTrue;
2222

23+
import java.io.ByteArrayOutputStream;
24+
import java.nio.charset.StandardCharsets;
2325
import java.util.List;
26+
import java.util.zip.ZipEntry;
27+
import java.util.zip.ZipOutputStream;
2428

2529
import org.junit.jupiter.api.Test;
2630

2731
import org.apache.tika.TikaTest;
32+
import org.apache.tika.io.TikaInputStream;
2833
import org.apache.tika.metadata.HttpHeaders;
2934
import org.apache.tika.metadata.Metadata;
3035
import org.apache.tika.metadata.PagedText;
3136
import org.apache.tika.metadata.TikaCoreProperties;
37+
import org.apache.tika.parser.ParseContext;
3238

3339
public class GeoGebraParserTest extends TikaTest {
3440

@@ -112,4 +118,33 @@ public void testGGT() throws Exception {
112118
assertEquals(1, metadataList.size());
113119
assertNull(metadata.get(TikaCoreProperties.TITLE));
114120
}
121+
122+
/**
123+
* A crafted slide id can carry more digits than an int holds; sorting the
124+
* slide ids must not throw a NumberFormatException out of parse().
125+
*/
126+
@Test
127+
public void testSlideNumberLargerThanIntParses() throws Exception {
128+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
129+
try (ZipOutputStream zos = new ZipOutputStream(bos)) {
130+
zos.putNextEntry(new ZipEntry("structure.json"));
131+
//two slides so that sorting actually compares the ids
132+
zos.write(("{\"chapters\":[{\"pages\":[{\"elements\":"
133+
+ "[{\"id\":\"_slide0\"},{\"id\":\"_slide99999999999\"}]}]}]}")
134+
.getBytes(StandardCharsets.UTF_8));
135+
zos.closeEntry();
136+
zos.putNextEntry(new ZipEntry("_slide0/geogebra.xml"));
137+
zos.write("<geogebra format=\"5.0\"></geogebra>".getBytes(StandardCharsets.UTF_8));
138+
zos.closeEntry();
139+
zos.putNextEntry(new ZipEntry("_slide99999999999/geogebra.xml"));
140+
zos.write("<geogebra format=\"5.0\"></geogebra>".getBytes(StandardCharsets.UTF_8));
141+
zos.closeEntry();
142+
}
143+
try (TikaInputStream tis = TikaInputStream.get(bos.toByteArray())) {
144+
List<Metadata> metadataList =
145+
getRecursiveMetadata(tis, new Metadata(), new ParseContext(), false);
146+
assertEquals("application/vnd.geogebra.slides",
147+
metadataList.get(0).get(HttpHeaders.CONTENT_TYPE));
148+
}
149+
}
115150
}

0 commit comments

Comments
 (0)