| /* ==================================================================== |
| 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 static org.apache.poi.util.GenericRecordUtil.getBitsAsString; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.util.Arrays; |
| import java.util.Map; |
| import java.util.function.Supplier; |
| |
| import org.apache.poi.util.GenericRecordUtil; |
| import org.apache.poi.util.LittleEndian; |
| import org.apache.poi.util.LittleEndianConsts; |
| |
| /** |
| * A SlideShowSlideInfo Atom (type 1017).<br> |
| * <br> |
| * |
| * An atom record that specifies which transition effects to perform |
| * during a slide show, and how to advance to the next presentation slide.<br> |
| * <br> |
| * |
| * Combination of effectType and effectDirection: |
| * <table summary=""> |
| * <tr><th>type</th><th>description</th><th>direction</th></tr> |
| * <tr><td>0</td><td>cut</td><td>0x00 = no transition, 0x01 = black transition</td></tr> |
| * <tr><td>1</td><td>random</td><td>0x00</td></tr> |
| * <tr><td>2</td><td>blinds</td><td>0x00 = vertical, 0x01 = horizontal</td></tr> |
| * <tr><td>3</td><td>checker</td><td>like blinds</td></tr> |
| * <tr><td>4</td><td>cover</td><td>0x00 = left, 0x01 = up, 0x02 = right, 0x03 = down, 0x04 = left/up, 0x05 = right/up, 0x06 left/down, 0x07 = left/down</td></tr> |
| * <tr><td>5</td><td>dissolve</td><td>0x00</td></tr> |
| * <tr><td>6</td><td>fade</td><td>0x00</td></tr> |
| * <tr><td>7</td><td>uncover</td><td>like cover</td></tr> |
| * <tr><td>8</td><td>random bars</td><td>like blinds</td></tr> |
| * <tr><td>9</td><td>strips</td><td>like 0x04 - 0x07 of cover</td></tr> |
| * <tr><td>10</td><td>wipe</td><td>like 0x00 - 0x03 of cover</td></tr> |
| * <tr><td>11</td><td>box in/out</td><td>0x00 = out, 0x01 = in</td></tr> |
| * <tr><td>13</td><td>split</td><td>0x00 = horizontally out, 0x01 = horizontally in, 0x02 = vertically out, 0x03 = vertically in</td></tr> |
| * <tr><td>17</td><td>diamond</td><td>0x00</td></tr> |
| * <tr><td>18</td><td>plus</td><td>0x00</td></tr> |
| * <tr><td>19</td><td>wedge</td><td>0x00</td></tr> |
| * <tr><td>20</td><td>push</td><td>like 0x00 - 0x03 of cover</td></tr> |
| * <tr><td>21</td><td>comb</td><td>like blinds</td></tr> |
| * <tr><td>22</td><td>newsflash</td><td>0x00</td></tr> |
| * <tr><td>23</td><td>alphafade</td><td>0x00</td></tr> |
| * <tr><td>26</td><td>wheel</td><td>number of radial divisions (0x01,0x02,0x03,0x04,0x08)</td></tr> |
| * <tr><td>27</td><td>circle</td><td>0x00</td></tr> |
| * <tr><td>255</td><td>undefined</td><td>0x00</td></tr> |
| * </table> |
| */ |
| 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 final 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 final int HIDDEN_BIT = 1 << 2; |
| |
| /** |
| * A bit that specifies whether to play the sound specified by soundIfRef. |
| */ |
| public static final 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 final int LOOP_SOUND_BIT = 1 << 6; |
| |
| /** |
| * A bit that specifies whether to stop any currently playing |
| * sound when the transition starts. |
| */ |
| public static final 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 final int AUTO_ADVANCE_BIT = 1 << 10; |
| |
| /** |
| * A bit that specifies whether to display the cursor during |
| * the slide show. |
| */ |
| public static final 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 final int[] EFFECT_MASKS = { |
| MANUAL_ADVANCE_BIT, |
| HIDDEN_BIT, |
| SOUND_BIT, |
| LOOP_SOUND_BIT, |
| STOP_SOUND_BIT, |
| AUTO_ADVANCE_BIT, |
| CURSOR_VISIBLE_BIT |
| }; |
| |
| private static final String[] EFFECT_NAMES = { |
| "MANUAL_ADVANCE", |
| "HIDDEN", |
| "SOUND", |
| "LOOP_SOUND", |
| "STOP_SOUND", |
| "AUTO_ADVANCE", |
| "CURSOR_VISIBLE" |
| }; |
| |
| private static final long _type = RecordTypes.SSSlideInfoAtom.typeID; |
| |
| private final 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; |
| |
| /** |
| * A SoundIdRef that specifies which sound to play when the transition starts. |
| */ |
| private int _soundIdRef; |
| |
| /** |
| * 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; // 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; // byte |
| |
| /** |
| * Various flags - see bitmask for more details |
| */ |
| private short _effectTransitionFlags; |
| |
| /** |
| * 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; // byte |
| private final 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 = Arrays.copyOfRange(source, ofs, 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 = Arrays.copyOfRange(source,ofs,ofs+3); |
| } |
| |
| /** |
| * Write the contents of the record back, so it can be written |
| * to disk |
| */ |
| @Override |
| 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 |
| */ |
| @Override |
| 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 |
| */ |
| 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; |
| } |
| |
| @Override |
| public Map<String, Supplier<?>> getGenericProperties() { |
| return GenericRecordUtil.getGenericProperties( |
| "effectTransitionFlags", getBitsAsString(this::getEffectTransitionFlags, EFFECT_MASKS, EFFECT_NAMES), |
| "slideTime", this::getSlideTime, |
| "soundIdRef", this::getSoundIdRef, |
| "effectDirection", this::getEffectDirection, |
| "effectType", this::getEffectType, |
| "speed", this::getSpeed |
| ); |
| } |
| } |