diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/FontEntityAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/FontEntityAtom.java index 073ce26946..118fc1d3bf 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/FontEntityAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/FontEntityAtom.java @@ -86,15 +86,39 @@ public final class FontEntityAtom extends RecordAtom { * @return font name */ public String getFontName(){ - int maxLen = Math.min(_recdata.length,64); - for(int i = 0; i < maxLen; i+=2){ + final int maxLen = Math.min(_recdata.length,64); + for(int i = 0; i+1 < maxLen; i+=2){ //loop until find null-terminated end of the font name - if(_recdata[i] == 0 && _recdata[i + 1] == 0) { + if(_recdata[i] == 0 && _recdata[i + 1] == 0 && !isFontNamePremature0terminated(i)) { return StringUtil.getFromUnicodeLE(_recdata, 0, i/2); } } return null; } + + /** + * #61881: there seem to be programs out there, which write the 0-termination also + * at the beginning of the string. Check if the next two bytes contain a valid ascii char + * and correct the _recdata with a '?' char + */ + private boolean isFontNamePremature0terminated(final int index) { + if (index > 0) { + // for now we only check the first char + return false; + } + + if (_recdata.length < index+4) { + return false; + } + + final int cp = LittleEndian.getShort(_recdata, index+2); + if (!Character.isJavaIdentifierPart(cp)) { + return false; + } + + _recdata[index] = '?'; + return true; + } /** * Set the name of the font. diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestFontCollection.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestFontCollection.java index 7ca07bd82e..36bddee8cf 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestFontCollection.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestFontCollection.java @@ -23,9 +23,12 @@ import static org.junit.Assert.assertNull; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; +import org.apache.poi.POIDataSamples; import org.apache.poi.hslf.usermodel.HSLFFontInfo; import org.apache.poi.hslf.usermodel.HSLFFontInfoPredefined; +import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.poifs.storage.RawDataUtil; import org.junit.BeforeClass; import org.junit.Test; @@ -34,6 +37,8 @@ import org.junit.Test; * Tests {@code FontCollection} and {@code FontEntityAtom} records */ public final class TestFontCollection { + private static final POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); + // From a real file private static byte[] data; @@ -87,4 +92,13 @@ public final class TestFontCollection { byte[] recdata = out.toByteArray(); assertArrayEquals(recdata, data); } + + @Test + public void bug61881() throws IOException { + try (InputStream is = _slTests.openResourceAsStream("bug61881.ppt")) { + try (HSLFSlideShow ppt = new HSLFSlideShow(is)) { + assertEquals("?imes New Roman",ppt.getFont(3).getTypeface()); + } + } + } } diff --git a/test-data/slideshow/bug61881.ppt b/test-data/slideshow/bug61881.ppt new file mode 100644 index 0000000000..1fa859064e Binary files /dev/null and b/test-data/slideshow/bug61881.ppt differ