mirror of https://github.com/apache/poi.git
Initial Powerpoint support, by Nick Burch
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353701 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
865c8bb4c4
commit
6424e17b17
|
@ -0,0 +1,347 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.poifs.filesystem.POIFSDocument;
|
||||
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||
|
||||
import org.apache.poi.hpsf.PropertySet;
|
||||
import org.apache.poi.hpsf.PropertySetFactory;
|
||||
import org.apache.poi.hpsf.MutablePropertySet;
|
||||
import org.apache.poi.hpsf.SummaryInformation;
|
||||
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
import org.apache.poi.hslf.record.*;
|
||||
|
||||
/**
|
||||
* This class contains the main functionality for the Powerpoint file
|
||||
* "reader". It is only a very basic class for now
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class HSLFSlideShow
|
||||
{
|
||||
private InputStream istream;
|
||||
private POIFSFileSystem filesystem;
|
||||
|
||||
// Holds metadata on our document
|
||||
private SummaryInformation sInf;
|
||||
private DocumentSummaryInformation dsInf;
|
||||
private CurrentUserAtom currentUser;
|
||||
|
||||
// Low level contents of the file
|
||||
private byte[] _docstream;
|
||||
|
||||
// Low level contents
|
||||
private Record[] _records;
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint document from fileName. Parses the document
|
||||
* and places all the important stuff into data structures.
|
||||
*
|
||||
* @param fileName The name of the file to read.
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public HSLFSlideShow(String fileName) throws IOException
|
||||
{
|
||||
this(new FileInputStream(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint document from an input stream. Parses the
|
||||
* document and places all the important stuff into data structures.
|
||||
*
|
||||
* @param inputStream the source of the data
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public HSLFSlideShow(InputStream inputStream) throws IOException
|
||||
{
|
||||
//do Ole stuff
|
||||
this(new POIFSFileSystem(inputStream));
|
||||
istream = inputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint document from a POIFS Filesystem. Parses the
|
||||
* document and places all the important stuff into data structures.
|
||||
*
|
||||
* @param filesystem the POIFS FileSystem to read from
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public HSLFSlideShow(POIFSFileSystem filesystem) throws IOException
|
||||
{
|
||||
this.filesystem = filesystem;
|
||||
|
||||
// Go find a PowerPoint document in the stream
|
||||
// Save anything useful we come across
|
||||
readFIB();
|
||||
|
||||
// Look for Property Streams:
|
||||
readProperties();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shuts things down. Closes underlying streams etc
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
if(istream != null) {
|
||||
istream.close();
|
||||
}
|
||||
filesystem = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts the main document stream from the POI file then hands off
|
||||
* to other functions that parse other areas.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void readFIB() throws IOException
|
||||
{
|
||||
// Get the main document stream
|
||||
DocumentEntry docProps =
|
||||
(DocumentEntry)filesystem.getRoot().getEntry("PowerPoint Document");
|
||||
|
||||
// Grab the document stream
|
||||
_docstream = new byte[docProps.getSize()];
|
||||
filesystem.createDocumentInputStream("PowerPoint Document").read(_docstream);
|
||||
|
||||
// The format of records in a powerpoint file are:
|
||||
// <little endian 2 byte "info">
|
||||
// <little endian 2 byte "type">
|
||||
// <little endian 4 byte "length">
|
||||
// If it has a zero length, following it will be another record
|
||||
// <xx xx yy yy 00 00 00 00> <xx xx yy yy zz zz zz zz>
|
||||
// If it has a length, depending on its type it may have children or data
|
||||
// If it has children, these will follow straight away
|
||||
// <xx xx yy yy zz zz zz zz <xx xx yy yy zz zz zz zz>>
|
||||
// If it has data, this will come straigh after, and run for the length
|
||||
// <xx xx yy yy zz zz zz zz dd dd dd dd dd dd dd>
|
||||
// All lengths given exclude the 8 byte record header
|
||||
// (Data records are known as Atoms)
|
||||
|
||||
// Document should start with:
|
||||
// 0F 00 E8 03 ## ## ## ##
|
||||
// (type 1000 = document, info 00 0f is normal, rest is document length)
|
||||
// 01 00 E9 03 28 00 00 00
|
||||
// (type 1001 = document atom, info 00 01 normal, 28 bytes long)
|
||||
// 80 16 00 00 E0 10 00 00 xx xx xx xx xx xx xx xx
|
||||
// 05 00 00 00 0A 00 00 00 xx xx xx
|
||||
// (the contents of the document atom, not sure what it means yet)
|
||||
// (records then follow)
|
||||
|
||||
// When parsing a document, look to see if you know about that type
|
||||
// of the current record. If you know it's a type that has children,
|
||||
// process the record's data area looking for more records
|
||||
// If you know about the type and it doesn't have children, either do
|
||||
// something with the data (eg TextRun) or skip over it
|
||||
// If you don't know about the type, play safe and skip over it (using
|
||||
// its length to know where the next record will start)
|
||||
//
|
||||
// For now, this work is handled by Record.findChildRecords
|
||||
|
||||
_records = Record.findChildRecords(_docstream,0,_docstream.length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the properties from the filesystem, and load them
|
||||
*/
|
||||
public void readProperties() {
|
||||
// DocumentSummaryInformation
|
||||
dsInf = (DocumentSummaryInformation)getPropertySet("\005DocumentSummaryInformation");
|
||||
|
||||
// SummaryInformation
|
||||
sInf = (SummaryInformation)getPropertySet("\005SummaryInformation");
|
||||
|
||||
// Current User
|
||||
try {
|
||||
currentUser = new CurrentUserAtom(filesystem);
|
||||
} catch(IOException ie) {
|
||||
System.err.println("Error finding Current User Atom:\n" + ie);
|
||||
currentUser = new CurrentUserAtom();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For a given named property entry, either return it or null if
|
||||
* if it wasn't found
|
||||
*/
|
||||
public PropertySet getPropertySet(String setName) {
|
||||
DocumentInputStream dis;
|
||||
try {
|
||||
// Find the entry, and get an input stream for it
|
||||
dis = filesystem.createDocumentInputStream(setName);
|
||||
} catch(IOException ie) {
|
||||
// Oh well, doesn't exist
|
||||
System.err.println("Error getting property set with name " + setName + "\n" + ie);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Create the Property Set
|
||||
PropertySet set = PropertySetFactory.create(dis);
|
||||
return set;
|
||||
} catch(IOException ie) {
|
||||
// Must be corrupt or something like that
|
||||
System.err.println("Error creating property set with name " + setName + "\n" + ie);
|
||||
} catch(org.apache.poi.hpsf.HPSFException he) {
|
||||
// Oh well, doesn't exist
|
||||
System.err.println("Error creating property set with name " + setName + "\n" + he);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out the slideshow file the is represented by an instance of
|
||||
* this class
|
||||
* @param out The OutputStream to write to.
|
||||
* @throws IOException If there is an unexpected IOException from the passed
|
||||
* in OutputStream
|
||||
*/
|
||||
public void write(OutputStream out) throws IOException {
|
||||
// Get a new Filesystem to write into
|
||||
POIFSFileSystem outFS = new POIFSFileSystem();
|
||||
|
||||
// Write out the Property Streams
|
||||
if(sInf != null) {
|
||||
writePropertySet("\005SummaryInformation",sInf,outFS);
|
||||
}
|
||||
if(dsInf != null) {
|
||||
writePropertySet("\005DocumentSummaryInformation",dsInf,outFS);
|
||||
}
|
||||
|
||||
// Need to take special care of PersistPtrHolder and UserEditAtoms
|
||||
// Store where they used to be, and where they are now
|
||||
Hashtable persistPtrHolderPos = new Hashtable();
|
||||
Hashtable userEditAtomsPos = new Hashtable();
|
||||
int lastUserEditAtomPos = -1;
|
||||
|
||||
// Write ourselves out
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for(int i=0; i<_records.length; i++) {
|
||||
// If it's a special record, record where it was and now is
|
||||
if(_records[i] instanceof PersistPtrHolder) {
|
||||
// Update position
|
||||
PersistPtrHolder pph = (PersistPtrHolder)_records[i];
|
||||
int oldPos = pph.getLastOnDiskOffset();
|
||||
int newPos = baos.size();
|
||||
pph.setLastOnDiskOffet(newPos);
|
||||
persistPtrHolderPos.put(new Integer(oldPos),new Integer(newPos));
|
||||
}
|
||||
if(_records[i] instanceof UserEditAtom) {
|
||||
// Update position
|
||||
UserEditAtom uea = (UserEditAtom)_records[i];
|
||||
int oldPos = uea.getLastOnDiskOffset();
|
||||
int newPos = baos.size();
|
||||
lastUserEditAtomPos = newPos;
|
||||
uea.setLastOnDiskOffet(newPos);
|
||||
userEditAtomsPos.put(new Integer(oldPos),new Integer(newPos));
|
||||
|
||||
// Update internal positions
|
||||
if(uea.getLastUserEditAtomOffset() != 0) {
|
||||
Integer ueNewPos = (Integer)userEditAtomsPos.get( new Integer( uea.getLastUserEditAtomOffset() ) );
|
||||
uea.setLastUserEditAtomOffset(ueNewPos.intValue());
|
||||
}
|
||||
if(uea.getPersistPointersOffset() != 0) {
|
||||
Integer ppNewPos = (Integer)persistPtrHolderPos.get( new Integer( uea.getPersistPointersOffset() ) );
|
||||
uea.setPersistPointersOffset(ppNewPos.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, write out
|
||||
_records[i].writeOut(baos);
|
||||
}
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
outFS.createDocument(bais,"PowerPoint Document");
|
||||
|
||||
// Update and write out the Current User atom
|
||||
if(lastUserEditAtomPos != -1) {
|
||||
currentUser.setCurrentEditOffset(lastUserEditAtomPos);
|
||||
}
|
||||
currentUser.writeToFS(outFS);
|
||||
|
||||
// Send the POIFSFileSystem object out
|
||||
outFS.writeFilesystem(out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out a given ProperySet
|
||||
*/
|
||||
private void writePropertySet(String name, PropertySet set, POIFSFileSystem fs) throws IOException {
|
||||
try {
|
||||
MutablePropertySet mSet = new MutablePropertySet(set);
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
mSet.write(bOut);
|
||||
byte[] data = bOut.toByteArray();
|
||||
ByteArrayInputStream bIn = new ByteArrayInputStream(data);
|
||||
fs.createDocument(bIn,name);
|
||||
System.out.println("Wrote property set " + name + " of size " + data.length);
|
||||
} catch(org.apache.poi.hpsf.WritingNotSupportedException wnse) {
|
||||
System.err.println("Couldn't write property set with name " + name + " as not supported by HPSF yet");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ******************* fetching methods follow ********************* */
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of all the records found in the slideshow
|
||||
*/
|
||||
public Record[] getRecords() { return _records; }
|
||||
|
||||
/**
|
||||
* Returns an array of the bytes of the file. Only correct after a
|
||||
* call to open or write - at all other times might be wrong!
|
||||
*/
|
||||
public byte[] getUnderlyingBytes() { return _docstream; }
|
||||
|
||||
/**
|
||||
* Fetch the Document Summary Information of the document
|
||||
*/
|
||||
public DocumentSummaryInformation getDocumentSummaryInformation() { return dsInf; }
|
||||
|
||||
/**
|
||||
* Fetch the Summary Information of the document
|
||||
*/
|
||||
public SummaryInformation getSummaryInformation() { return sInf; }
|
||||
|
||||
/**
|
||||
* Fetch the Current User Atom of the document
|
||||
*/
|
||||
public CurrentUserAtom getCurrentUserAtom() { return currentUser; }
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.dev;
|
||||
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.usermodel.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Uses record level code to locate PPDrawing entries.
|
||||
* Having found them, it sees if they have DDF Textbox records, and if so,
|
||||
* searches those for text. Prints out any text it finds
|
||||
*/
|
||||
public class PPDrawingTextListing {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length < 1) {
|
||||
System.err.println("Need to give a filename");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
HSLFSlideShow ss = new HSLFSlideShow(args[0]);
|
||||
|
||||
// Find PPDrawings at any second level position
|
||||
Record[] records = ss.getRecords();
|
||||
for(int i=0; i<records.length; i++) {
|
||||
Record[] children = records[i].getChildRecords();
|
||||
if(children != null && children.length != 0) {
|
||||
for(int j=0; j<children.length; j++) {
|
||||
if(children[j] instanceof PPDrawing) {
|
||||
System.out.println("Found PPDrawing at " + j + " in top level record " + i + " (" + records[i].getRecordType() + ")" );
|
||||
|
||||
// Look for EscherTextboxWrapper's
|
||||
PPDrawing ppd = (PPDrawing)children[j];
|
||||
EscherTextboxWrapper[] wrappers = ppd.getTextboxWrappers();
|
||||
System.out.println(" Has " + wrappers.length + " textbox wrappers within");
|
||||
|
||||
// Loop over the wrappers, showing what they contain
|
||||
for(int k=0; k<wrappers.length; k++) {
|
||||
EscherTextboxWrapper tbw = wrappers[k];
|
||||
System.out.println(" " + k + " has " + tbw.getChildRecords().length + " PPT atoms within");
|
||||
|
||||
// Loop over the records, printing the text
|
||||
Record[] pptatoms = tbw.getChildRecords();
|
||||
for(int l=0; l<pptatoms.length; l++) {
|
||||
String text = null;
|
||||
if(pptatoms[l] instanceof TextBytesAtom) {
|
||||
TextBytesAtom tba = (TextBytesAtom)pptatoms[l];
|
||||
text = tba.getText();
|
||||
}
|
||||
if(pptatoms[l] instanceof TextCharsAtom) {
|
||||
TextCharsAtom tca = (TextCharsAtom)pptatoms[l];
|
||||
text = tca.getText();
|
||||
}
|
||||
|
||||
if(text != null) {
|
||||
text = text.replace('\r','\n');
|
||||
System.out.println(" ''" + text + "''");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.dev;
|
||||
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.usermodel.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Uses record level code to locate SlideListWithText entries.
|
||||
* Having found them, it sees if they have any text, and prints out
|
||||
* what it finds.
|
||||
*/
|
||||
public class SLWTTextListing {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length < 1) {
|
||||
System.err.println("Need to give a filename");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
HSLFSlideShow ss = new HSLFSlideShow(args[0]);
|
||||
|
||||
// Find the documents, and then their SLWT
|
||||
Record[] records = ss.getRecords();
|
||||
for(int i=0; i<records.length; i++) {
|
||||
if(records[i].getRecordType() == 1000l) {
|
||||
Record docRecord = records[i];
|
||||
Record[] docChildren = docRecord.getChildRecords();
|
||||
for(int j=0; j<docChildren.length; j++) {
|
||||
if(docChildren[j] instanceof SlideListWithText) {
|
||||
System.out.println("Found SLWT in document at " + i);
|
||||
System.out.println(" Has " + docChildren[j].getChildRecords().length + " children");
|
||||
|
||||
// Grab the SlideAtomSet's, which contain
|
||||
// a SlidePersistAtom and then a bunch of text
|
||||
// + related records
|
||||
SlideListWithText slwt = (SlideListWithText)docChildren[j];
|
||||
SlideListWithText.SlideAtomsSet[] thisSets = slwt.getSlideAtomsSets();
|
||||
System.out.println(" Has " + thisSets.length + " AtomSets in it");
|
||||
|
||||
// Loop over the sets, showing what they contain
|
||||
for(int k=0; k<thisSets.length; k++) {
|
||||
SlidePersistAtom spa = thisSets[k].getSlidePersistAtom();
|
||||
System.out.println(" " + k + " has slide id " + spa.getSlideIdentifier() );
|
||||
System.out.println(" " + k + " has ref id " + spa.getRefID() );
|
||||
|
||||
// Loop over the records, printing the text
|
||||
Record[] slwtc = thisSets[k].getSlideRecords();
|
||||
for(int l=0; l<slwtc.length; l++) {
|
||||
String text = null;
|
||||
if(slwtc[l] instanceof TextBytesAtom) {
|
||||
TextBytesAtom tba = (TextBytesAtom)slwtc[l];
|
||||
text = tba.getText();
|
||||
}
|
||||
if(slwtc[l] instanceof TextCharsAtom) {
|
||||
TextCharsAtom tca = (TextCharsAtom)slwtc[l];
|
||||
text = tca.getText();
|
||||
}
|
||||
|
||||
if(text != null) {
|
||||
text = text.replace('\r','\n');
|
||||
System.out.println(" ''" + text + "''");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.dev;
|
||||
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Uses record level code to locate Notes and Slide records.
|
||||
* Having found them, it asks their SlideAtom or NotesAtom entries
|
||||
* what they are all about. Useful for checking the matching between
|
||||
* Slides, Master Slides and Notes
|
||||
*/
|
||||
public class SlideAndNotesAtomListing {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length < 1) {
|
||||
System.err.println("Need to give a filename");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
HSLFSlideShow ss = new HSLFSlideShow(args[0]);
|
||||
System.out.println("");
|
||||
|
||||
// Find either Slides or Notes
|
||||
Record[] records = ss.getRecords();
|
||||
for(int i=0; i<records.length; i++) {
|
||||
Record r = records[i];
|
||||
|
||||
// When we find them, print out their IDs
|
||||
if(r instanceof Slide) {
|
||||
Slide s = (Slide)r;
|
||||
SlideAtom sa = s.getSlideAtom();
|
||||
System.out.println("Found Slide at " + i);
|
||||
System.out.println(" Slide's master ID is " + sa.getMasterID());
|
||||
System.out.println(" Slide's notes ID is " + sa.getNotesID());
|
||||
System.out.println("");
|
||||
}
|
||||
if(r instanceof Notes) {
|
||||
Notes n = (Notes)r;
|
||||
NotesAtom na = n.getNotesAtom();
|
||||
System.out.println("Found Notes at " + i);
|
||||
System.out.println(" Notes ID is " + na.getSlideID());
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.dev;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* This class provides a way to view the contents of a powerpoint file.
|
||||
* It will use the recored layer to grok the contents of the file, and
|
||||
* will print out what it finds.
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class SlideShowRecordDumper
|
||||
{
|
||||
private HSLFSlideShow doc;
|
||||
|
||||
/**
|
||||
* right now this function takes one parameter: a ppt file, and outputs
|
||||
* a dump of what it contains
|
||||
*/
|
||||
public static void main(String args[]) throws IOException
|
||||
{
|
||||
if(args.length == 0) {
|
||||
System.err.println("Useage: SlideShowDumper <filename>");
|
||||
return;
|
||||
}
|
||||
|
||||
String filename = args[0];
|
||||
|
||||
SlideShowRecordDumper foo = new SlideShowRecordDumper(filename);
|
||||
|
||||
foo.printDump();
|
||||
foo.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint dump from fileName. Parses the document
|
||||
* and dumps out the contents
|
||||
*
|
||||
* @param fileName The name of the file to read.
|
||||
* @throws IOException if there is a problem while parsing the document.
|
||||
*/
|
||||
public SlideShowRecordDumper(String fileName) throws IOException
|
||||
{
|
||||
doc = new HSLFSlideShow(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts things down. Closes underlying streams etc
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
if(doc != null) {
|
||||
doc.close();
|
||||
}
|
||||
doc = null;
|
||||
}
|
||||
|
||||
|
||||
public void printDump() throws IOException {
|
||||
// Prints out the records in the tree
|
||||
walkTree(0,0,doc.getRecords());
|
||||
}
|
||||
|
||||
public String makeHex(int number, int padding) {
|
||||
String hex = Integer.toHexString(number).toUpperCase();
|
||||
while(hex.length() < padding) {
|
||||
hex = "0" + hex;
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
public String reverseHex(String s) {
|
||||
StringBuffer ret = new StringBuffer();
|
||||
|
||||
// Get to a multiple of two
|
||||
if((s.length() / 2) * 2 != s.length()) { s = "0" + s; }
|
||||
|
||||
// Break up into blocks
|
||||
char[] c = s.toCharArray();
|
||||
for(int i=c.length; i>0; i-=2) {
|
||||
ret.append(c[i-2]);
|
||||
ret.append(c[i-1]);
|
||||
if(i != 2) { ret.append(' '); }
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
public int getDiskLen(Record r) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
r.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
return b.length;
|
||||
}
|
||||
|
||||
|
||||
public void walkTree(int depth, int pos, Record[] records) throws IOException {
|
||||
int indent = depth;
|
||||
String ind = "";
|
||||
for(int i=0; i<indent; i++) { ind += " "; }
|
||||
|
||||
for(int i=0; i<records.length; i++) {
|
||||
Record r = records[i];
|
||||
|
||||
// Figure out how big it is
|
||||
int len = getDiskLen(r);
|
||||
|
||||
// Grab the type as hex
|
||||
String hexType = makeHex((int)r.getRecordType(),4);
|
||||
String rHexType = reverseHex(hexType);
|
||||
|
||||
// Grab the hslf.record type
|
||||
Class c = r.getClass();
|
||||
String cname = c.toString();
|
||||
if(cname.startsWith("class ")) {
|
||||
cname = cname.substring(6);
|
||||
}
|
||||
if(cname.startsWith("org.apache.poi.hslf.record.")) {
|
||||
cname = cname.substring(27);
|
||||
}
|
||||
|
||||
// Display the record
|
||||
System.out.println(ind + "At position " + pos + " (" + makeHex(pos,6) + "):");
|
||||
System.out.println(ind + " Record is of type " + cname);
|
||||
System.out.println(ind + " Type is " + r.getRecordType() + " (" + hexType + " -> " + rHexType + " )");
|
||||
System.out.println(ind + " Len is " + (len-8) + " (" + makeHex((len-8),8) + "), on disk len is " + len );
|
||||
System.out.println();
|
||||
|
||||
// If it has children, show them
|
||||
if(r.getChildRecords() != null) {
|
||||
walkTree((depth+3),pos+8,r.getChildRecords());
|
||||
}
|
||||
|
||||
// Wind on the position marker
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.dev;
|
||||
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Uses record level code to locate UserEditAtom records, and other
|
||||
* persistence related atoms. Tries to match them together, to help
|
||||
* illuminate quite what all the offsets mean
|
||||
*/
|
||||
public class UserEditAndPersistListing {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length < 1) {
|
||||
System.err.println("Need to give a filename");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
HSLFSlideShow ss = new HSLFSlideShow(args[0]);
|
||||
System.out.println("");
|
||||
|
||||
// Find any persist ones first
|
||||
Record[] records = ss.getRecords();
|
||||
int pos = 0;
|
||||
for(int i=0; i<records.length; i++) {
|
||||
Record r = records[i];
|
||||
|
||||
if(r.getRecordType() == 6001l) {
|
||||
// PersistPtrFullBlock
|
||||
System.out.println("Found PersistPtrFullBlock at " + pos + " (" + Integer.toHexString(pos) + ")");
|
||||
}
|
||||
if(r.getRecordType() == 6002l) {
|
||||
// PersistPtrIncrementalBlock
|
||||
System.out.println("Found PersistPtrIncrementalBlock at " + pos + " (" + Integer.toHexString(pos) + ")");
|
||||
}
|
||||
|
||||
// Increase the position by the on disk size
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
r.writeOut(baos);
|
||||
pos += baos.size();
|
||||
}
|
||||
|
||||
System.out.println("");
|
||||
|
||||
pos = 0;
|
||||
// Now look for UserEditAtoms
|
||||
for(int i=0; i<records.length; i++) {
|
||||
Record r = records[i];
|
||||
|
||||
if(r instanceof UserEditAtom) {
|
||||
UserEditAtom uea = (UserEditAtom)r;
|
||||
System.out.println("Found UserEditAtom at " + pos + " (" + Integer.toHexString(pos) + ")");
|
||||
System.out.println(" lastUserEditAtomOffset = " + uea.getLastUserEditAtomOffset() );
|
||||
System.out.println(" persistPointersOffset = " + uea.getPersistPointersOffset() );
|
||||
System.out.println(" docPersistRef = " + uea.getDocPersistRef() );
|
||||
System.out.println(" maxPersistWritten = " + uea.getMaxPersistWritten() );
|
||||
}
|
||||
|
||||
// Increase the position by the on disk size
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
r.writeOut(baos);
|
||||
pos += baos.size();
|
||||
}
|
||||
|
||||
System.out.println("");
|
||||
|
||||
|
||||
// Query the CurrentUserAtom
|
||||
CurrentUserAtom cua = ss.getCurrentUserAtom();
|
||||
System.out.println("Checking Current User Atom");
|
||||
System.out.println(" Thinks the CurrentEditOffset is " + cua.getCurrentEditOffset());
|
||||
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.exceptions;
|
||||
|
||||
/**
|
||||
* This exception is thrown when we try to create a record, and the
|
||||
* underlying data just doesn't match up
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class InvalidRecordFormatException extends Exception
|
||||
{
|
||||
public InvalidRecordFormatException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.extractor;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashSet;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hslf.usermodel.*;
|
||||
|
||||
/**
|
||||
* This class can be used to extract text from a PowerPoint file.
|
||||
* Can optionally also get the notes from one.
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class PowerPointExtractor
|
||||
{
|
||||
private HSLFSlideShow _hslfshow;
|
||||
private SlideShow _show;
|
||||
private Slide[] _slides;
|
||||
private Notes[] _notes;
|
||||
|
||||
/**
|
||||
* Basic extractor. Returns all the text, and optionally all the notes
|
||||
*/
|
||||
public static void main(String args[]) throws IOException
|
||||
{
|
||||
if(args.length < 1) {
|
||||
System.err.println("Useage:");
|
||||
System.err.println("\tPowerPointExtractor [-notes] <file>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
boolean notes = false;
|
||||
String file;
|
||||
if(args.length > 1) {
|
||||
notes = true;
|
||||
file = args[1];
|
||||
} else {
|
||||
file = args[0];
|
||||
}
|
||||
|
||||
PowerPointExtractor ppe = new PowerPointExtractor(file);
|
||||
System.out.println(ppe.getText(true,notes));
|
||||
ppe.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PowerPointExtractor
|
||||
* @param fileName
|
||||
*/
|
||||
public PowerPointExtractor(String fileName) throws IOException {
|
||||
_hslfshow = new HSLFSlideShow(fileName);
|
||||
_show = new SlideShow(_hslfshow);
|
||||
_slides = _show.getSlides();
|
||||
_notes = _show.getNotes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PowerPointExtractor
|
||||
* @param iStream
|
||||
*/
|
||||
public PowerPointExtractor(InputStream iStream) throws IOException {
|
||||
_hslfshow = new HSLFSlideShow(iStream);
|
||||
_show = new SlideShow(_hslfshow);
|
||||
_slides = _show.getSlides();
|
||||
_notes = _show.getNotes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PowerPointExtractor
|
||||
* @param fs
|
||||
*/
|
||||
public PowerPointExtractor(POIFSFileSystem fs) throws IOException {
|
||||
_hslfshow = new HSLFSlideShow(fs);
|
||||
_show = new SlideShow(_hslfshow);
|
||||
_slides = _show.getSlides();
|
||||
_notes = _show.getNotes();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shuts down the underlying streams
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
_hslfshow.close();
|
||||
_hslfshow = null;
|
||||
_show = null;
|
||||
_slides = null;
|
||||
_notes = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches all the slide text from the slideshow, but not the notes
|
||||
*/
|
||||
public String getText() {
|
||||
return getText(true,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all the notes text from the slideshow, but not the slide text
|
||||
*/
|
||||
public String getNotes() {
|
||||
return getText(false,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches text from the slideshow, be it slide text or note text
|
||||
* @param getSlideText fetch slide text
|
||||
* @param getNoteText fetch note text
|
||||
*/
|
||||
public String getText(boolean getSlideText, boolean getNoteText) {
|
||||
StringBuffer ret = new StringBuffer();
|
||||
|
||||
if(getSlideText) {
|
||||
for(int i=0; i<_slides.length; i++) {
|
||||
Slide slide = _slides[i];
|
||||
TextRun[] runs = slide.getTextRuns();
|
||||
for(int j=0; j<runs.length; j++) {
|
||||
TextRun run = runs[j];
|
||||
String text = run.getText();
|
||||
ret.append(text);
|
||||
if(! text.endsWith("\n")) {
|
||||
ret.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(getNoteText) {
|
||||
ret.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
if(getNoteText) {
|
||||
// Not currently using _notes, as that can have the notes of
|
||||
// master sheets in. Grab Slide list, then work from there,
|
||||
// but ensure no duplicates
|
||||
HashSet seenNotes = new HashSet();
|
||||
for(int i=0; i<_slides.length; i++) {
|
||||
Notes notes = _slides[i].getNotesSheet();
|
||||
if(notes == null) { continue; }
|
||||
Integer id = new Integer(notes.getSheetNumber());
|
||||
if(seenNotes.contains(id)) { continue; }
|
||||
seenNotes.add(id);
|
||||
|
||||
TextRun[] runs = notes.getTextRuns();
|
||||
if(runs != null && runs.length > 0) {
|
||||
for(int j=0; j<runs.length; j++) {
|
||||
TextRun run = runs[j];
|
||||
String text = run.getText();
|
||||
ret.append(text);
|
||||
if(! text.endsWith("\n")) {
|
||||
ret.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.model;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.record.SlideListWithText.*;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* This class represents a slide's notes in a PowerPoint Document. It
|
||||
* allows access to the text within, and the layout. For now, it only
|
||||
* does the text side of things though
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class Notes extends Sheet
|
||||
{
|
||||
|
||||
private int _sheetNo;
|
||||
private org.apache.poi.hslf.record.Notes _notes;
|
||||
private TextRun[] _runs;
|
||||
|
||||
/**
|
||||
* Constructs a Notes Sheet from the given Notes record.
|
||||
* Initialises TextRuns, to provide easier access to the text
|
||||
*
|
||||
* @param notes the Notes record to read from
|
||||
*/
|
||||
public Notes (org.apache.poi.hslf.record.Notes notes) {
|
||||
_notes = notes;
|
||||
|
||||
// Grab the sheet number, via the NotesAtom
|
||||
_sheetNo = _notes.getNotesAtom().getSlideID();
|
||||
|
||||
// Now, build up TextRuns from pairs of TextHeaderAtom and
|
||||
// one of TextBytesAtom or TextCharsAtom, found inside
|
||||
// EscherTextboxWrapper's in the PPDrawing
|
||||
_runs = findTextRuns(_notes.getPPDrawing());
|
||||
}
|
||||
|
||||
|
||||
// Accesser methods follow
|
||||
|
||||
/**
|
||||
* Returns an array of all the TextRuns found
|
||||
*/
|
||||
public TextRun[] getTextRuns() { return _runs; }
|
||||
|
||||
/**
|
||||
* Returns the sheet number
|
||||
*/
|
||||
public int getSheetNumber() { return _sheetNo; }
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.model;
|
||||
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This class defines the common format of "Sheets" in a powerpoint
|
||||
* document. Such sheets could be Slides, Notes, Master etc
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public abstract class Sheet
|
||||
{
|
||||
/**
|
||||
* Returns an array of all the TextRuns in the sheet.
|
||||
*/
|
||||
public abstract TextRun[] getTextRuns();
|
||||
|
||||
/**
|
||||
* Returns the sheet number
|
||||
*/
|
||||
public abstract int getSheetNumber();
|
||||
|
||||
/**
|
||||
* For a given PPDrawing, grab all the TextRuns
|
||||
*/
|
||||
public static TextRun[] findTextRuns(PPDrawing ppdrawing) {
|
||||
Vector runsV = new Vector();
|
||||
EscherTextboxWrapper[] wrappers = ppdrawing.getTextboxWrappers();
|
||||
for(int i=0; i<wrappers.length; i++) {
|
||||
findTextRuns(wrappers[i].getChildRecords(),runsV);
|
||||
}
|
||||
TextRun[] runs = new TextRun[runsV.size()];
|
||||
for(int i=0; i<runs.length; i++) {
|
||||
runs[i] = (TextRun)runsV.get(i);
|
||||
}
|
||||
return runs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans through the supplied record array, looking for
|
||||
* a TextHeaderAtom followed by one of a TextBytesAtom or
|
||||
* a TextCharsAtom. Builds up TextRuns from these
|
||||
*
|
||||
* @param records the records to build from
|
||||
* @param found vector to add any found to
|
||||
*/
|
||||
protected static void findTextRuns(Record[] records, Vector found) {
|
||||
// Look for a TextHeaderAtom
|
||||
for(int i=0; i<(records.length-1); i++) {
|
||||
if(records[i] instanceof TextHeaderAtom) {
|
||||
TextRun trun = null;
|
||||
TextHeaderAtom tha = (TextHeaderAtom)records[i];
|
||||
if(records[i+1] instanceof TextCharsAtom) {
|
||||
TextCharsAtom tca = (TextCharsAtom)records[i+1];
|
||||
trun = new TextRun(tha,tca);
|
||||
} else if(records[i+1] instanceof TextBytesAtom) {
|
||||
TextBytesAtom tba = (TextBytesAtom)records[i+1];
|
||||
trun = new TextRun(tha,tba);
|
||||
} else if(records[i+1].getRecordType() == 4010l) {
|
||||
// Safe to ignore
|
||||
} else {
|
||||
System.err.println("Found a TextHeaderAtom not followed by a TextBytesAtom or TextCharsAtom: Followed by " + records[i+1].getRecordType());
|
||||
continue;
|
||||
}
|
||||
found.add(trun);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.model;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.record.SlideListWithText.*;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* This class represents a slide in a PowerPoint Document. It allows
|
||||
* access to the text within, and the layout. For now, it only does
|
||||
* the text side of things though
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class Slide extends Sheet
|
||||
{
|
||||
|
||||
private int _sheetNo;
|
||||
private org.apache.poi.hslf.record.Slide _slide;
|
||||
private SlideAtomsSet[] _atomSet;
|
||||
private TextRun[] _runs;
|
||||
private TextRun[] _otherRuns; // Any from the PPDrawing, shouldn't really be any though
|
||||
private Notes _notes;
|
||||
|
||||
/**
|
||||
* Constructs a Slide from the Slide record, and the SlideAtomsSets
|
||||
* for ones not embeded in the PPDrawing.
|
||||
* Initialises TextRuns, to provide easier access to the text
|
||||
*
|
||||
* @param slide the Slide record we're based on
|
||||
* @param atomSet the SlideAtomsSet to get the text from
|
||||
*/
|
||||
public Slide(org.apache.poi.hslf.record.Slide slide, Notes notes, SlideAtomsSet[] atomSet) {
|
||||
_slide = slide;
|
||||
_notes = notes;
|
||||
_atomSet = atomSet;
|
||||
|
||||
// Grab the sheet number
|
||||
//_sheetNo = _slide.getSlideAtom().getSheetNumber();
|
||||
_sheetNo = -1;
|
||||
|
||||
// Grab the TextRuns from the PPDrawing
|
||||
_otherRuns = findTextRuns(_slide.getPPDrawing());
|
||||
|
||||
|
||||
// Ensure we've only got only copy of each SlideAtomSet
|
||||
// When in doubt, prefere the later one
|
||||
Hashtable seenSets = new Hashtable();
|
||||
Vector useSets = new Vector();
|
||||
for(int i=0; i<_atomSet.length; i++) {
|
||||
SlideAtomsSet set = _atomSet[i];
|
||||
int id = set.getSlidePersistAtom().getRefID();
|
||||
Integer idI = new Integer(id);
|
||||
if(seenSets.containsKey(idI)) {
|
||||
// Replace old one
|
||||
Integer replacePos = (Integer)seenSets.get(idI);
|
||||
useSets.set(replacePos.intValue(),set);
|
||||
} else {
|
||||
// Use for now
|
||||
useSets.add(set);
|
||||
seenSets.put(idI,new Integer(useSets.size()-1));
|
||||
}
|
||||
}
|
||||
|
||||
// For the text coming in from the SlideAtomsSet:
|
||||
// Build up TextRuns from pairs of TextHeaderAtom and
|
||||
// one of TextBytesAtom or TextCharsAtom
|
||||
Vector runSets = new Vector();
|
||||
for(int i=0; i<useSets.size(); i++) {
|
||||
SlideAtomsSet set = (SlideAtomsSet)useSets.get(i);
|
||||
findTextRuns(set.getSlideRecords(),runSets);
|
||||
}
|
||||
// Build an array, more useful than a vector
|
||||
_runs = new TextRun[runSets.size()];
|
||||
for(int i=0; i<_runs.length; i++) {
|
||||
_runs[i] = (TextRun)runSets.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Accesser methods follow
|
||||
|
||||
/**
|
||||
* Returns an array of all the TextRuns found
|
||||
*/
|
||||
public TextRun[] getTextRuns() { return _runs; }
|
||||
|
||||
/**
|
||||
* Returns the sheet number
|
||||
*/
|
||||
public int getSheetNumber() { return _sheetNo; }
|
||||
|
||||
/**
|
||||
* Returns the Notes Sheet for this slide, or null if there isn't one
|
||||
*/
|
||||
public Notes getNotesSheet() { return _notes; }
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.model;
|
||||
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
/**
|
||||
* This class represents a run of text in a powerpoint document. That
|
||||
* run could be text on a sheet, or text in a note.
|
||||
* It is only a very basic class for now
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class TextRun
|
||||
{
|
||||
private TextHeaderAtom _headerAtom;
|
||||
private TextBytesAtom _byteAtom;
|
||||
private TextCharsAtom _charAtom;
|
||||
private boolean _isUnicode;
|
||||
|
||||
/**
|
||||
* Constructs a Text Run from a Unicode text block
|
||||
*
|
||||
* @param tha the TextHeaderAtom that defines what's what
|
||||
* @param tca the TextCharsAtom containing the text
|
||||
*/
|
||||
public TextRun(TextHeaderAtom tha, TextCharsAtom tca) {
|
||||
_headerAtom = tha;
|
||||
_charAtom = tca;
|
||||
_isUnicode = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Text Run from a Ascii text block
|
||||
*
|
||||
* @param tha the TextHeaderAtom that defines what's what
|
||||
* @param tba the TextBytesAtom containing the text
|
||||
*/
|
||||
public TextRun(TextHeaderAtom tha, TextBytesAtom tba) {
|
||||
_headerAtom = tha;
|
||||
_byteAtom = tba;
|
||||
_isUnicode = false;
|
||||
}
|
||||
|
||||
|
||||
// Accesser methods follow
|
||||
|
||||
/**
|
||||
* Returns the text content of the run, which has been made safe
|
||||
* for printing and other use.
|
||||
*/
|
||||
public String getText() {
|
||||
String rawText = getRawText();
|
||||
|
||||
// PowerPoint seems to store files with \r as the line break
|
||||
// The messes things up on everything but a Mac, so translate
|
||||
// them to \n
|
||||
String text = rawText.replace('\r','\n');
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw text content of the run. This hasn't had any
|
||||
* changes applied to it, and so is probably unlikely to print
|
||||
* out nicely.
|
||||
*/
|
||||
public String getRawText() {
|
||||
if(_isUnicode) {
|
||||
return _charAtom.getText();
|
||||
} else {
|
||||
return _byteAtom.getText();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the text. Chance are, this won't work just yet, because
|
||||
* we also need to update some other bits of the powerpoint file
|
||||
* to match the change in the Text Atom, especially byte offsets
|
||||
*/
|
||||
public void setText(String s) {
|
||||
// If size changed, warn
|
||||
if(s.length() != getText().length()) {
|
||||
System.err.println("Warning: Your powerpoint file is probably no longer readable by powerpoint, as the text run has changed size!");
|
||||
}
|
||||
|
||||
if(_isUnicode) {
|
||||
// The atom can safely convert to unicode
|
||||
_charAtom.setText(s);
|
||||
} else {
|
||||
// Will it fit in a 8 bit atom?
|
||||
boolean hasMultibyte = StringUtil.hasMultibyte(s);
|
||||
if(! hasMultibyte) {
|
||||
// Fine to go into 8 bit atom
|
||||
byte[] text = new byte[s.length()];
|
||||
StringUtil.putCompressedUnicode(s,text,0);
|
||||
_byteAtom.setText(text);
|
||||
} else {
|
||||
throw new RuntimeException("Setting of unicode text is currently only possible for Text Runs that are Unicode in the file, sorry. For now, please convert that text to us-ascii and re-try it");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the text, from the TextHeaderAtom.
|
||||
* Possible values can be seen from TextHeaderAtom
|
||||
* @see org.apache.poi.hslf.record.TextHeaderAtom
|
||||
*/
|
||||
public int getRunType() {
|
||||
return _headerAtom.getTextType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the type of the text. Values should be taken
|
||||
* from TextHeaderAtom. No checking is done to ensure you
|
||||
* set this to a valid value!
|
||||
* @see org.apache.poi.hslf.record.TextHeaderAtom
|
||||
*/
|
||||
public void setRunType(int type) {
|
||||
_headerAtom.setTextType(type);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.*;
|
||||
import org.apache.poi.poifs.filesystem.*;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
|
||||
/**
|
||||
* This is a special kind of Atom, becauase it doesn't live inside the
|
||||
* PowerPoint document. Instead, it lives in a seperate stream in the
|
||||
* document. As such, it has to be treaded specially
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class CurrentUserAtom
|
||||
{
|
||||
/** Standard Atom header */
|
||||
public static final byte[] atomHeader = new byte[] { 0, 0, -10, 15 };
|
||||
/** The Powerpoint magic numer */
|
||||
public static final byte[] magicNumber = new byte[] { 95, -64, -111, -29 };
|
||||
/** The Powerpoint 97 version, major and minor numbers */
|
||||
public static final byte[] ppt97FileVer = new byte[] { 8, 00, -13, 03, 03, 00 };
|
||||
|
||||
/** The version, major and minor numbers */
|
||||
private int docFinalVersionA;
|
||||
private int docFinalVersionB;
|
||||
private byte docMajorNo;
|
||||
private byte docMinorNo;
|
||||
|
||||
/** The Offset into the file for the current edit */
|
||||
private long currentEditOffset;
|
||||
/** The Username of the last person to edit the file */
|
||||
private String lastEditUser;
|
||||
/** The document release version */
|
||||
private long releaseVersion;
|
||||
|
||||
/** Only correct after reading in or writing out */
|
||||
private byte[] _contents;
|
||||
|
||||
|
||||
/* ********************* getter/setter follows *********************** */
|
||||
|
||||
public int getDocFinalVersionA() { return docFinalVersionA; }
|
||||
public int getDocFinalVersionB() { return docFinalVersionB; }
|
||||
public byte getDocMajorNo() { return docMajorNo; }
|
||||
public byte getDocMinorNo() { return docMinorNo; }
|
||||
|
||||
public long getReleaseVersion() { return releaseVersion; }
|
||||
public void setReleaseVersion(long rv) { releaseVersion = rv; }
|
||||
|
||||
/** Points to the UserEditAtom */
|
||||
public long getCurrentEditOffset() { return currentEditOffset; }
|
||||
public void setCurrentEditOffset(long id ) { currentEditOffset = id; }
|
||||
|
||||
public String getLastEditUsername() { return lastEditUser; }
|
||||
public void setLastEditUsername(String u) { lastEditUser = u; }
|
||||
|
||||
|
||||
/* ********************* real code follows *************************** */
|
||||
|
||||
/**
|
||||
* Create a new Current User Atom
|
||||
*/
|
||||
public CurrentUserAtom() {
|
||||
_contents = new byte[0];
|
||||
throw new RuntimeException("Creation support for Current User Atom not complete");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the Current User in the filesystem, and create from that
|
||||
*/
|
||||
public CurrentUserAtom(POIFSFileSystem fs) throws IOException {
|
||||
// Decide how big it is
|
||||
DocumentEntry docProps =
|
||||
(DocumentEntry)fs.getRoot().getEntry("Current User");
|
||||
_contents = new byte[docProps.getSize()];
|
||||
|
||||
// Grab the contents
|
||||
InputStream in = fs.createDocumentInputStream("Current User");
|
||||
in.read(_contents);
|
||||
|
||||
// Set everything up
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create things from the bytes
|
||||
*/
|
||||
public CurrentUserAtom(byte[] b) {
|
||||
_contents = b;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually do the creation from a block of bytes
|
||||
*/
|
||||
private void init() {
|
||||
// Grab the edit offset
|
||||
currentEditOffset = LittleEndian.getUInt(_contents,16);
|
||||
|
||||
// Grab the versions
|
||||
docFinalVersionA = LittleEndian.getUShort(_contents,20);
|
||||
docFinalVersionB = LittleEndian.getUShort(_contents,22);
|
||||
docMajorNo = _contents[24];
|
||||
docMinorNo = _contents[25];
|
||||
|
||||
// Get the username length
|
||||
long usernameLen = LittleEndian.getUShort(_contents,20);
|
||||
|
||||
// Use this to grab the revision
|
||||
releaseVersion = LittleEndian.getUInt(_contents,28+(int)usernameLen);
|
||||
|
||||
// Grab the unicode username, if stored
|
||||
int start = 28+(int)usernameLen+4;
|
||||
int len = 2*(int)usernameLen;
|
||||
|
||||
if(_contents.length >= start+len) {
|
||||
byte[] textBytes = new byte[len];
|
||||
System.arraycopy(_contents,start,textBytes,0,len);
|
||||
lastEditUser = StringUtil.getFromUnicodeLE(textBytes);
|
||||
} else {
|
||||
// Fake from the 8 bit version
|
||||
byte[] textBytes = new byte[(int)usernameLen];
|
||||
System.arraycopy(_contents,28,textBytes,0,(int)usernameLen);
|
||||
lastEditUser = StringUtil.getFromCompressedUnicode(textBytes,0,(int)usernameLen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes ourselves back out
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
// Decide on the size
|
||||
// 8 = atom header
|
||||
// 20 = up to name
|
||||
// 4 = revision
|
||||
// 3 * len = ascii + unicode
|
||||
int size = 8 + 20 + 4 + (3 * lastEditUser.length());
|
||||
_contents = new byte[size];
|
||||
|
||||
// First we have a 8 byte atom header
|
||||
System.arraycopy(atomHeader,0,_contents,0,4);
|
||||
// Size is 20+user len + revision len(4)
|
||||
int atomSize = 20+4+lastEditUser.length();
|
||||
LittleEndian.putInt(_contents,4,atomSize);
|
||||
|
||||
// Now we have the size of the details, which is 20
|
||||
LittleEndian.putInt(_contents,8,20);
|
||||
|
||||
// Now the ppt magic number (4 bytes)
|
||||
System.arraycopy(magicNumber,0,_contents,12,4);
|
||||
|
||||
// Now the current edit offset
|
||||
LittleEndian.putInt(_contents,16,(int)currentEditOffset);
|
||||
|
||||
// Now the file versions, 2+2+1+1
|
||||
LittleEndian.putShort(_contents,20,(short)docFinalVersionA);
|
||||
LittleEndian.putShort(_contents,22,(short)docFinalVersionB);
|
||||
_contents[24] = docMajorNo;
|
||||
_contents[25] = docMinorNo;
|
||||
|
||||
// 2 bytes blank
|
||||
_contents[26] = 0;
|
||||
_contents[27] = 0;
|
||||
|
||||
// username in bytes in us ascii
|
||||
byte[] asciiUN = new byte[lastEditUser.length()];
|
||||
StringUtil.putCompressedUnicode(lastEditUser,asciiUN,0);
|
||||
System.arraycopy(asciiUN,0,_contents,28,asciiUN.length);
|
||||
|
||||
// 4 byte release version
|
||||
LittleEndian.putInt(_contents,28+asciiUN.length,(int)releaseVersion);
|
||||
|
||||
// username in unicode
|
||||
byte [] ucUN = new byte[lastEditUser.length()*2];
|
||||
StringUtil.putUnicodeLE(lastEditUser,ucUN,0);
|
||||
System.arraycopy(ucUN,0,_contents,28+asciiUN.length+4,ucUN.length);
|
||||
|
||||
// Write out
|
||||
out.write(_contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes ourselves back out to a filesystem
|
||||
*/
|
||||
public void writeToFS(POIFSFileSystem fs) throws IOException {
|
||||
// Grab contents
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
writeOut(baos);
|
||||
ByteArrayInputStream bais =
|
||||
new ByteArrayInputStream(baos.toByteArray());
|
||||
|
||||
// Write out
|
||||
fs.createDocument(bais,"Current User");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* If we come across a record we know has children of (potential)
|
||||
* interest, but where the record itself is boring, we create one
|
||||
* of these. It allows us to get at the children, but not much else
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class DummyRecordWithChildren extends RecordContainer
|
||||
{
|
||||
private Record[] _children;
|
||||
private byte[] _header;
|
||||
private long _type;
|
||||
|
||||
/**
|
||||
* Create a new holder for a boring record with children
|
||||
*/
|
||||
protected DummyRecordWithChildren(byte[] source, int start, int len) {
|
||||
// Just grab the header, not the whole contents
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
_type = LittleEndian.getUShort(_header,2);
|
||||
|
||||
// Find our children
|
||||
_children = Record.findChildRecords(source,start+8,len-8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value we were given at creation
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* Return any children
|
||||
*/
|
||||
public Record[] getChildRecords() { return _children; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
writeOut(_header[0],_header[1],_type,_children,out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.ddf.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* A wrapper around a DDF (Escher) EscherTextbox Record. Causes the DDF
|
||||
* Record to be accessible as if it were a HSLF record.
|
||||
* Note: when asked to write out, will simply put any child records correctly
|
||||
* into the Escher layer. A call to the escher layer to write out (by the
|
||||
* parent PPDrawing) will do the actual write out
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class EscherTextboxWrapper extends RecordContainer
|
||||
{
|
||||
private EscherTextboxRecord _escherRecord;
|
||||
private Record[] _children;
|
||||
private long _type;
|
||||
|
||||
/**
|
||||
* Returns the underlying DDF Escher Record
|
||||
*/
|
||||
public EscherTextboxRecord getEscherRecord() { return _escherRecord; }
|
||||
|
||||
/**
|
||||
* Creates the wrapper for the given DDF Escher Record and children
|
||||
*/
|
||||
protected EscherTextboxWrapper(EscherTextboxRecord textbox) {
|
||||
_escherRecord = textbox;
|
||||
_type = (long)_escherRecord.getRecordId();
|
||||
|
||||
// Find the child records in the escher data
|
||||
byte[] data = _escherRecord.getData();
|
||||
_children = Record.findChildRecords(data,0,data.length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the type of the escher record (normally in the 0xFnnn range)
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* Return any children
|
||||
*/
|
||||
public Record[] getChildRecords() { return _children; }
|
||||
|
||||
/**
|
||||
* Stores the data for the child records back into the Escher layer.
|
||||
* Doesn't actually do the writing out, that's left to the Escher
|
||||
* layer to do. Must be called before writeOut/serialize is called
|
||||
* on the underlying Escher object!
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
// Write out our children, and stuff them into the Escher layer
|
||||
|
||||
// Grab the children's data
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for(int i=0; i<_children.length; i++) {
|
||||
_children[i].writeOut(baos);
|
||||
}
|
||||
byte[] data = baos.toByteArray();
|
||||
|
||||
// Save in the escher layer
|
||||
_escherRecord.setData(data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Master container for Notes. There is one of these for every page of
|
||||
* notes, and they have certain specific children
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class Notes extends RecordContainer
|
||||
{
|
||||
private Record[] _children;
|
||||
private byte[] _header;
|
||||
private static long _type = 1008l;
|
||||
|
||||
// Links to our more interesting children
|
||||
private NotesAtom notesAtom;
|
||||
private PPDrawing ppDrawing;
|
||||
|
||||
/**
|
||||
* Returns the NotesAtom of this Notes
|
||||
*/
|
||||
public NotesAtom getNotesAtom() { return notesAtom; }
|
||||
/**
|
||||
* Returns the PPDrawing of this Notes, which has all the
|
||||
* interesting data in it
|
||||
*/
|
||||
public PPDrawing getPPDrawing() { return ppDrawing; }
|
||||
|
||||
|
||||
/**
|
||||
* Set things up, and find our more interesting children
|
||||
*/
|
||||
protected Notes(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);
|
||||
|
||||
// Find the interesting ones in there
|
||||
for(int i=0; i<_children.length; i++) {
|
||||
if(_children[i] instanceof NotesAtom) {
|
||||
notesAtom = (NotesAtom)_children[i];
|
||||
//System.out.println("Found notes for sheet " + notesAtom.getSlideID());
|
||||
}
|
||||
if(_children[i] instanceof PPDrawing) {
|
||||
ppDrawing = (PPDrawing)_children[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* We are of type 1008
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* Return any children
|
||||
*/
|
||||
public Record[] getChildRecords() { return _children; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
writeOut(_header[0],_header[1],_type,_children,out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A Notes Atom (type 1009). Holds information on the parent Notes, such
|
||||
* as what slide it is tied to
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class NotesAtom extends RecordAtom
|
||||
{
|
||||
private byte[] _header;
|
||||
private static long _type = 1009l;
|
||||
|
||||
private int slideID;
|
||||
private boolean followMasterObjects;
|
||||
private boolean followMasterScheme;
|
||||
private boolean followMasterBackground;
|
||||
private byte[] reserved;
|
||||
|
||||
|
||||
public int getSlideID() { return slideID; }
|
||||
public void setSlideID(int id) { slideID = id; }
|
||||
|
||||
public boolean getFollowMasterObjects() { return followMasterObjects; }
|
||||
public boolean getFollowMasterScheme() { return followMasterScheme; }
|
||||
public boolean getFollowMasterBackground() { return followMasterBackground; }
|
||||
public void setFollowMasterObjects(boolean flag) { followMasterObjects = flag; }
|
||||
public void setFollowMasterScheme(boolean flag) { followMasterScheme = flag; }
|
||||
public void setFollowMasterBackground(boolean flag) { followMasterBackground = flag; }
|
||||
|
||||
|
||||
/* *************** record code follows ********************** */
|
||||
|
||||
/**
|
||||
* For the Notes Atom
|
||||
*/
|
||||
protected NotesAtom(byte[] source, int start, int len) {
|
||||
// Sanity Checking
|
||||
if(len < 8) { len = 8; }
|
||||
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Get the slide ID
|
||||
slideID = (int)LittleEndian.getInt(source,start+8);
|
||||
|
||||
// Grok the flags, stored as bits
|
||||
int flags = LittleEndian.getUShort(source,start+12);
|
||||
if((flags&4) == 4) {
|
||||
followMasterBackground = true;
|
||||
} else {
|
||||
followMasterBackground = false;
|
||||
}
|
||||
if((flags&2) == 2) {
|
||||
followMasterScheme = true;
|
||||
} else {
|
||||
followMasterScheme = false;
|
||||
}
|
||||
if((flags&1) == 1) {
|
||||
followMasterObjects = true;
|
||||
} else {
|
||||
followMasterObjects = false;
|
||||
}
|
||||
|
||||
// There might be 2 more bytes, which are a reserved field
|
||||
reserved = new byte[len-14];
|
||||
System.arraycopy(source,start+14,reserved,0,reserved.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are of type 1009
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
// Header
|
||||
out.write(_header);
|
||||
|
||||
// Slide ID
|
||||
writeLittleEndian(slideID,out);
|
||||
|
||||
// Flags
|
||||
short flags = 0;
|
||||
if(followMasterObjects) { flags += 1; }
|
||||
if(followMasterScheme) { flags += 2; }
|
||||
if(followMasterBackground) { flags += 4; }
|
||||
writeLittleEndian(flags,out);
|
||||
|
||||
// Reserved fields
|
||||
out.write(reserved);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
|
||||
import org.apache.poi.ddf.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* These are actually wrappers onto Escher drawings. Make use of
|
||||
* the DDF classes to do useful things with them.
|
||||
* For now, creates a tree of the Escher records, and then creates any
|
||||
* PowerPoint (hslf) records found within the EscherTextboxRecord
|
||||
* (msofbtClientTextbox) records.
|
||||
* Also provides easy access to the EscherTextboxRecords, so that their
|
||||
* text may be extracted and used in Sheets
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
// For now, pretending to be an atom. Might not always be, but that
|
||||
// would require a wrapping class
|
||||
public class PPDrawing extends RecordAtom
|
||||
{
|
||||
private byte[] _header;
|
||||
private long _type;
|
||||
|
||||
private EscherRecord[] childRecords;
|
||||
private EscherTextboxWrapper[] textboxWrappers;
|
||||
|
||||
|
||||
/**
|
||||
* Get access to the underlying Escher Records
|
||||
*/
|
||||
public EscherRecord[] getEscherRecords() { return childRecords; }
|
||||
|
||||
/**
|
||||
* Get access to the atoms inside Textboxes
|
||||
*/
|
||||
public EscherTextboxWrapper[] getTextboxWrappers() { return textboxWrappers; }
|
||||
|
||||
|
||||
/* ******************** record stuff follows ********************** */
|
||||
|
||||
/**
|
||||
* Sets everything up, groks the escher etc
|
||||
*/
|
||||
protected PPDrawing(byte[] source, int start, int len) {
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Get the type
|
||||
_type = LittleEndian.getUShort(_header,2);
|
||||
|
||||
// Get the contents for now
|
||||
byte[] contents = new byte[len];
|
||||
System.arraycopy(source,start,contents,0,len);
|
||||
|
||||
|
||||
// Build up a tree of Escher records contained within
|
||||
DefaultEscherRecordFactory erf = new DefaultEscherRecordFactory();
|
||||
Vector escherChildren = new Vector();
|
||||
findEscherChildren(erf,contents,8,len-8,escherChildren);
|
||||
|
||||
childRecords = new EscherRecord[escherChildren.size()];
|
||||
for(int i=0; i<childRecords.length; i++) {
|
||||
childRecords[i] = (EscherRecord)escherChildren.get(i);
|
||||
}
|
||||
|
||||
// Find and EscherTextboxRecord's, and wrap them up
|
||||
Vector textboxes = new Vector();
|
||||
findEscherTextboxRecord(childRecords, textboxes);
|
||||
textboxWrappers = new EscherTextboxWrapper[textboxes.size()];
|
||||
for(int i=0; i<textboxWrappers.length; i++) {
|
||||
textboxWrappers[i] = (EscherTextboxWrapper)textboxes.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tree walking way of finding Escher Child Records
|
||||
*/
|
||||
private void findEscherChildren(DefaultEscherRecordFactory erf, byte[] source, int startPos, int lenToGo, Vector found) {
|
||||
// Find the record
|
||||
EscherRecord r = erf.createRecord(source,startPos);
|
||||
// Fill it in
|
||||
r.fillFields( source, startPos, erf );
|
||||
// Save it
|
||||
found.add(r);
|
||||
|
||||
// Wind on
|
||||
int size = r.getRecordSize();
|
||||
if(size < 8) {
|
||||
System.err.println("Hit short DDF record at " + startPos + " - " + size);
|
||||
}
|
||||
startPos += size;
|
||||
lenToGo -= size;
|
||||
if(lenToGo >= 8) {
|
||||
findEscherChildren(erf, source, startPos, lenToGo, found);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for EscherTextboxRecords
|
||||
*/
|
||||
private void findEscherTextboxRecord(EscherRecord[] toSearch, Vector found) {
|
||||
for(int i=0; i<toSearch.length; i++) {
|
||||
if(toSearch[i] instanceof EscherTextboxRecord) {
|
||||
EscherTextboxRecord tbr = (EscherTextboxRecord)toSearch[i];
|
||||
EscherTextboxWrapper w = new EscherTextboxWrapper(tbr);
|
||||
found.add(w);
|
||||
} else {
|
||||
// If it has children, walk them
|
||||
if(toSearch[i].isContainerRecord()) {
|
||||
List childrenL = toSearch[i].getChildRecords();
|
||||
EscherRecord[] children = new EscherRecord[childrenL.size()];
|
||||
for(int j=0; j< children.length; j++) {
|
||||
children[j] = (EscherRecord)childrenL.get(j);
|
||||
}
|
||||
findEscherTextboxRecord(children,found);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We are type 1036
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* We're pretending to be an atom, so return null
|
||||
*/
|
||||
public Record[] getChildRecords() { return null; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
* Walks the escher layer to get the contents
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
// Ensure the escher layer reflects the text changes
|
||||
for(int i=0; i<textboxWrappers.length; i++) {
|
||||
textboxWrappers[i].writeOut(null);
|
||||
}
|
||||
|
||||
// Find the new size of the escher children;
|
||||
int newSize = 0;
|
||||
for(int i=0; i<childRecords.length; i++) {
|
||||
newSize += childRecords[i].getRecordSize();
|
||||
}
|
||||
|
||||
// Update the size (header bytes 5-8)
|
||||
LittleEndian.putInt(_header,4,newSize);
|
||||
|
||||
// Write out our header
|
||||
out.write(_header);
|
||||
|
||||
// Now grab the children's data
|
||||
byte[] b = new byte[newSize];
|
||||
int done = 0;
|
||||
for(int i=0; i<childRecords.length; i++) {
|
||||
int written = childRecords[i].serialize( done, b );
|
||||
done += written;
|
||||
}
|
||||
|
||||
// Finally, write out the children
|
||||
out.write(b);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* General holder for PersistPtrFullBlock and PersistPtrIncrementalBlock
|
||||
* records. We need to handle them specially, since we have to go around
|
||||
* updating UserEditAtoms if they shuffle about on disk
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class PersistPtrHolder extends PositionDependentRecordAtom
|
||||
{
|
||||
private byte[] _contents;
|
||||
private long _type;
|
||||
|
||||
/**
|
||||
* Create a new holder for a PersistPtr record
|
||||
*/
|
||||
protected PersistPtrHolder(byte[] source, int start, int len) {
|
||||
// Sanity Checking - including whole header, so treat
|
||||
// length as based of 0, not 8 (including header size based)
|
||||
if(len < 4) { len = 4; }
|
||||
|
||||
// Store where we are found on disk
|
||||
myLastOnDiskOffset = start;
|
||||
|
||||
// Treat as an atom, grab and hold everything
|
||||
_contents = new byte[len];
|
||||
System.arraycopy(source,start,_contents,0,len);
|
||||
_type = LittleEndian.getUShort(_contents,2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value we were given at creation
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
out.write(_contents);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
/**
|
||||
* A special (and dangerous) kind of Record Atom that cares about where
|
||||
* it lives on the disk, or who has other Atoms that care about where
|
||||
* this is on the disk.
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public abstract class PositionDependentRecordAtom extends RecordAtom
|
||||
{
|
||||
/** Our location on the disk, as of the last write out */
|
||||
protected int myLastOnDiskOffset;
|
||||
|
||||
/** Fetch our location on the disk, as of the last write out */
|
||||
public int getLastOnDiskOffset() { return myLastOnDiskOffset; }
|
||||
|
||||
/**
|
||||
* Update the Record's idea of where on disk it lives, after a write out.
|
||||
* Use with care...
|
||||
*/
|
||||
public void setLastOnDiskOffet(int offset) {
|
||||
myLastOnDiskOffset = offset;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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 java.io.ByteArrayOutputStream;
|
||||
import java.util.Vector;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
|
||||
/**
|
||||
* This abstract class represents a record in the PowerPoint document.
|
||||
* Record classes should extend with RecordContainer or RecordAtom, which
|
||||
* extend this in turn.
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public abstract class Record
|
||||
{
|
||||
/**
|
||||
* Is this record type an Atom record (only has data),
|
||||
* or is it a non-Atom record (has other records)?
|
||||
*/
|
||||
public abstract boolean isAnAtom();
|
||||
|
||||
/**
|
||||
* Returns the type (held as a little endian in bytes 3 and 4)
|
||||
* that this class handles
|
||||
*/
|
||||
public abstract long getRecordType();
|
||||
|
||||
/**
|
||||
* Fetch all the child records of this record
|
||||
* If this record is an atom, will return null
|
||||
* If this record is a non-atom, but has no children, will return
|
||||
* an empty array
|
||||
*/
|
||||
public abstract Record[] getChildRecords();
|
||||
|
||||
/**
|
||||
* Have the contents printer out into an OutputStream, used when
|
||||
* writing a file back out to disk
|
||||
* (Normally, atom classes will keep their bytes around, but
|
||||
* non atom classes will just request the bytes from their
|
||||
* children, then chuck on their header and return)
|
||||
*/
|
||||
public abstract void writeOut(OutputStream o) throws IOException;
|
||||
|
||||
/**
|
||||
* When writing out, write out a signed int (32bit) in Little Endian format
|
||||
*/
|
||||
public static void writeLittleEndian(int i,OutputStream o) throws IOException {
|
||||
byte[] bi = new byte[4];
|
||||
LittleEndian.putInt(bi,i);
|
||||
o.write(bi);
|
||||
}
|
||||
/**
|
||||
* When writing out, write out a signed short (16bit) in Little Endian format
|
||||
*/
|
||||
public static void writeLittleEndian(short s,OutputStream o) throws IOException {
|
||||
byte[] bs = new byte[2];
|
||||
LittleEndian.putShort(bs,s);
|
||||
o.write(bs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default method for finding child records of a given record
|
||||
*/
|
||||
public static Record[] findChildRecords(byte[] b, int start, int len) {
|
||||
Vector children = new Vector(5);
|
||||
|
||||
// Jump our little way along, creating records as we go
|
||||
int pos = start;
|
||||
while(pos <= (start+len-8)) {
|
||||
long type = LittleEndian.getUShort(b,pos+2);
|
||||
long rlen = LittleEndian.getUInt(b,pos+4);
|
||||
|
||||
// Sanity check the length
|
||||
int rleni = (int)rlen;
|
||||
if(rleni < 0) { rleni = 0; }
|
||||
|
||||
//System.out.println("Found a " + type + " at pos " + pos + " (" + Integer.toHexString(pos) + "), len " + rlen);
|
||||
Record r = createRecordForType(type,b,pos,8+rleni);
|
||||
children.add(r);
|
||||
pos += 8;
|
||||
pos += rlen;
|
||||
}
|
||||
|
||||
// Turn the vector into an array, and return
|
||||
Record[] cRecords = new Record[children.size()];
|
||||
for(int i=0; i < children.size(); i++) {
|
||||
cRecords[i] = (Record)children.get(i);
|
||||
}
|
||||
return cRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given type (little endian bytes 3 and 4 in record header),
|
||||
* byte array, start position and length:
|
||||
* will return a Record object that will handle that record
|
||||
*
|
||||
* Remember that while PPT stores the record lengths as 8 bytes short
|
||||
* (not including the size of the header), this code assumes you're
|
||||
* passing in corrected lengths
|
||||
*/
|
||||
protected static Record createRecordForType(long type, byte[] b, int start, int len) {
|
||||
// Default is to use UnknownRecordPlaceholder
|
||||
// When you create classes for new Records, add them here
|
||||
switch((int)type) {
|
||||
// Document
|
||||
case 1000:
|
||||
return new DummyRecordWithChildren(b,start,len);
|
||||
|
||||
// "Slide"
|
||||
case 1006:
|
||||
return new Slide(b,start,len);
|
||||
|
||||
// "SlideAtom"
|
||||
case 1007:
|
||||
return new SlideAtom(b,start,len);
|
||||
|
||||
// "Notes"
|
||||
case 1008:
|
||||
return new Notes(b,start,len);
|
||||
|
||||
// "NotesAtom" (Details on Notes sheets)
|
||||
case 1009:
|
||||
return new NotesAtom(b,start,len);
|
||||
|
||||
// "SlidePersistAtom" (Details on text for a sheet)
|
||||
case 1011:
|
||||
return new SlidePersistAtom(b,start,len);
|
||||
|
||||
// MainMaster (MetaSheet lives inside the PPDrawing inside this)
|
||||
case 1016:
|
||||
return new DummyRecordWithChildren(b,start,len);
|
||||
|
||||
// PPDrawing (MetaSheet lives inside this)
|
||||
case 1036:
|
||||
return new PPDrawing(b,start,len);
|
||||
|
||||
// TextHeaderAtom (Holds details on following text)
|
||||
case 3999:
|
||||
return new TextHeaderAtom(b,start,len);
|
||||
|
||||
// TextCharsAtom (Text in Unicode format)
|
||||
case 4000:
|
||||
return new TextCharsAtom(b,start,len);
|
||||
|
||||
// TextByteAtom (Text in ascii format)
|
||||
case 4008:
|
||||
return new TextBytesAtom(b,start,len);
|
||||
|
||||
// SlideListWithText (Many Sheets live inside here)
|
||||
case 4080:
|
||||
return new SlideListWithText(b,start,len);
|
||||
|
||||
// UserEditAtom (Holds pointers, last viewed etc)
|
||||
case 4085:
|
||||
return new UserEditAtom(b,start,len);
|
||||
|
||||
// PersistPtrFullBlock (Don't know what it holds, but do care about where it lives)
|
||||
case 6001:
|
||||
return new PersistPtrHolder(b,start,len);
|
||||
// PersistPtrIncrementalBlock (Don't know what it holds, but do care about where it lives)
|
||||
case 6002:
|
||||
return new PersistPtrHolder(b,start,len);
|
||||
|
||||
default:
|
||||
return new UnknownRecordPlaceholder(b,start,len);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
/**
|
||||
* Abstract class which all atom records will extend.
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public abstract class RecordAtom extends Record
|
||||
{
|
||||
/**
|
||||
* We are an atom
|
||||
*/
|
||||
public boolean isAnAtom() { return true; }
|
||||
|
||||
/**
|
||||
* We're an atom, returns null
|
||||
*/
|
||||
public Record[] getChildRecords() { return null; }
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import org.apache.poi.hslf.util.MutableByteArrayOutputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Abstract class which all container records will extend. Providers
|
||||
* helpful methods for writing child records out to disk
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public abstract class RecordContainer extends Record
|
||||
{
|
||||
/**
|
||||
* We're not an atom
|
||||
*/
|
||||
public boolean isAnAtom() { return false; }
|
||||
|
||||
/**
|
||||
* Write out our header, and our children.
|
||||
* @param headerA the first byte of the header
|
||||
* @param headerB the second byte of the header
|
||||
* @param type the record type
|
||||
* @param children our child records
|
||||
* @param out the stream to write to
|
||||
*/
|
||||
public void writeOut(byte headerA, byte headerB, long type, Record[] children, OutputStream out) throws IOException {
|
||||
// If we have a mutable output stream, take advantage of that
|
||||
if(out instanceof MutableByteArrayOutputStream) {
|
||||
MutableByteArrayOutputStream mout =
|
||||
(MutableByteArrayOutputStream)out;
|
||||
|
||||
// Grab current size
|
||||
int oldSize = mout.getBytesWritten();
|
||||
|
||||
// Write out our header, less the size
|
||||
mout.write(new byte[] {headerA,headerB});
|
||||
byte[] typeB = new byte[2];
|
||||
LittleEndian.putShort(typeB,(short)type);
|
||||
mout.write(typeB);
|
||||
mout.write(new byte[4]);
|
||||
|
||||
// Write out the children
|
||||
for(int i=0; i<children.length; i++) {
|
||||
children[i].writeOut(mout);
|
||||
}
|
||||
|
||||
// Update our header with the size
|
||||
// Don't forget to knock 8 more off, since we don't include the
|
||||
// header in the size
|
||||
int length = mout.getBytesWritten() - oldSize - 8;
|
||||
byte[] size = new byte[4];
|
||||
LittleEndian.putInt(size,0,length);
|
||||
mout.overwrite(size, oldSize+4);
|
||||
} else {
|
||||
// Going to have to do it a slower way, because we have
|
||||
// to update the length come the end
|
||||
|
||||
// Create a ByteArrayOutputStream to hold everything in
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
// Write out our header, less the size
|
||||
baos.write(new byte[] {headerA,headerB});
|
||||
byte[] typeB = new byte[2];
|
||||
LittleEndian.putShort(typeB,(short)type);
|
||||
baos.write(typeB);
|
||||
baos.write(new byte[] {0,0,0,0});
|
||||
|
||||
// Write out our children
|
||||
for(int i=0; i<children.length; i++) {
|
||||
children[i].writeOut(baos);
|
||||
}
|
||||
|
||||
// Grab the bytes back
|
||||
byte[] toWrite = baos.toByteArray();
|
||||
|
||||
// Update our header with the size
|
||||
// Don't forget to knock 8 more off, since we don't include the
|
||||
// header in the size
|
||||
LittleEndian.putInt(toWrite,4,(toWrite.length-8));
|
||||
|
||||
// Write out the bytes
|
||||
out.write(toWrite);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Master container for Slides. There is one of these for every slide,
|
||||
* and they have certain specific children
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class Slide extends RecordContainer
|
||||
{
|
||||
private Record[] _children;
|
||||
private byte[] _header;
|
||||
private static long _type = 1006l;
|
||||
|
||||
// Links to our more interesting children
|
||||
private SlideAtom slideAtom;
|
||||
private PPDrawing ppDrawing;
|
||||
|
||||
/**
|
||||
* Returns the SlideAtom of this Slide
|
||||
*/
|
||||
public SlideAtom getSlideAtom() { return slideAtom; }
|
||||
|
||||
/**
|
||||
* Returns the PPDrawing of this Slide, which has all the
|
||||
* interesting data in it
|
||||
*/
|
||||
public PPDrawing getPPDrawing() { return ppDrawing; }
|
||||
|
||||
|
||||
/**
|
||||
* Set things up, and find our more interesting children
|
||||
*/
|
||||
protected Slide(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);
|
||||
|
||||
// Find the interesting ones in there
|
||||
for(int i=0; i<_children.length; i++) {
|
||||
if(_children[i] instanceof SlideAtom) {
|
||||
slideAtom = (SlideAtom)_children[i];
|
||||
}
|
||||
if(_children[i] instanceof PPDrawing) {
|
||||
ppDrawing = (PPDrawing)_children[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* We are of type 1006
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* Return any children
|
||||
*/
|
||||
public Record[] getChildRecords() { return _children; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
writeOut(_header[0],_header[1],_type,_children,out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A Slide Atom (type 1007). Holds information on the parent Slide, what
|
||||
* Master Slide it uses, what Notes is attached to it, that sort of thing.
|
||||
* It also has a SSlideLayoutAtom embeded in it, but without the Atom header
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class SlideAtom extends RecordAtom
|
||||
{
|
||||
private byte[] _header;
|
||||
private static long _type = 1007l;
|
||||
public static final int MASTER_SLIDE_ID = 0;
|
||||
public static final int USES_MASTER_SLIDE_ID = -2147483648;
|
||||
|
||||
private int masterID;
|
||||
private int notesID;
|
||||
|
||||
private boolean followMasterObjects;
|
||||
private boolean followMasterScheme;
|
||||
private boolean followMasterBackground;
|
||||
private SSlideLayoutAtom layoutAtom;
|
||||
private byte[] reserved;
|
||||
|
||||
|
||||
/** Get the ID of the master slide used. 0 if this is a master slide, otherwise -2147483648 */
|
||||
public int getMasterID() { return masterID; }
|
||||
/** Get the ID of the notes for this slide. 0 if doesn't have one */
|
||||
public int getNotesID() { return notesID; }
|
||||
/** Get the embeded SSlideLayoutAtom */
|
||||
public SSlideLayoutAtom getSSlideLayoutAtom() { return layoutAtom; }
|
||||
|
||||
public boolean getFollowMasterObjects() { return followMasterObjects; }
|
||||
public boolean getFollowMasterScheme() { return followMasterScheme; }
|
||||
public boolean getFollowMasterBackground() { return followMasterBackground; }
|
||||
public void setFollowMasterObjects(boolean flag) { followMasterObjects = flag; }
|
||||
public void setFollowMasterScheme(boolean flag) { followMasterScheme = flag; }
|
||||
public void setFollowMasterBackground(boolean flag) { followMasterBackground = flag; }
|
||||
|
||||
|
||||
/* *************** record code follows ********************** */
|
||||
|
||||
/**
|
||||
* For the Slide Atom
|
||||
*/
|
||||
protected SlideAtom(byte[] source, int start, int len) {
|
||||
// Sanity Checking
|
||||
if(len < 30) { len = 30; }
|
||||
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Grab the 12 bytes that is "SSlideLayoutAtom"
|
||||
byte[] SSlideLayoutAtomData = new byte[12];
|
||||
System.arraycopy(source,start+8,SSlideLayoutAtomData,0,12);
|
||||
// Use them to build up the SSlideLayoutAtom
|
||||
layoutAtom = new SSlideLayoutAtom(SSlideLayoutAtomData);
|
||||
|
||||
// Get the IDs of the master and notes
|
||||
masterID = (int)LittleEndian.getInt(source,start+12+8);
|
||||
notesID = (int)LittleEndian.getInt(source,start+16+8);
|
||||
|
||||
// Grok the flags, stored as bits
|
||||
int flags = LittleEndian.getUShort(source,start+20+8);
|
||||
if((flags&4) == 4) {
|
||||
followMasterBackground = true;
|
||||
} else {
|
||||
followMasterBackground = false;
|
||||
}
|
||||
if((flags&2) == 2) {
|
||||
followMasterScheme = true;
|
||||
} else {
|
||||
followMasterScheme = false;
|
||||
}
|
||||
if((flags&1) == 1) {
|
||||
followMasterObjects = true;
|
||||
} else {
|
||||
followMasterObjects = false;
|
||||
}
|
||||
|
||||
// If there's any other bits of data, keep them about
|
||||
// 8 bytes header + 20 bytes to flags + 2 bytes flags = 30 bytes
|
||||
reserved = new byte[len-30];
|
||||
System.arraycopy(source,start+30,reserved,0,reserved.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are of type 1007
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
// Header
|
||||
out.write(_header);
|
||||
|
||||
// SSSlideLayoutAtom stuff
|
||||
layoutAtom.writeOut(out);
|
||||
|
||||
// IDs
|
||||
writeLittleEndian(masterID,out);
|
||||
writeLittleEndian(notesID,out);
|
||||
|
||||
// Flags
|
||||
short flags = 0;
|
||||
if(followMasterObjects) { flags += 1; }
|
||||
if(followMasterScheme) { flags += 2; }
|
||||
if(followMasterBackground) { flags += 4; }
|
||||
writeLittleEndian(flags,out);
|
||||
|
||||
// Reserved data
|
||||
out.write(reserved);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds the geometry of the Slide, and the ID of the placeholders
|
||||
* on the slide.
|
||||
* (Embeded inside SlideAtom is a SSlideLayoutAtom, without the
|
||||
* usual record header. Since it's a fixed size and tied to
|
||||
* the SlideAtom, we'll hold it here.)
|
||||
*/
|
||||
public class SSlideLayoutAtom {
|
||||
// The different kinds of geometry
|
||||
public static final int TITLE_SLIDE = 0;
|
||||
public static final int TITLE_BODY_SLIDE = 1;
|
||||
public static final int TITLE_MASTER_SLIDE = 2;
|
||||
public static final int MASTER_SLIDE = 3;
|
||||
public static final int MASTER_NOTES = 4;
|
||||
public static final int NOTES_TITLE_BODY = 5;
|
||||
public static final int HANDOUT = 6; // Only header, footer and date placeholders
|
||||
public static final int TITLE_ONLY = 7;
|
||||
public static final int TITLE_2_COLUMN_BODY = 8;
|
||||
public static final int TITLE_2_ROW_BODY = 9;
|
||||
public static final int TITLE_2_COLUNM_RIGHT_2_ROW_BODY = 10;
|
||||
public static final int TITLE_2_COLUNM_LEFT_2_ROW_BODY = 11;
|
||||
public static final int TITLE_2_ROW_BOTTOM_2_COLUMN_BODY = 12;
|
||||
public static final int TITLE_2_ROW_TOP_2_COLUMN_BODY = 13;
|
||||
public static final int FOUR_OBJECTS = 14;
|
||||
public static final int BIG_OBJECT = 15;
|
||||
public static final int BLANK_SLIDE = 16;
|
||||
public static final int VERTICAL_TITLE_BODY_LEFT = 17;
|
||||
public static final int VERTICAL_TITLE_2_ROW_BODY_LEFT = 17;
|
||||
|
||||
/** What geometry type we are */
|
||||
private int geometry;
|
||||
/** What placeholder IDs we have */
|
||||
private byte[] placeholderIDs;
|
||||
|
||||
/** Retrieve the geometry type */
|
||||
public int getGeometryType() { return geometry; }
|
||||
|
||||
/**
|
||||
* Create a new Embeded SSlideLayoutAtom, from 12 bytes of data
|
||||
*/
|
||||
public SSlideLayoutAtom(byte[] data) {
|
||||
if(data.length != 12) {
|
||||
throw new RuntimeException("SSlideLayoutAtom created with byte array not 12 bytes long - was " + data.length + " bytes in size");
|
||||
}
|
||||
|
||||
// Grab out our data
|
||||
geometry = (int)LittleEndian.getInt(data,0);
|
||||
placeholderIDs = new byte[8];
|
||||
System.arraycopy(data,4,placeholderIDs,0,8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk. Skips the record header
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
// Write the geometry
|
||||
writeLittleEndian(geometry,out);
|
||||
// Write the placeholder IDs
|
||||
out.write(placeholderIDs);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import org.apache.poi.hslf.model.Sheet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* These are tricky beasts. They contain the text of potentially
|
||||
* many (normal) slides. They are made up of several sets of
|
||||
* - SlidePersistAtom
|
||||
* - TextHeaderAtom
|
||||
* - TextBytesAtom / TextCharsAtom
|
||||
* - StyleTextPropAtom (optional)
|
||||
* - TextSpecInfoAtom (optional)
|
||||
* - InteractiveInfo (optional)
|
||||
* - TxInteractiveInfoAtom (optional)
|
||||
* and then the next SlidePersistAtom.
|
||||
*
|
||||
* Eventually, Slides will find the blocks that interest them from all
|
||||
* the SlideListWithText entries, and refere to them
|
||||
*
|
||||
* For now, we scan through looking for interesting bits, then creating
|
||||
* the helpful Sheet from model for them
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
// For now, pretend to be an atom
|
||||
public class SlideListWithText extends RecordContainer
|
||||
{
|
||||
private Record[] _children;
|
||||
private byte[] _header;
|
||||
private static long _type = 4080;
|
||||
|
||||
private SlideAtomsSet[] slideAtomsSets;
|
||||
|
||||
/**
|
||||
* Create a new holder for slide records
|
||||
*/
|
||||
protected SlideListWithText(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);
|
||||
|
||||
// Group our children together into SlideAtomsSets
|
||||
// That way, model layer code can just grab the sets to use,
|
||||
// without having to try to match the children together
|
||||
Vector sets = new Vector();
|
||||
for(int i=0; i<_children.length; i++) {
|
||||
if(_children[i] instanceof SlidePersistAtom) {
|
||||
// Find where the next SlidePersistAtom is
|
||||
int endPos = i+1;
|
||||
while(endPos < _children.length && !(_children[endPos] instanceof SlidePersistAtom)) {
|
||||
endPos += 1;
|
||||
}
|
||||
|
||||
// Now, if not empty, create a SlideAtomsSets
|
||||
int clen = endPos - i - 1;
|
||||
if(clen == 0) { continue; }
|
||||
Record[] spaChildren = new Record[clen];
|
||||
System.arraycopy(_children,i+1,spaChildren,0,clen);
|
||||
SlideAtomsSet set = new SlideAtomsSet((SlidePersistAtom)_children[i],spaChildren);
|
||||
sets.add(set);
|
||||
|
||||
// Wind on
|
||||
i += clen;
|
||||
}
|
||||
}
|
||||
|
||||
// Turn the vector into an array
|
||||
slideAtomsSets = new SlideAtomsSet[sets.size()];
|
||||
for(int i=0; i<slideAtomsSets.length; i++) {
|
||||
slideAtomsSets[i] = (SlideAtomsSet)sets.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get access to the SlideAtomsSets of the children of this record
|
||||
*/
|
||||
public SlideAtomsSet[] getSlideAtomsSets() { return slideAtomsSets; }
|
||||
|
||||
/**
|
||||
* Return the value we were given at creation
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* We're pretending to be an atom, so return null
|
||||
*/
|
||||
public Record[] getChildRecords() { return _children; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
writeOut(_header[0],_header[1],_type,_children,out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to wrap up a matching set of records that hold the
|
||||
* text for a given sheet. Contains the leading SlidePersistAtom,
|
||||
* and all of the records until the next SlidePersistAtom. This
|
||||
* includes sets of TextHeaderAtom and TextBytesAtom/TextCharsAtom,
|
||||
* along with some others.
|
||||
*/
|
||||
public class SlideAtomsSet {
|
||||
private SlidePersistAtom slidePersistAtom;
|
||||
private Record[] slideRecords;
|
||||
|
||||
/** Get the SlidePersistAtom, which gives details on the Slide this text is associated with */
|
||||
public SlidePersistAtom getSlidePersistAtom() { return slidePersistAtom; }
|
||||
/** Get the Text related records for this slide */
|
||||
public Record[] getSlideRecords() { return slideRecords; }
|
||||
|
||||
/** Create one to hold the Records for one Slide's text */
|
||||
public SlideAtomsSet(SlidePersistAtom s, Record[] r) {
|
||||
slidePersistAtom = s;
|
||||
slideRecords = r;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A SlidePersist Atom (type 1011). Holds information on the text of a
|
||||
* given slide, which are stored in the same SlideListWithText
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class SlidePersistAtom extends RecordAtom
|
||||
{
|
||||
private byte[] _header;
|
||||
private static long _type = 1011l;
|
||||
|
||||
/** Slide reference ID. A machine readable "page id" */
|
||||
private int refID;
|
||||
private boolean hasShapesOtherThanPlaceholders;
|
||||
/** Number of placeholder texts that will follow in the SlideListWithText */
|
||||
private int numPlaceholderTexts;
|
||||
/** Less useful identifier */
|
||||
private int slideIdentifier;
|
||||
/** Reserved fields. Who knows what they do */
|
||||
private byte[] reservedFields;
|
||||
|
||||
public int getRefID() { return refID; }
|
||||
public int getSlideIdentifier() { return slideIdentifier; }
|
||||
public int getNumPlaceholderTexts() { return numPlaceholderTexts; }
|
||||
public boolean getHasShapesOtherThanPlaceholders() { return hasShapesOtherThanPlaceholders; }
|
||||
|
||||
/* *************** record code follows ********************** */
|
||||
|
||||
/**
|
||||
* For the SlidePersist Atom
|
||||
*/
|
||||
protected SlidePersistAtom(byte[] source, int start, int len) {
|
||||
// Sanity Checking
|
||||
if(len < 8) { len = 8; }
|
||||
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Grab the reference ID
|
||||
refID = (int)LittleEndian.getInt(source,start+8);
|
||||
|
||||
// Next up is a set of flags, but only bit 3 is used!
|
||||
int flags = (int)LittleEndian.getInt(source,start+12);
|
||||
if(flags == 4) {
|
||||
hasShapesOtherThanPlaceholders = true;
|
||||
} else {
|
||||
hasShapesOtherThanPlaceholders = false;
|
||||
}
|
||||
|
||||
// Now the number of Placeholder Texts
|
||||
numPlaceholderTexts = (int)LittleEndian.getInt(source,start+16);
|
||||
|
||||
// Last useful one is the unique slide identifier
|
||||
slideIdentifier = (int)LittleEndian.getInt(source,start+20);
|
||||
|
||||
// Finally you have typically 4 or 8 bytes of reserved fields,
|
||||
// all zero running from 24 bytes in to the end
|
||||
reservedFields = new byte[len-24];
|
||||
System.arraycopy(source,start+24,reservedFields,0,reservedFields.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are of type 1011
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// Compute the flags part - only bit 3 is used
|
||||
int flags = 0;
|
||||
if(hasShapesOtherThanPlaceholders) {
|
||||
flags = 4;
|
||||
}
|
||||
|
||||
// Write out our fields
|
||||
writeLittleEndian(refID,out);
|
||||
writeLittleEndian(flags,out);
|
||||
writeLittleEndian(numPlaceholderTexts,out);
|
||||
writeLittleEndian(slideIdentifier,out);
|
||||
out.write(reservedFields);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A TextBytesAtom (type 4008). Holds text in ascii form (unknown
|
||||
* code page, for now assumed to be the default of
|
||||
* org.apache.poi.util.StringUtil, which is the Excel default).
|
||||
* The trailing return character is always stripped from this
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class TextBytesAtom extends RecordAtom
|
||||
{
|
||||
private byte[] _header;
|
||||
private static long _type = 4008l;
|
||||
|
||||
/** The bytes that make up the text */
|
||||
private byte[] _text;
|
||||
|
||||
/** Grabs the text. Uses the default codepage */
|
||||
public String getText() {
|
||||
return StringUtil.getFromCompressedUnicode(_text,0,_text.length);
|
||||
}
|
||||
|
||||
/** Updates the text in the Atom. Must be 8 bit ascii */
|
||||
public void setText(byte[] b) {
|
||||
// Set the text
|
||||
_text = b;
|
||||
|
||||
// Update the size (header bytes 5-8)
|
||||
LittleEndian.putInt(_header,4,_text.length);
|
||||
}
|
||||
|
||||
/* *************** record code follows ********************** */
|
||||
|
||||
/**
|
||||
* For the TextBytes Atom
|
||||
*/
|
||||
protected TextBytesAtom(byte[] source, int start, int len) {
|
||||
// Sanity Checking
|
||||
if(len < 8) { len = 8; }
|
||||
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Grab the text
|
||||
_text = new byte[len-8];
|
||||
System.arraycopy(source,start+8,_text,0,len-8);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are of type 4008
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// Write out our text
|
||||
out.write(_text);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A TextCharsAtom (type 4000). Holds text in byte swapped unicode form.
|
||||
* The trailing return character is always stripped from this
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class TextCharsAtom extends RecordAtom
|
||||
{
|
||||
private byte[] _header;
|
||||
private static long _type = 4000l;
|
||||
|
||||
/** The bytes that make up the text */
|
||||
private byte[] _text;
|
||||
|
||||
/** Grabs the text. */
|
||||
public String getText() {
|
||||
return StringUtil.getFromUnicodeLE(_text);
|
||||
}
|
||||
|
||||
/** Updates the text in the Atom. */
|
||||
public void setText(String text) {
|
||||
// Convert to little endian unicode
|
||||
_text = new byte[text.length()*2];
|
||||
StringUtil.putUnicodeLE(text,_text,0);
|
||||
|
||||
// Update the size (header bytes 5-8)
|
||||
LittleEndian.putInt(_header,4,_text.length);
|
||||
}
|
||||
|
||||
/* *************** record code follows ********************** */
|
||||
|
||||
/**
|
||||
* For the TextChars Atom
|
||||
*/
|
||||
protected TextCharsAtom(byte[] source, int start, int len) {
|
||||
// Sanity Checking
|
||||
if(len < 8) { len = 8; }
|
||||
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Grab the text
|
||||
_text = new byte[len-8];
|
||||
System.arraycopy(source,start+8,_text,0,len-8);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are of type 4000
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// Write out our text
|
||||
out.write(_text);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A TextHeaderAtom (type 3999). Holds information on what kind of
|
||||
* text is contained in the TextBytesAtom / TextCharsAtom that follows
|
||||
* straight after
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class TextHeaderAtom extends RecordAtom
|
||||
{
|
||||
private byte[] _header;
|
||||
private static long _type = 3999l;
|
||||
|
||||
public static final int TITLE_TYPE = 0;
|
||||
public static final int BODY_TYPE = 1;
|
||||
public static final int NOTES_TYPE = 2;
|
||||
public static final int OTHER_TYPE = 4;
|
||||
public static final int CENTRE_BODY_TYPE = 5;
|
||||
public static final int CENTER_TITLE_TYPE = 6;
|
||||
public static final int HALF_BODY_TYPE = 7;
|
||||
public static final int QUARTER_BODY_TYPE = 8;
|
||||
|
||||
/** The kind of text it is */
|
||||
private int textType;
|
||||
|
||||
public int getTextType() { return textType; }
|
||||
public void setTextType(int type) { textType = type; }
|
||||
|
||||
/* *************** record code follows ********************** */
|
||||
|
||||
/**
|
||||
* For the TextHeader Atom
|
||||
*/
|
||||
protected TextHeaderAtom(byte[] source, int start, int len) {
|
||||
// Sanity Checking - we're always 12 bytes long
|
||||
if(len < 12) {
|
||||
len = 12;
|
||||
if(source.length - start < 12) {
|
||||
throw new RuntimeException("Not enough data to form a TextHeaderAtom (always 12 bytes long) - found " + (source.length - start));
|
||||
}
|
||||
}
|
||||
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Grab the type
|
||||
textType = (int)LittleEndian.getInt(source,start+8);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are of type 3999
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// Write out our type
|
||||
writeLittleEndian(textType,out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* If we come across a record we don't know about, we create one of
|
||||
* these. It allows us to keep track of what it contains, so we can
|
||||
* write it back out to disk unchanged
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class UnknownRecordPlaceholder extends RecordAtom
|
||||
{
|
||||
private byte[] _contents;
|
||||
private long _type;
|
||||
|
||||
/**
|
||||
* Create a new holder for a record we don't grok
|
||||
*/
|
||||
protected UnknownRecordPlaceholder(byte[] source, int start, int len) {
|
||||
// Sanity Checking - including whole header, so treat
|
||||
// length as based of 0, not 8 (including header size based)
|
||||
if(len < 0) { len = 0; }
|
||||
|
||||
// Treat as an atom, grab and hold everything
|
||||
_contents = new byte[len];
|
||||
System.arraycopy(source,start,_contents,0,len);
|
||||
_type = LittleEndian.getUShort(_contents,2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value we were given at creation
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
out.write(_contents);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.LittleEndian;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A UserEdit Atom (type 4085). Holds information which bits of the file
|
||||
* were last used by powerpoint, the version of powerpoint last used etc.
|
||||
*
|
||||
* ** WARNING ** stores byte offsets from the start of the PPT stream to
|
||||
* other records! If you change the size of any elements before one of
|
||||
* these, you'll need to update the offsets!
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class UserEditAtom extends PositionDependentRecordAtom
|
||||
{
|
||||
public static final int LAST_VIEW_NONE = 0;
|
||||
public static final int LAST_VIEW_SLIDE_VIEW = 1;
|
||||
public static final int LAST_VIEW_OUTLINE_VIEW = 2;
|
||||
public static final int LAST_VIEW_NOTES = 3;
|
||||
|
||||
private byte[] _header;
|
||||
private static long _type = 4085l;
|
||||
private byte[] reserved;
|
||||
|
||||
private int lastViewedSlideID;
|
||||
private int pptVersion;
|
||||
private int lastUserEditAtomOffset;
|
||||
private int persistPointersOffset;
|
||||
private int docPersistRef;
|
||||
private int maxPersistWritten;
|
||||
private short lastViewType;
|
||||
|
||||
// Somewhat user facing getters
|
||||
public int getLastViewedSlideID() { return lastViewedSlideID; }
|
||||
public short getLastViewType() { return lastViewType; }
|
||||
|
||||
// Scary internal getters
|
||||
public int getLastUserEditAtomOffset() { return lastUserEditAtomOffset; }
|
||||
public int getPersistPointersOffset() { return persistPointersOffset; }
|
||||
public int getDocPersistRef() { return docPersistRef; }
|
||||
public int getMaxPersistWritten() { return maxPersistWritten; }
|
||||
|
||||
// More scary internal setters
|
||||
public void setLastUserEditAtomOffset(int offset) { lastUserEditAtomOffset = offset; }
|
||||
public void setPersistPointersOffset(int offset) { persistPointersOffset = offset; }
|
||||
|
||||
/* *************** record code follows ********************** */
|
||||
|
||||
/**
|
||||
* For the UserEdit Atom
|
||||
*/
|
||||
protected UserEditAtom(byte[] source, int start, int len) {
|
||||
// Sanity Checking
|
||||
if(len < 34) { len = 34; }
|
||||
|
||||
// Store where we currently live on disk
|
||||
myLastOnDiskOffset = start;
|
||||
|
||||
// Get the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Get the last viewed slide ID
|
||||
lastViewedSlideID = (int)LittleEndian.getInt(source,start+0+8);
|
||||
|
||||
// Get the PPT version
|
||||
pptVersion = (int)LittleEndian.getInt(source,start+4+8);
|
||||
|
||||
// Get the offset to the previous incremental save's UserEditAtom
|
||||
// This will be the byte offset on disk where the previous one
|
||||
// starts, or 0 if this is the first one
|
||||
lastUserEditAtomOffset = (int)LittleEndian.getInt(source,start+8+8);
|
||||
|
||||
// Get the offset to the persist pointers
|
||||
// This will be the byte offset on disk where the preceding
|
||||
// PersistPtrFullBlock or PersistPtrIncrementalBlock starts
|
||||
persistPointersOffset = (int)LittleEndian.getInt(source,start+12+8);
|
||||
|
||||
// Get the persist reference for the document persist object
|
||||
// Normally seems to be 1
|
||||
docPersistRef = (int)LittleEndian.getInt(source,start+16+8);
|
||||
|
||||
// Maximum number of persist objects written
|
||||
maxPersistWritten = (int)LittleEndian.getInt(source,start+20+8);
|
||||
|
||||
// Last view type
|
||||
lastViewType = (short)LittleEndian.getShort(source,start+24+8);
|
||||
|
||||
// There might be a few more bytes, which are a reserved field
|
||||
reserved = new byte[len-26-8];
|
||||
System.arraycopy(source,start+26+8,reserved,0,reserved.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are of type 4085
|
||||
*/
|
||||
public long getRecordType() { return _type; }
|
||||
|
||||
/**
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
// Header
|
||||
out.write(_header);
|
||||
|
||||
// Write out the values
|
||||
writeLittleEndian(lastViewedSlideID,out);
|
||||
writeLittleEndian(pptVersion,out);
|
||||
writeLittleEndian(lastUserEditAtomOffset,out);
|
||||
writeLittleEndian(persistPointersOffset,out);
|
||||
writeLittleEndian(docPersistRef,out);
|
||||
writeLittleEndian(maxPersistWritten,out);
|
||||
writeLittleEndian(lastViewType,out);
|
||||
|
||||
// Reserved fields
|
||||
out.write(reserved);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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 java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
import org.apache.poi.hslf.record.Record;
|
||||
import org.apache.poi.hslf.record.SlideAtom;
|
||||
import org.apache.poi.hslf.record.SlideListWithText;
|
||||
import org.apache.poi.hslf.record.SlideListWithText.*;
|
||||
|
||||
/**
|
||||
* This class is a friendly wrapper on top of the more scary HSLFSlideShow.
|
||||
*
|
||||
* TODO:
|
||||
* - figure out how to match notes to their correct sheet
|
||||
* (will involve understanding DocSlideList and DocNotesList)
|
||||
* - handle Slide creation cleaner
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class SlideShow
|
||||
{
|
||||
// What we're based on
|
||||
private HSLFSlideShow _hslfSlideShow;
|
||||
|
||||
// Low level contents, as taken from HSLFSlideShow
|
||||
private Record[] _records;
|
||||
|
||||
// Friendly objects for people to deal with
|
||||
private Slide[] _slides;
|
||||
private Notes[] _notes;
|
||||
// private MetaSheets[] _msheets;
|
||||
|
||||
/**
|
||||
* right now this function takes one parameter: a ppt file, and outputs
|
||||
* the text it can find for it
|
||||
*/
|
||||
public static void main(String args[]) throws IOException
|
||||
{
|
||||
HSLFSlideShow basefoo = new HSLFSlideShow(args[0]);
|
||||
SlideShow foo = new SlideShow(basefoo);
|
||||
|
||||
Slide[] slides = foo.getSlides();
|
||||
for(int i=0; i<slides.length; i++) {
|
||||
Slide slide = slides[i];
|
||||
System.out.println("*Slide " + slide.getSheetNumber() + ":");
|
||||
TextRun[] runs = slide.getTextRuns();
|
||||
for(int j=0; j<runs.length; j++) {
|
||||
TextRun run = runs[j];
|
||||
System.out.println(" * Text run " + run.getRunType());
|
||||
System.out.println("\n" + run.getText() + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Powerpoint document from the underlying
|
||||
* HSLFSlideShow object. Finds the model stuff from this
|
||||
*
|
||||
* @param hslfSlideShow the HSLFSlideShow to base on
|
||||
*/
|
||||
public SlideShow(HSLFSlideShow hslfSlideShow) throws IOException
|
||||
{
|
||||
// Get useful things from our base slideshow
|
||||
_hslfSlideShow = hslfSlideShow;
|
||||
_records = _hslfSlideShow.getRecords();
|
||||
byte[] _docstream = _hslfSlideShow.getUnderlyingBytes();
|
||||
|
||||
|
||||
// For holding the Slide Records
|
||||
Vector slidesV = new Vector(10);
|
||||
// For holding the Notes Records
|
||||
Vector notesV = new Vector(10);
|
||||
// For holding the Meta Sheet Records
|
||||
Vector metaSheetsV = new Vector(10);
|
||||
// For holding Document Records
|
||||
Vector documentsV = new Vector(10);
|
||||
// For holding SlideListWithText Records
|
||||
Vector slwtV = new Vector(10);
|
||||
|
||||
// Look for Notes, Slides and Documents
|
||||
for(int i=0; i<_records.length; i++) {
|
||||
if(_records[i] instanceof org.apache.poi.hslf.record.Notes) {
|
||||
notesV.add(_records[i]);
|
||||
}
|
||||
if(_records[i] instanceof org.apache.poi.hslf.record.Slide) {
|
||||
slidesV.add(_records[i]);
|
||||
}
|
||||
if(_records[i].getRecordType() == 1000l) {
|
||||
documentsV.add(_records[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Also look for SlideListWithTexts in Documents
|
||||
//
|
||||
// Need to get the SlideAtomsSets for all of these. Then, query the
|
||||
// SlidePersistAtom, and group stuff together between SLWT blocks
|
||||
// based on the refID/slideID. Finally, build up a list of all the
|
||||
// SlideAtomsSets for a given refID / slideID, and pass them on to
|
||||
// the Slide when creating
|
||||
//
|
||||
// If a notes sheet exists, can normally match the Notes sheet ID
|
||||
// to the slide ID in the SlidePersistAtom. Since there isn't always,
|
||||
// and we can't find the ID in the slide, just order on the slide ID,
|
||||
// and hand off to the Slides in turn.
|
||||
// (Based on output from dev.SLWTTextListing and dev.SlideAndNotesAtomListing)
|
||||
//
|
||||
// There is often duplicate text, especially for the first few
|
||||
// Slides. Currently, it's up to the Slide model code to detect
|
||||
// and ignore those
|
||||
|
||||
for(int i=0; i<documentsV.size(); i++) {
|
||||
Record docRecord = (Record)documentsV.get(i);
|
||||
Record[] docChildren = docRecord.getChildRecords();
|
||||
for(int j=0; j<docChildren.length; j++) {
|
||||
if(docChildren[j] instanceof SlideListWithText) {
|
||||
//System.out.println("Found SLWT in document " + i);
|
||||
//System.out.println(" Has " + docChildren[j].getChildRecords().length + " children");
|
||||
slwtV.add(docChildren[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For now, grab out all the sets of Atoms in the SlideListWithText's
|
||||
// Only store those which aren't empty
|
||||
Vector setsV = new Vector();
|
||||
for(int i=0; i<slwtV.size(); i++) {
|
||||
SlideListWithText slwt = (SlideListWithText)slwtV.get(i);
|
||||
SlideAtomsSet[] thisSets = slwt.getSlideAtomsSets();
|
||||
for(int j=0; j<thisSets.length; j++) {
|
||||
setsV.add(thisSets[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now, sort the SlideAtomSets together into groups for the same slide ID,
|
||||
// and order them by the slide ID
|
||||
|
||||
// Find the unique IDs
|
||||
HashSet uniqueSlideIDs = new HashSet();
|
||||
for(int i=0; i<setsV.size(); i++) {
|
||||
SlideAtomsSet thisSet = (SlideAtomsSet)setsV.get(i);
|
||||
int id = thisSet.getSlidePersistAtom().getSlideIdentifier();
|
||||
Integer idI = new Integer(id);
|
||||
if(! uniqueSlideIDs.contains(idI) ) {
|
||||
uniqueSlideIDs.add(idI);
|
||||
}
|
||||
}
|
||||
int[] slideIDs = new int[uniqueSlideIDs.size()];
|
||||
int pos = 0;
|
||||
for(Iterator getIDs = uniqueSlideIDs.iterator(); getIDs.hasNext(); pos++) {
|
||||
Integer id = (Integer)getIDs.next();
|
||||
slideIDs[pos] = id.intValue();
|
||||
}
|
||||
// Sort
|
||||
Arrays.sort(slideIDs);
|
||||
// Group
|
||||
Vector[] sortedSetsV = new Vector[slideIDs.length];
|
||||
for(int i=0; i<setsV.size(); i++) {
|
||||
SlideAtomsSet thisSet = (SlideAtomsSet)setsV.get(i);
|
||||
int id = thisSet.getSlidePersistAtom().getSlideIdentifier();
|
||||
int arrayPos = -1;
|
||||
for(int j=0; j<slideIDs.length; j++) {
|
||||
if(slideIDs[j] == id) { arrayPos = j; }
|
||||
}
|
||||
if(sortedSetsV[arrayPos] == null) { sortedSetsV[arrayPos] = new Vector(); }
|
||||
sortedSetsV[arrayPos].add(thisSet);
|
||||
}
|
||||
|
||||
|
||||
// ******************* Do the real model layer creation ****************
|
||||
|
||||
|
||||
// Create our Notes
|
||||
// (Need to create first, as passed to the Slides)
|
||||
_notes = new Notes[notesV.size()];
|
||||
for(int i=0; i<_notes.length; i++) {
|
||||
_notes[i] = new Notes((org.apache.poi.hslf.record.Notes)notesV.get(i));
|
||||
}
|
||||
|
||||
|
||||
// Create our Slides
|
||||
_slides = new Slide[slidesV.size()];
|
||||
for(int i=0; i<_slides.length; i++) {
|
||||
// Grab the slide Record
|
||||
org.apache.poi.hslf.record.Slide slideRecord = (org.apache.poi.hslf.record.Slide)slidesV.get(i);
|
||||
|
||||
// Do they have a Notes?
|
||||
Notes thisNotes = null;
|
||||
// Find their SlideAtom, and use this to check for a Notes
|
||||
Record[] slideRecordChildren = slideRecord.getChildRecords();
|
||||
for(int j=0; j<slideRecordChildren.length; j++) {
|
||||
if(slideRecordChildren[j] instanceof SlideAtom) {
|
||||
SlideAtom sa = (SlideAtom)slideRecordChildren[j];
|
||||
int notesID = sa.getNotesID();
|
||||
if(notesID != 0) {
|
||||
for(int k=0; k<_notes.length; k++) {
|
||||
if(_notes[k].getSheetNumber() == notesID) {
|
||||
thisNotes = _notes[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grab the (hopefully) corresponding block of Atoms
|
||||
SlideAtomsSet[] sets;
|
||||
if(sortedSetsV.length > i) {
|
||||
Vector thisSetsV = sortedSetsV[i];
|
||||
sets = new SlideAtomsSet[thisSetsV.size()];
|
||||
for(int j=0; j<sets.length; j++) {
|
||||
sets[j] = (SlideAtomsSet)thisSetsV.get(j);
|
||||
}
|
||||
//System.out.println("For slide " + i + ", found " + sets.length + " Sets of text");
|
||||
} else {
|
||||
// Didn't find enough SlideAtomSets to give any to this sheet
|
||||
sets = new SlideAtomsSet[0];
|
||||
}
|
||||
|
||||
// Create the Slide model layer
|
||||
_slides[i] = new Slide(slideRecord,thisNotes,sets);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out the slideshow file the is represented by an instance of
|
||||
* this class
|
||||
* @param out The OutputStream to write to.
|
||||
* @throws IOException If there is an unexpected IOException from the passed
|
||||
* in OutputStream
|
||||
*/
|
||||
public void write(OutputStream out) throws IOException {
|
||||
_hslfSlideShow.write(out);
|
||||
}
|
||||
|
||||
|
||||
// Accesser methods follow
|
||||
|
||||
/**
|
||||
* Returns an array of all the normal Slides found in the slideshow
|
||||
*/
|
||||
public Slide[] getSlides() { return _slides; }
|
||||
|
||||
/**
|
||||
* Returns an array of all the normal Notes found in the slideshow
|
||||
*/
|
||||
public Notes[] getNotes() { return _notes; }
|
||||
|
||||
/**
|
||||
* Returns an array of all the meta Sheets (master sheets etc)
|
||||
* found in the slideshow
|
||||
*/
|
||||
//public MetaSheet[] getMetaSheets() { return _msheets; }
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* This class doesn't work yet, but is here to show the idea of a
|
||||
* ByteArrayOutputStream where you can track how many bytes you've
|
||||
* already written, and go back and write over a previous part of the stream
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public class MutableByteArrayOutputStream extends ByteArrayOutputStream
|
||||
{
|
||||
/** Return how many bytes we've stuffed in so far */
|
||||
public int getBytesWritten() { return -1; }
|
||||
|
||||
/** Write some bytes to the array */
|
||||
public void write(byte[] b) {}
|
||||
public void write(int b) {}
|
||||
|
||||
/** Write some bytes to an earlier bit of the array */
|
||||
public void overwrite(byte[] b, int startPos) {}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import java.io.*;
|
||||
import org.apache.poi.poifs.filesystem.*;
|
||||
|
||||
/**
|
||||
* Tests that HSLFSlideShow writes the powerpoint bit of data back out
|
||||
* correctly. Currently, that means being the same as what it read in
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestReWrite extends TestCase {
|
||||
// HSLFSlideShow primed on the test data
|
||||
private HSLFSlideShow ss;
|
||||
// POIFS primed on the test data
|
||||
private POIFSFileSystem pfs;
|
||||
|
||||
public TestReWrite() throws Exception {
|
||||
String dirname = System.getProperty("HSLF.testdata.path");
|
||||
String filename = dirname + "/basic_test_ppt_file.ppt";
|
||||
FileInputStream fis = new FileInputStream(filename);
|
||||
pfs = new POIFSFileSystem(fis);
|
||||
ss = new HSLFSlideShow(pfs);
|
||||
}
|
||||
|
||||
public void testWritesOutTheSame() throws Exception {
|
||||
// Write out to a byte array
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ss.write(baos);
|
||||
|
||||
// Build an input stream of it
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
|
||||
// Use POIFS to query that lot
|
||||
POIFSFileSystem npfs = new POIFSFileSystem(bais);
|
||||
|
||||
// Check that the "PowerPoint Document" sections have the same size
|
||||
DocumentEntry oProps = (DocumentEntry)pfs.getRoot().getEntry("PowerPoint Document");
|
||||
DocumentEntry nProps = (DocumentEntry)npfs.getRoot().getEntry("PowerPoint Document");
|
||||
assertEquals(oProps.getSize(),nProps.getSize());
|
||||
|
||||
// Check that they contain the same data
|
||||
byte[] _oData = new byte[oProps.getSize()];
|
||||
byte[] _nData = new byte[nProps.getSize()];
|
||||
pfs.createDocumentInputStream("PowerPoint Document").read(_oData);
|
||||
npfs.createDocumentInputStream("PowerPoint Document").read(_nData);
|
||||
for(int i=0; i<_oData.length; i++) {
|
||||
System.out.println(i + "\t" + Integer.toHexString(i));
|
||||
assertEquals(_oData[i], _nData[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.poifs.filesystem.*;
|
||||
|
||||
/**
|
||||
* Tests that HSLFSlideShow writes the powerpoint bit of data back out
|
||||
* in a sane manner - i.e. records end up in the right place
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestReWriteSanity extends TestCase {
|
||||
// HSLFSlideShow primed on the test data
|
||||
private HSLFSlideShow ss;
|
||||
// POIFS primed on the test data
|
||||
private POIFSFileSystem pfs;
|
||||
|
||||
public TestReWriteSanity() throws Exception {
|
||||
String dirname = System.getProperty("HSLF.testdata.path");
|
||||
String filename = dirname + "/basic_test_ppt_file.ppt";
|
||||
FileInputStream fis = new FileInputStream(filename);
|
||||
pfs = new POIFSFileSystem(fis);
|
||||
ss = new HSLFSlideShow(pfs);
|
||||
}
|
||||
|
||||
public void testUserEditAtomsRight() throws Exception {
|
||||
// Write out to a byte array
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ss.write(baos);
|
||||
|
||||
// Build an input stream of it
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
|
||||
// Create a new one from that
|
||||
HSLFSlideShow wss = new HSLFSlideShow(bais);
|
||||
|
||||
// Find the location of the PersistPtrIncrementalBlocks and
|
||||
// UserEditAtoms
|
||||
Record[] r = wss.getRecords();
|
||||
Hashtable pp = new Hashtable();
|
||||
Hashtable ue = new Hashtable();
|
||||
ue.put(new Integer(0),new Integer(0)); // Will show 0 if first
|
||||
int pos = 0;
|
||||
int lastUEPos = -1;
|
||||
|
||||
for(int i=0; i<r.length; i++) {
|
||||
if(r[i] instanceof PersistPtrHolder) {
|
||||
pp.put(new Integer(pos), r[i]);
|
||||
}
|
||||
if(r[i] instanceof UserEditAtom) {
|
||||
ue.put(new Integer(pos), r[i]);
|
||||
lastUEPos = pos;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream bc = new ByteArrayOutputStream();
|
||||
r[i].writeOut(bc);
|
||||
pos += bc.size();
|
||||
}
|
||||
|
||||
// Check that the UserEditAtom's point to right stuff
|
||||
for(int i=0; i<r.length; i++) {
|
||||
if(r[i] instanceof UserEditAtom) {
|
||||
UserEditAtom uea = (UserEditAtom)r[i];
|
||||
int luPos = uea.getLastUserEditAtomOffset();
|
||||
int ppPos = uea.getPersistPointersOffset();
|
||||
|
||||
assertTrue(pp.containsKey(new Integer(ppPos)));
|
||||
assertTrue(ue.containsKey(new Integer(luPos)));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the CurrentUserAtom points to the right UserEditAtom
|
||||
CurrentUserAtom cua = wss.getCurrentUserAtom();
|
||||
int listedUEPos = (int)cua.getCurrentEditOffset();
|
||||
assertEquals(lastUEPos,listedUEPos);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
|
||||
/**
|
||||
* Tests that HSLFSlideShow returns the right numbers of key records when
|
||||
* it parses the test file
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestRecordCounts extends TestCase {
|
||||
// HSLFSlideShow primed on the test data
|
||||
private HSLFSlideShow ss;
|
||||
|
||||
public TestRecordCounts() throws Exception {
|
||||
String dirname = System.getProperty("HSLF.testdata.path");
|
||||
String filename = dirname + "/basic_test_ppt_file.ppt";
|
||||
ss = new HSLFSlideShow(filename);
|
||||
}
|
||||
|
||||
public void testSheetsCount() throws Exception {
|
||||
// Top level
|
||||
Record[] r = ss.getRecords();
|
||||
|
||||
int count = 0;
|
||||
for(int i=0; i<r.length; i++) {
|
||||
if(r[i] instanceof Slide) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
// Currently still sees the Master Sheet, but might not in the future
|
||||
assertEquals(3,count);
|
||||
}
|
||||
|
||||
public void testNotesCount() throws Exception {
|
||||
// Top level
|
||||
Record[] r = ss.getRecords();
|
||||
|
||||
int count = 0;
|
||||
for(int i=0; i<r.length; i++) {
|
||||
if(r[i] instanceof Notes &&
|
||||
r[i].getRecordType() == 1008l) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
// Two real sheets, plus the master sheet
|
||||
assertEquals(3,count);
|
||||
}
|
||||
|
||||
public void testSlideListWithTextCount() throws Exception {
|
||||
// Second level
|
||||
Record[] rt = ss.getRecords();
|
||||
Record[] r = rt[0].getChildRecords();
|
||||
|
||||
int count = 0;
|
||||
for(int i=0; i<r.length; i++) {
|
||||
if(r[i] instanceof SlideListWithText &&
|
||||
r[i].getRecordType() == 4080l) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
// Two real sheets, plus the master sheet
|
||||
assertEquals(3,count);
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,67 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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.extractor;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests that the extractor correctly gets the text out of our sample file
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TextExtractor extends TestCase {
|
||||
// Extractor primed on the test data
|
||||
private PowerPointExtractor ppe;
|
||||
|
||||
public TextExtractor() throws Exception {
|
||||
String dirname = System.getProperty("HSLF.testdata.path");
|
||||
String filename = dirname + "/basic_test_ppt_file.ppt";
|
||||
ppe = new PowerPointExtractor(filename);
|
||||
}
|
||||
|
||||
public void testReadSheetText() throws Exception {
|
||||
String sheetText = ppe.getText();
|
||||
String expectText = "This is a test title\nThis is a test subtitle\nThis is on page 1\nThis is the title on page 2\nThis is page two\nIt has several blocks of text\nNone of them have formatting\n";
|
||||
|
||||
assertEquals(expectText.length(),sheetText.length());
|
||||
char[] st = sheetText.toCharArray();
|
||||
char[] et = expectText.toCharArray();
|
||||
for(int i=0; i<et.length; i++) {
|
||||
System.out.println(i + "\t" + et[i] + " " + st[i]);
|
||||
assertEquals(et[i],st[i]);
|
||||
}
|
||||
assertEquals(expectText,sheetText);
|
||||
}
|
||||
|
||||
public void testReadNoteText() throws Exception {
|
||||
String notesText = ppe.getNotes();
|
||||
String expectText = "These are the notes for page 1\nThese are the notes on page two, again lacking formatting\n";
|
||||
|
||||
assertEquals(expectText.length(),notesText.length());
|
||||
char[] nt = notesText.toCharArray();
|
||||
char[] et = expectText.toCharArray();
|
||||
for(int i=0; i<et.length; i++) {
|
||||
System.out.println(i + "\t" + et[i] + " " + nt[i]);
|
||||
assertEquals(et[i],nt[i]);
|
||||
}
|
||||
assertEquals(expectText,notesText);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
/**
|
||||
* Tests that SlidePersistAtom works properly
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestSlidePersistAtom extends TestCase {
|
||||
// From a real file
|
||||
private byte[] data_a = new byte[] { 0, 0, 0xF3-256, 3, 0x14, 0, 0, 0,
|
||||
4, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
public void testRecordType() throws Exception {
|
||||
SlidePersistAtom spa = new SlidePersistAtom(data_a, 0, data_a.length);
|
||||
assertEquals(1011l, spa.getRecordType());
|
||||
}
|
||||
public void testFlags() throws Exception {
|
||||
SlidePersistAtom spa = new SlidePersistAtom(data_a, 0, data_a.length);
|
||||
assertEquals(4, spa.getRefID() );
|
||||
assertEquals(true, spa.getHasShapesOtherThanPlaceholders() );
|
||||
assertEquals(2, spa.getNumPlaceholderTexts() );
|
||||
assertEquals(256, spa.getSlideIdentifier());
|
||||
}
|
||||
|
||||
public void testWrite() throws Exception {
|
||||
SlidePersistAtom spa = new SlidePersistAtom(data_a, 0, data_a.length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
spa.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(data_a.length, b.length);
|
||||
for(int i=0; i<data_a.length; i++) {
|
||||
assertEquals(data_a[i],b[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
/**
|
||||
* Tests that TextBytesAtom works properly
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestTextBytesAtom extends TestCase {
|
||||
// From a real file
|
||||
private byte[] data = new byte[] { 0, 0, 0xA8-256, 0x0f, 0x1c, 0, 0, 0,
|
||||
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
|
||||
0x65, 0x20, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x20, 0x6F, 0x6E,
|
||||
0x20, 0x70, 0x61, 0x67, 0x65, 0x20, 0x32 };
|
||||
private String data_text = "This is the title on page 2";
|
||||
private byte[] alt_data = new byte[] { 0, 0, 0xA8-256, 0x0F, 0x14, 0, 0, 0,
|
||||
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20,
|
||||
0x74, 0x65, 0x73, 0x74, 0x20, 0x74, 0x69, 0x74, 0x6C, 0x65 };
|
||||
private String alt_text = "This is a test title";
|
||||
|
||||
public void testRecordType() throws Exception {
|
||||
TextBytesAtom tba = new TextBytesAtom(data,0,data.length);
|
||||
assertEquals(4008l, tba.getRecordType());
|
||||
}
|
||||
|
||||
public void testTextA() throws Exception {
|
||||
TextBytesAtom tba = new TextBytesAtom(data,0,data.length);
|
||||
assertEquals(data_text, tba.getText());
|
||||
}
|
||||
public void testTextB() throws Exception {
|
||||
TextBytesAtom tba = new TextBytesAtom(alt_data,0,alt_data.length);
|
||||
assertEquals(alt_text, tba.getText());
|
||||
}
|
||||
|
||||
public void testChangeText() throws Exception {
|
||||
TextBytesAtom tba = new TextBytesAtom(data,0,data.length);
|
||||
tba.setText(alt_text.getBytes("ISO-8859-1"));
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
tba.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
// Compare the header and the text
|
||||
assertEquals(alt_data.length, b.length);
|
||||
for(int i=0; i<alt_data.length; i++) {
|
||||
assertEquals(alt_data[i],b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void testWrite() throws Exception {
|
||||
TextBytesAtom tba = new TextBytesAtom(data,0,data.length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
tba.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(data.length, b.length);
|
||||
for(int i=0; i<data.length; i++) {
|
||||
assertEquals(data[i],b[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
/**
|
||||
* Tests that TextCharsAtom works properly
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestTextCharsAtom extends TestCase {
|
||||
// From a real file
|
||||
private byte[] data = new byte[] { 0, 0, 0xA0-256, 0x0f, 0x08, 0, 0, 0,
|
||||
0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00 };
|
||||
private String data_text = "This";
|
||||
private byte[] alt_data = new byte[] { 0, 0, 0xA0-256, 0x0F, 0x0a, 0, 0, 0,
|
||||
0x54, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0xa3-256, 0x01 };
|
||||
private String alt_text = "This\u01A3";
|
||||
|
||||
public void testRecordType() throws Exception {
|
||||
TextCharsAtom tca = new TextCharsAtom(data,0,data.length);
|
||||
assertEquals(4000l, tca.getRecordType());
|
||||
}
|
||||
|
||||
public void testTextA() throws Exception {
|
||||
TextCharsAtom tca = new TextCharsAtom(data,0,data.length);
|
||||
assertEquals(data_text, tca.getText());
|
||||
}
|
||||
public void testTextB() throws Exception {
|
||||
TextCharsAtom tca = new TextCharsAtom(alt_data,0,alt_data.length);
|
||||
assertEquals(alt_text, tca.getText());
|
||||
}
|
||||
|
||||
public void testChangeText() throws Exception {
|
||||
TextCharsAtom tca = new TextCharsAtom(data,0,data.length);
|
||||
tca.setText(alt_text);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
tca.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
// Compare the header and the text
|
||||
assertEquals(alt_data.length, b.length);
|
||||
for(int i=0; i<alt_data.length; i++) {
|
||||
assertEquals(alt_data[i],b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void testWrite() throws Exception {
|
||||
TextCharsAtom tca = new TextCharsAtom(data,0,data.length);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
tca.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(data.length, b.length);
|
||||
for(int i=0; i<data.length; i++) {
|
||||
assertEquals(data[i],b[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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;
|
||||
|
||||
/**
|
||||
* Tests that TextHeaderAtom works properly
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestTextHeaderAtom extends TestCase {
|
||||
// From a real file
|
||||
private byte[] notes_data = new byte[] { 0, 0, 0x9f-256, 0x0f, 4, 0, 0, 0, 2, 0, 0, 0};
|
||||
private byte[] title_data = new byte[] { 0, 0, 0x9f-256, 0x0f, 4, 0, 0, 0, 0, 0, 0, 0 };
|
||||
private byte[] body_data = new byte[] { 0, 0, 0x9f-256, 0x0f, 4, 0, 0, 0, 1, 0, 0, 0 };
|
||||
|
||||
public void testRecordType() throws Exception {
|
||||
TextHeaderAtom tha = new TextHeaderAtom(notes_data,0,12);
|
||||
assertEquals(3999l, tha.getRecordType());
|
||||
}
|
||||
public void testTypes() throws Exception {
|
||||
TextHeaderAtom n_tha = new TextHeaderAtom(notes_data,0,12);
|
||||
TextHeaderAtom t_tha = new TextHeaderAtom(title_data,0,12);
|
||||
TextHeaderAtom b_tha = new TextHeaderAtom(body_data,0,12);
|
||||
assertEquals(TextHeaderAtom.NOTES_TYPE, n_tha.getTextType());
|
||||
assertEquals(TextHeaderAtom.TITLE_TYPE, t_tha.getTextType());
|
||||
assertEquals(TextHeaderAtom.BODY_TYPE, b_tha.getTextType());
|
||||
}
|
||||
|
||||
public void testWrite() throws Exception {
|
||||
TextHeaderAtom tha = new TextHeaderAtom(notes_data,0,12);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
tha.writeOut(baos);
|
||||
byte[] b = baos.toByteArray();
|
||||
|
||||
assertEquals(notes_data.length, b.length);
|
||||
for(int i=0; i<notes_data.length; i++) {
|
||||
assertEquals(notes_data[i],b[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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 junit.framework.TestCase;
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
|
||||
/**
|
||||
* Tests that SlideShow returns the right number of Sheets and MetaSheets
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestCounts extends TestCase {
|
||||
// SlideShow primed on the test data
|
||||
private SlideShow ss;
|
||||
|
||||
public TestCounts() throws Exception {
|
||||
String dirname = System.getProperty("HSLF.testdata.path");
|
||||
String filename = dirname + "/basic_test_ppt_file.ppt";
|
||||
HSLFSlideShow hss = new HSLFSlideShow(filename);
|
||||
ss = new SlideShow(hss);
|
||||
}
|
||||
|
||||
public void testSheetsCount() throws Exception {
|
||||
Slide[] slides = ss.getSlides();
|
||||
// Two sheets, plus some crap related to the master sheet
|
||||
assertEquals(3, slides.length);
|
||||
}
|
||||
|
||||
public void testNotesCount() throws Exception {
|
||||
Notes[] notes = ss.getNotes();
|
||||
// Two sheets -> two notes, plus the notes on the slide master
|
||||
assertEquals(3, notes.length);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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 junit.framework.TestCase;
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
|
||||
/**
|
||||
* Tests that SlideShow returns MetaSheets which have the right text in them
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestNotesText extends TestCase {
|
||||
// SlideShow primed on the test data
|
||||
private SlideShow ss;
|
||||
|
||||
public TestNotesText() throws Exception {
|
||||
String dirname = System.getProperty("HSLF.testdata.path");
|
||||
String filename = dirname + "/basic_test_ppt_file.ppt";
|
||||
HSLFSlideShow hss = new HSLFSlideShow(filename);
|
||||
ss = new SlideShow(hss);
|
||||
}
|
||||
|
||||
public void testNotesOne() throws Exception {
|
||||
Notes notes = ss.getNotes()[1];
|
||||
|
||||
String[] expectText = new String[] {"These are the notes for page 1"};
|
||||
assertEquals(expectText.length, notes.getTextRuns().length);
|
||||
for(int i=0; i<expectText.length; i++) {
|
||||
assertEquals(expectText[i], notes.getTextRuns()[i].getText());
|
||||
}
|
||||
}
|
||||
|
||||
public void testNotesTwo() throws Exception {
|
||||
Notes notes = ss.getNotes()[2];
|
||||
String[] expectText = new String[] {"These are the notes on page two, again lacking formatting"};
|
||||
assertEquals(expectText.length, notes.getTextRuns().length);
|
||||
for(int i=0; i<expectText.length; i++) {
|
||||
assertEquals(expectText[i], notes.getTextRuns()[i].getText());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
/* ====================================================================
|
||||
Copyright 2002-2004 Apache Software Foundation
|
||||
|
||||
Licensed 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 junit.framework.TestCase;
|
||||
import org.apache.poi.hslf.*;
|
||||
import org.apache.poi.hslf.model.*;
|
||||
|
||||
/**
|
||||
* Tests that SlideShow returns Sheets which have the right text in them
|
||||
*
|
||||
* @author Nick Burch (nick at torchbox dot com)
|
||||
*/
|
||||
public class TestSheetText extends TestCase {
|
||||
// SlideShow primed on the test data
|
||||
private SlideShow ss;
|
||||
|
||||
public TestSheetText() throws Exception {
|
||||
String dirname = System.getProperty("HSLF.testdata.path");
|
||||
String filename = dirname + "/basic_test_ppt_file.ppt";
|
||||
HSLFSlideShow hss = new HSLFSlideShow(filename);
|
||||
ss = new SlideShow(hss);
|
||||
}
|
||||
|
||||
public void testSheetOne() throws Exception {
|
||||
Sheet slideOne = ss.getSlides()[0];
|
||||
|
||||
String[] expectText = new String[] {"This is a test title","This is a test subtitle\nThis is on page 1"};
|
||||
assertEquals(expectText.length, slideOne.getTextRuns().length);
|
||||
for(int i=0; i<expectText.length; i++) {
|
||||
assertEquals(expectText[i], slideOne.getTextRuns()[i].getText());
|
||||
}
|
||||
}
|
||||
|
||||
public void testSheetTwo() throws Exception {
|
||||
Sheet slideTwo = ss.getSlides()[1];
|
||||
String[] expectText = new String[] {"This is the title on page 2","This is page two\nIt has several blocks of text\nNone of them have formatting"};
|
||||
assertEquals(expectText.length, slideTwo.getTextRuns().length);
|
||||
for(int i=0; i<expectText.length; i++) {
|
||||
assertEquals(expectText[i], slideTwo.getTextRuns()[i].getText());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue