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;
/**
{
/** 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;
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 */
/* ********************* 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; }
*/
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";
}
/**
* 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];
// 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;
_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
--- /dev/null
+
+/* ====================================================================
+ 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]);
+ }
+ }
+}