From b524036bd43d59102fb8defe15d6adb3918ee5cc Mon Sep 17 00:00:00 2001 From: Yegor Kozlov Date: Sat, 9 Nov 2013 11:57:21 +0000 Subject: [PATCH] Bugzilla 55560 : Patch for hiding slides in HSLF git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1540295 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/org/apache/poi/hslf/model/Slide.java | 22 ++ .../apache/poi/hslf/record/RecordTypes.java | 2 +- .../poi/hslf/record/SSSlideInfoAtom.java | 289 ++++++++++++++++++ .../apache/poi/hslf/record/TestSlideAtom.java | 23 +- 4 files changed, 333 insertions(+), 3 deletions(-) create mode 100644 src/scratchpad/src/org/apache/poi/hslf/record/SSSlideInfoAtom.java diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java b/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java index 60ab2b120e..79ef820ac8 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java @@ -32,6 +32,7 @@ import org.apache.poi.hslf.record.HeadersFootersContainer; import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.RecordContainer; import org.apache.poi.hslf.record.RecordTypes; +import org.apache.poi.hslf.record.SSSlideInfoAtom; import org.apache.poi.hslf.record.SlideAtom; import org.apache.poi.hslf.record.StyleTextProp9Atom; import org.apache.poi.hslf.record.TextHeaderAtom; @@ -488,4 +489,25 @@ public final class Slide extends Sheet public EscherTextboxWrapper[] getTextboxWrappers() { return this.getPPDrawing().getTextboxWrappers(); } + + public void setHidden(boolean hidden) { + org.apache.poi.hslf.record.Slide cont = getSlideRecord(); + + SSSlideInfoAtom slideInfo = + (SSSlideInfoAtom)cont.findFirstOfType(RecordTypes.SSSlideInfoAtom.typeID); + if (slideInfo == null) { + slideInfo = new SSSlideInfoAtom(); + cont.addChildAfter(slideInfo, cont.findFirstOfType(RecordTypes.SlideAtom.typeID)); + } + + slideInfo.setEffectTransitionFlagByBit(SSSlideInfoAtom.HIDDEN_BIT, hidden); + } + + public boolean getHidden() { + SSSlideInfoAtom slideInfo = + (SSSlideInfoAtom)getSlideRecord().findFirstOfType(RecordTypes.SSSlideInfoAtom.typeID); + return (slideInfo == null) + ? false + : slideInfo.getEffectTransitionFlagByBit(SSSlideInfoAtom.HIDDEN_BIT); + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java index 455e261c21..2b2dc4bddf 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java @@ -46,7 +46,7 @@ public final class RecordTypes { public static final Type SlidePersistAtom = new Type(1011,SlidePersistAtom.class); public static final Type SSlideLayoutAtom = new Type(1015,null); public static final Type MainMaster = new Type(1016,MainMaster.class); - public static final Type SSSlideInfoAtom = new Type(1017,null); + public static final Type SSSlideInfoAtom = new Type(1017,SSSlideInfoAtom.class); public static final Type SlideViewInfo = new Type(1018,null); public static final Type GuideAtom = new Type(1019,null); public static final Type ViewInfo = new Type(1020,null); diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/SSSlideInfoAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/SSSlideInfoAtom.java new file mode 100644 index 0000000000..0fbc7ff75f --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/record/SSSlideInfoAtom.java @@ -0,0 +1,289 @@ +/* ==================================================================== + 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 java.io.IOException; +import java.io.OutputStream; + +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianConsts; + +/** + * A SlideShowSlideInfo Atom (type 1017).
+ *
+ * + * An atom record that specifies which transition effects to perform + * during a slide show, and how to advance to the next presentation slide.
+ *
+ * + * Combination of effectType and effectDirection: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
typedescriptiondirection
0cut0x00 = no transition, 0x01 = black transition
1random0x00
2blinds0x00 = vertical, 0x01 = horizontal
3checkerlike blinds
4cover0x00 = left, 0x01 = up, 0x02 = right, 0x03 = down, 0x04 = left/up, 0x05 = right/up, 0x06 left/down, 0x07 = left/down
5dissolve0x00
6fade0x00
7uncoverlike cover
8random barslike blinds
9stripslike 0x04 - 0x07 of cover
10wipelike 0x00 - 0x03 of cover
11box in/out0x00 = out, 0x01 = in
13split0x00 = horizontally out, 0x01 = horizontally in, 0x02 = vertically out, 0x03 = vertically in
17diamond0x00
18plus0x00
19wedge0x00
20pushlike 0x00 - 0x03 of cover
21comblike blinds
22newsflash0x00
23alphafade0x00
26wheelnumber of radial divisions (0x01,0x02,0x03,0x04,0x08)
27circle0x00
255undefined0x00
+ */ +public class SSSlideInfoAtom extends RecordAtom { + /** + * A bit that specifies whether the presentation slide can be + * manually advanced by the user during the slide show. + */ + public static int MANUAL_ADVANCE_BIT = 1 << 0; + + /** + * A bit that specifies whether the corresponding slide is + * hidden and is not displayed during the slide show. + */ + public static int HIDDEN_BIT = 1 << 2; + + /** + * A bit that specifies whether to play the sound specified by soundIfRef. + */ + public static int SOUND_BIT = 1 << 4; + + /** + * A bit that specifies whether the sound specified by soundIdRef is + * looped continuously when playing until the next sound plays. + */ + public static int LOOP_SOUND_BIT = 1 << 6; + + /** + * A bit that specifies whether to stop any currently playing + * sound when the transition starts. + */ + public static int STOP_SOUND_BIT = 1 << 8; + + /** + * A bit that specifies whether the slide will automatically + * advance after slideTime milliseconds during the slide show. + */ + public static int AUTO_ADVANCE_BIT = 1 << 10; + + /** + * A bit that specifies whether to display the cursor during + * the slide show. + */ + public static int CURSOR_VISIBLE_BIT = 1 << 12; + + // public static int RESERVED1_BIT = 1 << 1; + // public static int RESERVED2_BIT = 1 << 3; + // public static int RESERVED3_BIT = 1 << 5; + // public static int RESERVED4_BIT = 1 << 7; + // public static int RESERVED5_BIT = 1 << 9; + // public static int RESERVED6_BIT = 1 << 11; + // public static int RESERVED7_BIT = 1 << 13 | 1 << 14 | 1 << 15; + + private static long _type = RecordTypes.SSSlideInfoAtom.typeID; + + private byte[] _header; + + /** + * A signed integer that specifies an amount of time, in milliseconds, to wait + * before advancing to the next presentation slide. It MUST be greater than or equal to 0 and + * less than or equal to 86399000. It MUST be ignored unless AUTO_ADVANCE_BIT is TRUE. + */ + private int _slideTime = 0; + + /** + * A SoundIdRef that specifies which sound to play when the transition starts. + */ + private int _soundIdRef = 0; + + /** + * A byte that specifies the variant of effectType. In combination of the effectType + * there are further restriction and specification of this field. + */ + private short _effectDirection = 0; // byte + + /** + * A byte that specifies which transition is used when transitioning to the + * next presentation slide during a slide show. Exact rendering of any transition is + * determined by the rendering application. As such, the same transition can have + * many variations depending on the implementation. + */ + private short _effectType = 0; // byte + + /** + * Various flags - see bitmask for more details + */ + private short _effectTransitionFlags = 0; + + /** + * A byte value that specifies how long the transition takes to run. + * (0x00 = 0.75 seconds, 0x01 = 0.5 seconds, 0x02 = 0.25 seconds) + */ + private short _speed = 0; // byte + private byte[] _unused; // 3-byte + + public SSSlideInfoAtom() { + _header = new byte[8]; + LittleEndian.putShort(_header, 0, (short)0); + LittleEndian.putShort(_header, 2, (short)_type); + LittleEndian.putShort(_header, 4, (short)0x10); + LittleEndian.putShort(_header, 6, (short)0); + _unused = new byte[3]; + } + + public SSSlideInfoAtom(byte[] source, int offset, int len) { + int ofs = offset; + + // Sanity Checking + if(len != 24) len = 24; + assert(source.length >= offset+len); + + // Get the header + _header = LittleEndian.getByteArray(source,ofs,8); + ofs += _header.length; + + assert(LittleEndian.getShort(_header, 0) == 0); + assert(LittleEndian.getShort(_header, 2) == RecordTypes.SSSlideInfoAtom.typeID); + assert(LittleEndian.getShort(_header, 4) == 0x10); + assert(LittleEndian.getShort(_header, 6) == 0); + + _slideTime = LittleEndian.getInt(source, ofs); + assert(0 <= _slideTime && _slideTime <= 86399000); + ofs += LittleEndianConsts.INT_SIZE; + _soundIdRef = LittleEndian.getInt(source, ofs); + ofs += LittleEndianConsts.INT_SIZE; + _effectDirection = LittleEndian.getUByte(source, ofs); + ofs += LittleEndianConsts.BYTE_SIZE; + _effectType = LittleEndian.getUByte(source, ofs); + ofs += LittleEndianConsts.BYTE_SIZE; + _effectTransitionFlags = LittleEndian.getShort(source, ofs); + ofs += LittleEndianConsts.SHORT_SIZE; + _speed = LittleEndian.getUByte(source, ofs); + ofs += LittleEndianConsts.BYTE_SIZE; + _unused = LittleEndian.getByteArray(source,ofs,3); + } + + /** + * Write the contents of the record back, so it can be written + * to disk + */ + public void writeOut(OutputStream out) throws IOException { + // Header - size or type unchanged + out.write(_header); + writeLittleEndian(_slideTime, out); + writeLittleEndian(_soundIdRef, out); + + byte byteBuf[] = new byte[LittleEndianConsts.BYTE_SIZE]; + LittleEndian.putUByte(byteBuf, 0, _effectDirection); + out.write(byteBuf); + LittleEndian.putUByte(byteBuf, 0, _effectType); + out.write(byteBuf); + + writeLittleEndian(_effectTransitionFlags, out); + LittleEndian.putUByte(byteBuf, 0, _speed); + out.write(byteBuf); + + assert(_unused.length == 3); + out.write(_unused); + } + + /** + * We are of type 1017 + */ + public long getRecordType() { return _type; } + + + public int getSlideTime() { + return _slideTime; + } + + public void setSlideTime(int slideTime) { + this._slideTime = slideTime; + } + + public int getSoundIdRef() { + return _soundIdRef; + } + + public void setSoundIdRef(int soundIdRef) { + this._soundIdRef = soundIdRef; + } + + public short getEffectDirection() { + return _effectDirection; + } + + public void setEffectDirection(short effectDirection) { + this._effectDirection = effectDirection; + } + + public short getEffectType() { + return _effectType; + } + + public void setEffectType(short effectType) { + this._effectType = effectType; + } + + public short getEffectTransitionFlags() { + return _effectTransitionFlags; + } + + public void setEffectTransitionFlags(short effectTransitionFlags) { + this._effectTransitionFlags = effectTransitionFlags; + } + + /** + * Use one of the bitmasks MANUAL_ADVANCE_BIT ... CURSOR_VISIBLE_BIT + * @param bitmask + * @param enabled + */ + public void setEffectTransitionFlagByBit(int bitmask, boolean enabled) { + if (enabled) { + _effectTransitionFlags |= bitmask; + } else { + _effectTransitionFlags &= (0xFFFF ^ bitmask); + } + } + + public boolean getEffectTransitionFlagByBit(int bitmask) { + return ((_effectTransitionFlags & bitmask) != 0); + } + + public short getSpeed() { + return _speed; + } + + public void setSpeed(short speed) { + this._speed = speed; + } +} diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestSlideAtom.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestSlideAtom.java index 28b122abae..26e608bc37 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestSlideAtom.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestSlideAtom.java @@ -17,10 +17,14 @@ package org.apache.poi.hslf.record; -import org.apache.poi.hslf.record.SlideAtom.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; import junit.framework.TestCase; -import java.io.ByteArrayOutputStream; + +import org.apache.poi.hslf.record.SlideAtom.SSlideLayoutAtom; +import org.apache.poi.hslf.usermodel.SlideShow; /** * Tests that SlideAtom works properly @@ -71,4 +75,19 @@ public final class TestSlideAtom extends TestCase { assertEquals(data_a[i],b[i]); } } + + public void testSSSlideInfoAtom() throws Exception { + SlideShow ss = new SlideShow(); + org.apache.poi.hslf.model.Slide slide1 = ss.createSlide(), slide2 = ss.createSlide(); + slide2.setHidden(true); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(4096); + ss.write(bos); + ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); + ss = new SlideShow(bis); + slide1 = ss.getSlides()[0]; + slide2 = ss.getSlides()[1]; + assertFalse(slide1.getHidden()); + assertTrue(slide2.getHidden()); + } } -- 2.39.5