Support for creating new HSLF CurrentUserAtoms

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@680853 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-07-29 21:40:47 +00:00
parent 7fd95e217f
commit d5020af75e
4 changed files with 156 additions and 18 deletions

View File

@ -37,6 +37,7 @@
<!-- Don't forget to update status.xml too! -->
<release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>
<action dev="POI-DEVELOPERS" type="add">45466 - Partial support for removing excel comments (won't work for all excel versions yet)</action>
<action dev="POI-DEVELOPERS" type="fix">45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM</action>
<action dev="POI-DEVELOPERS" type="add">45404 - New class, hssf.usermodel.HSSFDataFormatter, for formatting numbers and dates in the same way that Excel does</action>

View File

@ -34,6 +34,7 @@
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.1.1-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="add">Support for creating new HSLF CurrentUserAtoms</action>
<action dev="POI-DEVELOPERS" type="add">45466 - Partial support for removing excel comments (won't work for all excel versions yet)</action>
<action dev="POI-DEVELOPERS" type="fix">45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM</action>
<action dev="POI-DEVELOPERS" type="add">45404 - New class, hssf.usermodel.HSSFDataFormatter, for formatting numbers and dates in the same way that Excel does</action>

View File

@ -25,6 +25,7 @@ import org.apache.poi.poifs.filesystem.*;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException;
/**
@ -39,14 +40,15 @@ 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 magic number for a non-encrypted file */
public static final byte[] headerToken = new byte[] { 95, -64, -111, -29 };
/** The PowerPoint magic number for an encrytpted file */
public static final byte[] encHeaderToken = new byte[] { -33, -60, -47, -13 };
/** 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 int docFinalVersion;
private byte docMajorNo;
private byte docMinorNo;
@ -54,7 +56,7 @@ public class CurrentUserAtom
private long currentEditOffset;
/** The Username of the last person to edit the file */
private String lastEditUser;
/** The document release version */
/** The document release version. Almost always 8 */
private long releaseVersion;
/** Only correct after reading in or writing out */
@ -63,8 +65,7 @@ public class CurrentUserAtom
/* ********************* getter/setter follows *********************** */
public int getDocFinalVersionA() { return docFinalVersionA; }
public int getDocFinalVersionB() { return docFinalVersionB; }
public int getDocFinalVersion() { return docFinalVersion; }
public byte getDocMajorNo() { return docMajorNo; }
public byte getDocMinorNo() { return docMinorNo; }
@ -86,7 +87,14 @@ public class CurrentUserAtom
*/
public CurrentUserAtom() {
_contents = new byte[0];
throw new RuntimeException("Creation support for Current User Atom not complete");
// Initialise to empty
docFinalVersion = 0x03f4;
docMajorNo = 3;
docMinorNo = 0;
releaseVersion = 8;
currentEditOffset = 0;
lastEditUser = "Apache POI";
}
/**
@ -130,12 +138,20 @@ public class CurrentUserAtom
* Actually do the creation from a block of bytes
*/
private void init() {
// First up is the size, in 4 bytes, which is fixed
// Then is the header - check for encrypted
if(_contents[12] == encHeaderToken[0] &&
_contents[13] == encHeaderToken[1] &&
_contents[14] == encHeaderToken[2] &&
_contents[15] == encHeaderToken[3]) {
throw new EncryptedPowerPointFileException("The CurrentUserAtom specifies that the document is encrypted");
}
// Grab the edit offset
currentEditOffset = LittleEndian.getUInt(_contents,16);
// Grab the versions
docFinalVersionA = LittleEndian.getUShort(_contents,20);
docFinalVersionB = LittleEndian.getUShort(_contents,22);
docFinalVersion = LittleEndian.getUShort(_contents,22);
docMajorNo = _contents[24];
docMinorNo = _contents[25];
@ -194,15 +210,22 @@ public class CurrentUserAtom
// 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 ppt un-encrypted header token (4 bytes)
System.arraycopy(headerToken,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);
// The username gets stored twice, once as US
// ascii, and again as unicode laster on
byte[] asciiUN = new byte[lastEditUser.length()];
StringUtil.putCompressedUnicode(lastEditUser,asciiUN,0);
// Now we're able to do the length of the last edited user
LittleEndian.putShort(_contents,20,(short)asciiUN.length);
// Now the file versions, 2+1+1
LittleEndian.putShort(_contents,22,(short)docFinalVersion);
_contents[24] = docMajorNo;
_contents[25] = docMinorNo;
@ -210,9 +233,7 @@ public class CurrentUserAtom
_contents[26] = 0;
_contents[27] = 0;
// username in bytes in us ascii
byte[] asciiUN = new byte[lastEditUser.length()];
StringUtil.putCompressedUnicode(lastEditUser,asciiUN,0);
// At this point we have the username as us ascii
System.arraycopy(asciiUN,0,_contents,28,asciiUN.length);
// 4 byte release version

View File

@ -0,0 +1,115 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.imageio.stream.FileImageInputStream;
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/**
* Tests that CurrentUserAtom works properly.
*
* @author Nick Burch (nick at torchbox dot com)
*/
public class TestCurrentUserAtom extends TestCase {
/** Not encrypted */
private String normalFile;
/** Encrypted */
private String encFile;
protected void setUp() throws Exception {
super.setUp();
String dirname = System.getProperty("HSLF.testdata.path");
normalFile = dirname + "/basic_test_ppt_file.ppt";
encFile = dirname + "/Password_Protected-hello.ppt";
}
public void testReadNormal() throws Exception {
POIFSFileSystem fs = new POIFSFileSystem(
new FileInputStream(normalFile)
);
CurrentUserAtom cu = new CurrentUserAtom(fs);
// Check the contents
assertEquals("Hogwarts", cu.getLastEditUsername());
assertEquals(0x2942, cu.getCurrentEditOffset());
// Round trip
ByteArrayOutputStream baos = new ByteArrayOutputStream();
cu.writeOut(baos);
CurrentUserAtom cu2 = new CurrentUserAtom(baos.toByteArray());
assertEquals("Hogwarts", cu2.getLastEditUsername());
assertEquals(0x2942, cu2.getCurrentEditOffset());
}
public void testReadEnc() throws Exception {
POIFSFileSystem fs = new POIFSFileSystem(
new FileInputStream(encFile)
);
try {
new CurrentUserAtom(fs);
fail();
} catch(EncryptedPowerPointFileException e) {
// Good
}
}
public void testWriteNormal() throws Exception {
// Get raw contents from a known file
POIFSFileSystem fs = new POIFSFileSystem(
new FileInputStream(normalFile)
);
DocumentEntry docProps = (DocumentEntry)fs.getRoot().getEntry("Current User");
byte[] contents = new byte[docProps.getSize()];
InputStream in = fs.getRoot().createDocumentInputStream("Current User");
in.read(contents);
// Now build up a new one
CurrentUserAtom cu = new CurrentUserAtom();
cu.setLastEditUsername("Hogwarts");
cu.setCurrentEditOffset(0x2942);
// Check it matches
ByteArrayOutputStream baos = new ByteArrayOutputStream();
cu.writeOut(baos);
byte[] out = baos.toByteArray();
assertEquals(contents.length, out.length);
for(int i=0; i<contents.length; i++) {
assertEquals("Byte " + i, contents[i], out[i]);
}
}
}