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:
parent
7fd95e217f
commit
d5020af75e
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user