]> source.dussan.org Git - poi.git/commitdiff
Support for creating new HSLF CurrentUserAtoms
authorNick Burch <nick@apache.org>
Tue, 29 Jul 2008 21:40:47 +0000 (21:40 +0000)
committerNick Burch <nick@apache.org>
Tue, 29 Jul 2008 21:40:47 +0000 (21:40 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@680853 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/scratchpad/src/org/apache/poi/hslf/record/CurrentUserAtom.java
src/scratchpad/testcases/org/apache/poi/hslf/record/TestCurrentUserAtom.java [new file with mode: 0644]

index c1424c4d0497a4a187b4e1c31e52b3e78ee4b0b7..12763c3d3db5af03ac9f0878017bd7a9d3426317 100644 (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>
index 8d8f567674f15f0dd0d52f97c40a6448b382fb93..230244190c19133914b5decf4031c4e6cbeca02c 100644 (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>
index e0810dbca1d9bdd80f5e7797002c28565a28e44b..fb669b38ead748710de7a5b14eafc2e0d6541d6e 100644 (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
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestCurrentUserAtom.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestCurrentUserAtom.java
new file mode 100644 (file)
index 0000000..e92998e
--- /dev/null
@@ -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]);
+               }
+       }
+}