Support for getting embedded sounds from slide show

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@649796 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-04-19 11:09:59 +00:00
parent 15b47da3fb
commit 76a479f668
10 changed files with 565 additions and 2 deletions

View File

@ -70,9 +70,10 @@ public class RecordTypes {
public static final Type List = new Type(2000,null);
public static final Type FontCollection = new Type(2005,FontCollection.class);
public static final Type BookmarkCollection = new Type(2019,null);
public static final Type SoundCollection = new Type(2020,SoundCollection.class);
public static final Type SoundCollAtom = new Type(2021,null);
public static final Type Sound = new Type(2022,null);
public static final Type SoundData = new Type(2023,null);
public static final Type Sound = new Type(2022,Sound.class);
public static final Type SoundData = new Type(2023,SoundData.class);
public static final Type BookmarkSeedAtom = new Type(2025,null);
public static final Type ColorSchemeAtom = new Type(2032,ColorSchemeAtom.class);
public static final Type ExObjRefAtom = new Type(3009,null);

View File

@ -0,0 +1,136 @@
/* ====================================================================
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.util.POILogger;
import java.io.OutputStream;
import java.io.IOException;
/**
* A container holding information about a sound. It contains:
* <p>
* <li>1. CString (4026), Instance 0: Name of sound (e.g. "crash")
* <li>2. CString (4026), Instance 1: Type of sound (e.g. ".wav")
* <li>3. CString (4026), Instance 2: Reference id of sound in sound collection
* <li>4. CString (4026), Instance 3, optional: Built-in id of sound, for sounds we ship. This is the id that?s in the reg file.
* <li>5. SoundData (2023), optional
* </p>
*
* @author Yegor Kozlov
*/
public class Sound extends RecordContainer {
/**
* Record header data.
*/
private byte[] _header;
// Links to our more interesting children
private CString _name;
private CString _type;
private SoundData _data;
/**
* Set things up, and find our more interesting children
*
* @param source the source data as a byte array.
* @param start the start offset into the byte array.
* @param len the length of the slice in the byte array.
*/
protected Sound(byte[] source, int start, int len) {
// Grab the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Find our children
_children = Record.findChildRecords(source,start+8,len-8);
findInterestingChildren();
}
private void findInterestingChildren() {
// First child should be the ExHyperlinkAtom
if(_children[0] instanceof CString) {
_name = (CString)_children[0];
} else {
logger.log(POILogger.ERROR, "First child record wasn't a CString, was of type " + _children[0].getRecordType());
}
// Second child should be the ExOleObjAtom
if (_children[1] instanceof CString) {
_type = (CString)_children[1];
} else {
logger.log(POILogger.ERROR, "Second child record wasn't a CString, was of type " + _children[1].getRecordType());
}
for (int i = 2; i < _children.length; i++) {
if(_children[i] instanceof SoundData){
_data = (SoundData)_children[i];
break;
}
}
}
/**
* Returns the type (held as a little endian in bytes 3 and 4)
* that this class handles.
*
* @return the record type.
*/
public long getRecordType() {
return RecordTypes.Sound.typeID;
}
/**
* Have the contents printer out into an OutputStream, used when
* writing a file back out to disk.
*
* @param out the output stream.
* @throws java.io.IOException if there was an error writing to the stream.
*/
public void writeOut(OutputStream out) throws IOException {
writeOut(_header[0],_header[1],getRecordType(),_children,out);
}
/**
* Name of the sound (e.g. "crash")
*
* @return name of the sound
*/
public String getSoundName(){
return _name.getText();
}
/**
* Type of the sound (e.g. ".wav")
*
* @return type of the sound
*/
public String getSoundType(){
return _type.getText();
}
/**
* The sound data
*
* @return the sound data.
*/
public byte[] getSoundData(){
return _data == null ? null : _data.getData();
}
}

View File

@ -0,0 +1,73 @@
/* ====================================================================
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.util.POILogger;
import java.io.OutputStream;
import java.io.IOException;
/**
* Is a container for all sound related atoms and containers. It contains:
*<li>1. SoundCollAtom (2021)
*<li>2. Sound (2022), for each sound, if any
*
* @author Yegor Kozlov
*/
public class SoundCollection extends RecordContainer {
/**
* Record header data.
*/
private byte[] _header;
/**
* Set things up, and find our more interesting children
*
* @param source the source data as a byte array.
* @param start the start offset into the byte array.
* @param len the length of the slice in the byte array.
*/
protected SoundCollection(byte[] source, int start, int len) {
// Grab the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Find our children
_children = Record.findChildRecords(source,start+8,len-8);
}
/**
* Returns the type (held as a little endian in bytes 3 and 4)
* that this class handles.
*
* @return the record type.
*/
public long getRecordType() {
return RecordTypes.SoundCollection.typeID;
}
/**
* Have the contents printer out into an OutputStream, used when
* writing a file back out to disk.
*
* @param out the output stream.
* @throws java.io.IOException if there was an error writing to the stream.
*/
public void writeOut(OutputStream out) throws IOException {
writeOut(_header[0],_header[1],getRecordType(),_children,out);
}
}

View File

@ -0,0 +1,103 @@
/* ====================================================================
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.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.InflaterInputStream;
import org.apache.poi.util.LittleEndian;
/**
* Storage for embedded sounds.
*
* @author Yegor Kozlov
*/
public class SoundData extends RecordAtom {
/**
* Record header.
*/
private byte[] _header;
/**
* Record data.
*/
private byte[] _data;
/**
* Constructs a new empty sound container.
*/
protected SoundData() {
_header = new byte[8];
_data = new byte[0];
LittleEndian.putShort(_header, 2, (short)getRecordType());
LittleEndian.putInt(_header, 4, _data.length);
}
/**
* Constructs the link related atom record from its
* source data.
*
* @param source the source data as a byte array.
* @param start the start offset into the byte array.
* @param len the length of the slice in the byte array.
*/
protected SoundData(byte[] source, int start, int len) {
// Get the header.
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Get the record data.
_data = new byte[len-8];
System.arraycopy(source,start+8,_data,0,len-8);
}
/**
* Returns the sound data.
*
* @return the sound data
*/
public byte[] getData() {
return _data;
}
/**
* Gets the record type.
*
* @return the record type.
*/
public long getRecordType() {
return RecordTypes.SoundData.typeID;
}
/**
* Write the contents of the record back, so it can be written
* to disk.
*
* @param out the output stream to write to.
* @throws java.io.IOException if an error occurs.
*/
public void writeOut(OutputStream out) throws IOException {
out.write(_header);
out.write(_data);
}
}

View File

@ -494,6 +494,14 @@ public class SlideShow
public ObjectData[] getEmbeddedObjects() {
return _hslfSlideShow.getEmbeddedObjects();
}
/**
* Returns the data of all the embedded sounds in the SlideShow
*/
public SoundData[] getSoundData() {
return SoundData.find(_documentRecord);
}
/**
* Return the current page size
*/

View File

@ -0,0 +1,93 @@
/* ====================================================================
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.usermodel;
import org.apache.poi.hslf.record.*;
import java.util.ArrayList;
/**
* A class that represents sound data embedded in a slide show.
*
* @author Yegor Kozlov
*/
public class SoundData {
/**
* The record that contains the object data.
*/
private Sound _container;
/**
* Creates the object data wrapping the record that contains the sound data.
*
* @param container the record that contains the sound data.
*/
public SoundData(Sound container) {
this._container = container;
}
/**
* Name of the sound (e.g. "crash")
*
* @return name of the sound
*/
public String getSoundName(){
return _container.getSoundName();
}
/**
* Type of the sound (e.g. ".wav")
*
* @return type of the sound
*/
public String getSoundType(){
return _container.getSoundType();
}
/**
* Gets an input stream which returns the binary of the sound data.
*
* @return the input stream which will contain the binary of the sound data.
*/
public byte[] getData() {
return _container.getSoundData();
}
/**
* Find all sound records in the supplied Document records
*
* @param document the document to find in
* @return the array with the sound data
*/
public static SoundData[] find(Document document){
ArrayList lst = new ArrayList();
Record[] ch = document.getChildRecords();
for (int i = 0; i < ch.length; i++) {
if(ch[i].getRecordType() == RecordTypes.SoundCollection.typeID){
RecordContainer col = (RecordContainer)ch[i];
Record[] sr = col.getChildRecords();
for (int j = 0; j < sr.length; j++) {
if(sr[j] instanceof Sound){
lst.add(new SoundData((Sound)sr[j]));
}
}
}
}
return (SoundData[])lst.toArray(new SoundData[lst.size()]);
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,86 @@
/* ====================================================================
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 junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Arrays;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.SlideShow;
/**
* Tests Sound-related records: SoundCollection(2020), Sound(2022) and SoundData(2023)).
*
* @author Yegor Kozlov
*/
public class TestSound extends TestCase {
public void testRealFile() throws Exception {
String cwd = System.getProperty("HSLF.testdata.path");
FileInputStream is = new FileInputStream(new File(cwd, "sound.ppt"));
SlideShow ppt = new SlideShow(is);
is.close();
// Get the document
Document doc = ppt.getDocumentRecord();
SoundCollection soundCollection = null;
Record[] doc_ch = doc.getChildRecords();
for (int i = 0; i < doc_ch.length; i++) {
if(doc_ch[i] instanceof SoundCollection){
soundCollection = (SoundCollection)doc_ch[i];
break;
}
}
assertNotNull(soundCollection);
Sound sound = null;
Record[] sound_ch = soundCollection.getChildRecords();
int k = 0;
for (int i = 0; i < sound_ch.length; i++) {
if(sound_ch[i] instanceof Sound){
sound = (Sound)sound_ch[i];
k++;
}
}
assertNotNull(sound);
assertEquals(1, k);
assertEquals("ringin.wav", sound.getSoundName());
assertEquals(".WAV", sound.getSoundType());
assertNotNull(sound.getSoundData());
File f = new File(cwd, "ringin.wav");
int length = (int)f.length();
byte[] ref_data = new byte[length];
is = new FileInputStream(f);
is.read(ref_data);
is.close();
assertTrue(Arrays.equals(ref_data, sound.getSoundData()));
}
}

View File

@ -0,0 +1,63 @@
/* ====================================================================
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.usermodel;
import org.apache.poi.hslf.*;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.blip.*;
import org.apache.poi.hslf.model.*;
import junit.framework.TestCase;
import java.io.*;
import java.util.Arrays;
/**
* Test reading sound data from a ppt
*
* @author Yegor Kozlov
*/
public class TestSoundData extends TestCase{
protected File cwd;
public void setUp() throws Exception {
cwd = new File(System.getProperty("HSLF.testdata.path"));
}
/**
* Read a reference sound file from disk and compare it from the data extracted from the slide show
*/
public void testSounds() throws Exception {
//read the reference sound file
File f = new File(cwd, "ringin.wav");
int length = (int)f.length();
byte[] ref_data = new byte[length];
FileInputStream is = new FileInputStream(f);
is.read(ref_data);
is.close();
is = new FileInputStream(new File(cwd, "sound.ppt"));
SlideShow ppt = new SlideShow(is);
is.close();
SoundData[] sound = ppt.getSoundData();
assertEquals("Expected 1 sound", 1, sound.length);
assertTrue(Arrays.equals(ref_data, sound[0].getData()));
}
}