diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
index 5dac65025..f2d265363 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
@@ -45,7 +45,6 @@ public class TextRun
protected TextBytesAtom _byteAtom;
protected TextCharsAtom _charAtom;
protected StyleTextPropAtom _styleAtom;
- protected TextSpecInfoAtom _specAtom;
protected boolean _isUnicode;
protected RichTextRun[] _rtRuns;
private SlideShow slideShow;
@@ -361,6 +360,18 @@ public class TextRun
_isUnicode = true;
}
}
+ /**
+ * If TextSpecInfoAtom is present, we must update the text size in it,
+ * otherwise the ppt will be corrupted
+ */
+ if(_records != null) for (int i = 0; i < _records.length; i++) {
+ if(_records[i] instanceof TextSpecInfoAtom){
+ TextSpecInfoAtom specAtom = (TextSpecInfoAtom)_records[i];
+ if((s.length() + 1) != specAtom.getCharactersCovered()){
+ specAtom.reset(s.length() + 1);
+ }
+ }
+ }
}
/**
@@ -474,17 +485,6 @@ public class TextRun
_rtRuns[0] = new RichTextRun(this,0,s.length());
}
- /**
- * If TextSpecInfoAtom is present, we must update the text size,
- * otherwise the ppt will be corrupted
- */
- if(_records != null) for (int i = 0; i < _records.length; i++) {
- if(_records[i] instanceof TextSpecInfoAtom){
- TextSpecInfoAtom specAtom = (TextSpecInfoAtom)_records[i];
- specAtom.setTextSize(s.length());
- }
-
- }
}
/**
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java
index a8915f049..85cdd1e15 100755
--- a/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java
@@ -20,6 +20,7 @@ import org.apache.poi.util.LittleEndian;
import java.io.OutputStream;
import java.io.IOException;
+import java.util.ArrayList;
/**
* The special info runs contained in this text.
@@ -82,4 +83,118 @@ public class TextSpecInfoAtom extends RecordAtom {
public void setTextSize(int size){
LittleEndian.putInt(_data, 0, size);
}
+
+ /**
+ * Reset the content to one info run with the default values
+ * @param size the site of parent text
+ */
+ public void reset(int size){
+ _data = new byte[10];
+ // 01 00 00 00
+ LittleEndian.putInt(_data, 0, size);
+ // 01 00 00 00
+ LittleEndian.putInt(_data, 4, 1); //mask
+ // 00 00
+ LittleEndian.putShort(_data, 8, (short)0); //langId
+
+ // Update the size (header bytes 5-8)
+ LittleEndian.putInt(_header, 4, _data.length);
+ }
+
+ /**
+ * Get the number of characters covered by this records
+ *
+ * @return the number of characters covered by this records
+ */
+ public int getCharactersCovered(){
+ int covered = 0;
+ TextSpecInfoRun[] runs = getTextSpecInfoRuns();
+ for (int i = 0; i < runs.length; i++) covered += runs[i].len;
+ return covered;
+ }
+
+ public TextSpecInfoRun[] getTextSpecInfoRuns(){
+ ArrayList lst = new ArrayList();
+ int pos = 0;
+ int[] bits = {1, 0, 2};
+ while(pos < _data.length) {
+ TextSpecInfoRun run = new TextSpecInfoRun();
+ run.len = LittleEndian.getInt(_data, pos); pos += 4;
+ run.mask = LittleEndian.getInt(_data, pos); pos += 4;
+ for (int i = 0; i < bits.length; i++) {
+ if((run.mask & 1 << bits[i]) != 0){
+ switch (bits[i]){
+ case 0:
+ run.spellInfo = LittleEndian.getShort(_data, pos); pos += 2;
+ break;
+ case 1:
+ run.langId = LittleEndian.getShort(_data, pos); pos += 2;
+ break;
+ case 2:
+ run.altLangId = LittleEndian.getShort(_data, pos); pos += 2;
+ break;
+ }
+ }
+ }
+ lst.add(run);
+ }
+ return (TextSpecInfoRun[])lst.toArray(new TextSpecInfoRun[lst.size()]);
+
+ }
+
+ public static class TextSpecInfoRun {
+ //Length of special info run.
+ protected int len;
+
+ //Special info mask of this run;
+ protected int mask;
+
+ // info fields as indicated by the mask.
+ // -1 means the bit is not set
+ protected short spellInfo = -1;
+ protected short langId = -1;
+ protected short altLangId = -1;
+
+ /**
+ * Spelling status of this text. See Spell Info table below.
+ *
+ *
Spell Info Types:
+ * 0 Unchecked
+ * 1 Previously incorrect, needs rechecking
+ * 2 Correct
+ * 3 Incorrect
+ *
+ * @return Spelling status of this text
+ */
+ public short getSpellInfo(){
+ return spellInfo;
+ }
+
+ /**
+ * Windows LANGID for this text.
+ *
+ * @return Windows LANGID for this text.
+ */
+ public short getLangId(){
+ return spellInfo;
+ }
+
+ /**
+ * Alternate Windows LANGID of this text;
+ * must be a valid non-East Asian LANGID if the text has an East Asian language,
+ * otherwise may be an East Asian LANGID or language neutral (zero).
+ *
+ * @return Alternate Windows LANGID of this text
+ */
+ public short getAltLangId(){
+ return altLangId;
+ }
+
+ /**
+ * @return Length of special info run.
+ */
+ public int length(){
+ return len;
+ }
+ }
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextSpecInfoAtom.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextSpecInfoAtom.java
new file mode 100755
index 000000000..5079628ae
--- /dev/null
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextSpecInfoAtom.java
@@ -0,0 +1,95 @@
+
+/* ====================================================================
+ 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.hslf.record;
+
+import org.apache.poi.hslf.HSLFSlideShow;
+import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
+import org.apache.poi.hslf.model.textproperties.TextProp;
+import org.apache.poi.hslf.model.textproperties.TextPropCollection;
+import org.apache.poi.hslf.record.StyleTextPropAtom.*;
+import org.apache.poi.hslf.usermodel.SlideShow;
+import org.apache.poi.util.HexDump;
+
+import junit.framework.TestCase;
+import java.io.ByteArrayOutputStream;
+import java.util.LinkedList;
+import java.util.Arrays;
+
+/**
+ * Tests TextSpecInfoAtom
+ *
+ * @author Yegor Kozlov
+ */
+public class TestTextSpecInfoAtom extends TestCase {
+
+ //from a real file
+ private byte[] data_1 = new byte[] {
+ 0x00, 0x00, (byte)0xAA, 0x0F, 0x2C, 0x00, 0x00, 0x00,
+ 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+
+ public void testRead() throws Exception {
+ TextSpecInfoAtom spec = new TextSpecInfoAtom(data_1, 0, data_1.length);
+ TextSpecInfoAtom.TextSpecInfoRun[] run = spec.getTextSpecInfoRuns();
+ assertEquals(5, run.length);
+
+ assertEquals(10, run[0].length());
+ assertEquals(1, run[1].length());
+ assertEquals(70, run[2].length());
+ assertEquals(9, run[3].length());
+ assertEquals(32, run[4].length());
+
+ }
+
+ public void testWrite() throws Exception {
+ TextSpecInfoAtom spec = new TextSpecInfoAtom(data_1, 0, data_1.length);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ spec.writeOut(out);
+
+ byte[] result = out.toByteArray();
+ assertTrue(Arrays.equals(result, data_1));
+ }
+
+ public void testReset() throws Exception {
+ TextSpecInfoAtom spec = new TextSpecInfoAtom(data_1, 0, data_1.length);
+ spec.reset(32); //length of the parent text
+
+ TextSpecInfoAtom.TextSpecInfoRun[] run = spec.getTextSpecInfoRuns();
+ assertEquals(1, run.length);
+
+ assertEquals(32, run[0].length());
+
+ //serialize and read again
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ spec.writeOut(out);
+
+ byte[] result = out.toByteArray();
+ TextSpecInfoAtom spec2 = new TextSpecInfoAtom(result, 0, result.length);
+ TextSpecInfoAtom.TextSpecInfoRun[] run2 = spec2.getTextSpecInfoRuns();
+ assertEquals(1, run2.length);
+
+ assertEquals(32, run2[0].length());
+ }
+}