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()); + } +}