]> source.dussan.org Git - poi.git/commitdiff
you can now protect files with writeProtectWorkbook
authorAndrew C. Oliver <acoliver@apache.org>
Wed, 18 Jul 2007 17:00:14 +0000 (17:00 +0000)
committerAndrew C. Oliver <acoliver@apache.org>
Wed, 18 Jul 2007 17:00:14 +0000 (17:00 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@557333 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/dev/BiffViewer.java
src/java/org/apache/poi/hssf/model/Workbook.java
src/java/org/apache/poi/hssf/model/WorkbookRecordList.java
src/java/org/apache/poi/hssf/record/FileSharingRecord.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/RecordFactory.java
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java

index 2d5f02bebc69b2e45830d609a7d364dc1d91cef1..2e343012d469597558c90dd90eab7ba64af797e8 100644 (file)
@@ -512,6 +512,9 @@ public class BiffViewer {
             case NoteRecord.sid:
                 retval = new NoteRecord( in );
                 break;
+            case FileSharingRecord.sid:
+                retval = new FileSharingRecord( in );
+                break;
             default:
                 retval = new UnknownRecord( in );
         }
index 5071735b6043a2b5baa2dbdfb9059986f97b201f..28970820d9bdd4e0b4441523ad7ab802209c4ce1 100644 (file)
@@ -44,13 +44,13 @@ import java.util.Locale;
  * before even attempting to use this.
  *
  *
+ * @author  Luc Girardin (luc dot girardin at macrofocus dot com)
+ * @author  Sergei Kozello (sergeikozello at mail.ru)
  * @author  Shawn Laubach (slaubach at apache dot org) (Data Formats)
  * @author  Andrew C. Oliver (acoliver at apache dot org)
- * @author  Glen Stampoultzis (glens at apache.org)
- * @author  Sergei Kozello (sergeikozello at mail.ru)
- * @author  Luc Girardin (luc dot girardin at macrofocus dot com)
- * @author  Dan Sherman (dsherman at isisph.com)
  * @author  Brian Sanders (bsanders at risklabs dot com) - custom palette
+ * @author  Dan Sherman (dsherman at isisph.com)
+ * @author  Glen Stampoultzis (glens at apache.org)
  * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
  * @version 1.0-pre
  */
@@ -101,6 +101,9 @@ public class Workbook implements Model
     private DrawingManager2    drawingManager;
     private List               escherBSERecords = new ArrayList();  // EscherBSERecord
     private WindowOneRecord windowOne;
+    private FileSharingRecord fileShare;
+    private WriteAccessRecord writeAccess;
+    private WriteProtectRecord writeProtect;
 
     private static POILogger   log = POILogFactory.getLogger(Workbook.class);
 
@@ -220,7 +223,22 @@ public class Workbook implements Model
                 case WindowOneRecord.sid:
                     if (log.check( POILogger.DEBUG ))
                         log.log(DEBUG, "found WindowOneRecord at " + k);
-                    retval.windowOne = (WindowOneRecord) rec;
+                    retval.windowOne = (WindowOneRecord) rec; 
+                    break;
+                case WriteAccessRecord.sid: 
+                    if (log.check( POILogger.DEBUG ))
+                        log.log(DEBUG, "found WriteAccess at " + k);
+                    retval.writeAccess = (WriteAccessRecord) rec;
+                    break;
+                case WriteProtectRecord.sid: 
+                    if (log.check( POILogger.DEBUG ))
+                        log.log(DEBUG, "found WriteProtect at " + k);
+                    retval.writeProtect = (WriteProtectRecord) rec;
+                    break;
+                case FileSharingRecord.sid: 
+                    if (log.check( POILogger.DEBUG ))
+                        log.log(DEBUG, "found FileSharing at " + k);
+                    retval.fileShare = (FileSharingRecord) rec;
                 default :
             }
             records.add(rec);
@@ -2235,5 +2253,70 @@ public class Workbook implements Model
         return drawingManager;
     }
 
+    public WriteProtectRecord getWriteProtect() {
+        if (this.writeProtect == null) {
+           this.writeProtect = new WriteProtectRecord();
+           int i = 0;
+           for (i = 0; 
+                i < records.size() && !(records.get(i) instanceof BOFRecord); 
+                i++) {
+           }
+           records.add(i+1,this.writeProtect);
+        }
+        return this.writeProtect;
+    }
+
+    public WriteAccessRecord getWriteAccess() {
+        if (this.writeAccess == null) {
+           this.writeAccess = (WriteAccessRecord)createWriteAccess();
+           int i = 0;
+           for (i = 0; 
+                i < records.size() && !(records.get(i) instanceof InterfaceEndRecord); 
+                i++) {
+           }
+           records.add(i+1,this.writeAccess);
+        }
+        return this.writeAccess;
+    }
+
+    public FileSharingRecord getFileSharing() {
+        if (this.fileShare == null) {
+           this.fileShare = new FileSharingRecord();
+           int i = 0;
+           for (i = 0; 
+                i < records.size() && !(records.get(i) instanceof WriteAccessRecord); 
+                i++) {
+           }
+           records.add(i+1,this.fileShare);
+        }
+        return this.fileShare;
+    }
+
+    /**
+     * protect a workbook with a password (not encypted, just sets writeprotect
+     * flags and the password.
+     * @param password to set
+     */
+    public void writeProtectWorkbook( String password, String username ) {
+        int protIdx = -1;
+        FileSharingRecord frec = getFileSharing();
+        WriteAccessRecord waccess = getWriteAccess();
+        WriteProtectRecord wprotect = getWriteProtect();
+        frec.setReadOnly((short)1);
+        frec.setPassword(FileSharingRecord.hashPassword(password));
+        frec.setUsername(username);
+        waccess.setUsername(username);
+    }
+
+    /**
+     * removes the write protect flag
+     */
+    public void unwriteProtectWorkbook() {
+        records.remove(fileShare);
+        records.remove(writeProtect);
+        fileShare = null;
+        writeProtect = null;
+    }
+
 }
 
index e9e0b88536267a4394444ac29eac028735ca9489..60d0081aa4798eebafeb4fbff342be6c52f43669 100644 (file)
@@ -79,6 +79,11 @@ public class WorkbookRecordList
         return records.iterator();
     }
 
+    public void remove( Object record ) {
+       int i = records.indexOf(record);
+       this.remove(i);
+    }
+
     public void remove( int pos )
     {
         records.remove(pos);
diff --git a/src/java/org/apache/poi/hssf/record/FileSharingRecord.java b/src/java/org/apache/poi/hssf/record/FileSharingRecord.java
new file mode 100644 (file)
index 0000000..17f8cda
--- /dev/null
@@ -0,0 +1,209 @@
+/* ====================================================================
+   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.hssf.record;
+
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.StringUtil;
+
+/**
+ * Title:        FileSharing<P>
+ * Description:  stores the encrypted readonly for a workbook (write protect) 
+ * REFERENCE:  PG 314 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
+ * @author Andrew C. Oliver (acoliver at apache dot org)
+ */
+
+public class FileSharingRecord extends Record {
+    public final static short sid = 0x5b;
+    private short             field_1_readonly;
+    private short             field_2_password;
+    private byte              field_3_username_length;
+    private short             field_4_unknown; // not documented
+    private String            field_5_username;
+
+    public FileSharingRecord() {}
+    
+
+    /**
+     * Constructs a FileSharing record and sets its fields appropriately.
+     * @param in the RecordInputstream to read the record from
+     */
+
+    public FileSharingRecord(RecordInputStream in) {
+        super(in);
+    }
+
+    protected void validateSid(short id) {
+        if (id != sid) {
+            throw new RecordFormatException("NOT A FILESHARING RECORD");
+        }
+    }
+
+    protected void fillFields(RecordInputStream in) {
+        field_1_readonly = in.readShort();
+        field_2_password = in.readShort();
+        field_3_username_length = in.readByte();
+        field_4_unknown = in.readShort();
+        field_5_username = in.readCompressedUnicode(field_3_username_length);
+    }
+
+    //this is the world's lamest "security".  thanks to Wouter van Vugt for making me
+    //not have to try real hard.  -ACO
+    public static short hashPassword(String password) {
+        byte[] passwordCharacters = password.getBytes();
+        int hash = 0;
+        if (passwordCharacters.length > 0) {
+            int charIndex = passwordCharacters.length;
+            while (charIndex-- > 0) {
+                hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
+                hash ^= passwordCharacters[charIndex];
+            }
+            // also hash with charcount
+            hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
+            hash ^= passwordCharacters.length;
+            hash ^= (0x8000 | ('N' << 8) | 'K');
+        }
+        return (short)hash;
+    } 
+
+    /**
+     * set the readonly flag
+     *
+     * @param readonly 1 for true, not 1 for false
+     */
+    public void setReadOnly(short readonly) {
+        field_1_readonly = readonly;
+    }
+
+    /**
+     * get the readonly
+     *
+     * @return short  representing if this is read only (1 = true)
+     */
+    public short getReadOnly() {
+        return field_1_readonly;
+    }
+
+    /**
+     * @param hashed password
+     */
+    public void setPassword(short password) {
+        field_2_password = password;
+    }
+
+    /**
+     * @returns password hashed with hashPassword() (very lame)
+     */
+    public short getPassword() {
+        return field_2_password;
+    }
+
+    /**
+     * @returns byte representing the length of the username field
+     */
+    public byte getUsernameLength() {
+        return field_3_username_length ;
+    }
+
+    /**
+     * @param byte representing the length of the username field
+     */
+    public void setUsernameLength(byte length) {
+        this.field_3_username_length = length;
+    }
+
+    /**
+     * @returns username of the user that created the file
+     */
+    public String getUsername() {
+        return this.field_5_username;
+    }
+
+    /**
+     * @param username of the user that created the file
+     */
+    public void setUsername(String username) {
+        this.field_5_username = username;
+        this.field_3_username_length = (byte)username.length();
+    }
+
+    /**
+     * @return short value of a "bonus field" in Excel that was not doc'd
+     */
+    public short getUnknown() {
+        return field_4_unknown;
+    }
+
+    /**
+     * @param unknown field value to set (bonus field that is not doc'd)
+     */
+    public void setUnknown(short unk) {
+        field_4_unknown = unk;
+    }
+
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[FILESHARING]\n");
+        buffer.append("    .readonly       = ")
+            .append(getReadOnly() == 1 ? "true" : "false").append("\n");
+        buffer.append("    .password       = ")
+            .append(Integer.toHexString(getPassword())).append("\n");
+        buffer.append("    .userlen        = ")
+            .append(Integer.toHexString(getUsernameLength())).append("\n");
+        buffer.append("    .unknown        = ")
+            .append(Integer.toHexString(getUnknown())).append("\n");
+        buffer.append("    .username       = ")
+            .append(getUsername()).append("\n");
+        buffer.append("[/FILESHARING]\n");
+        return buffer.toString();
+    }
+
+    public int serialize(int offset, byte [] data) {
+        LittleEndian.putShort(data, 0 + offset, sid);
+        LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize()-4));
+        LittleEndian.putShort(data, 4 + offset, getReadOnly());
+        LittleEndian.putShort(data, 6 + offset, getPassword());
+        data[ 8 + offset ] =  getUsernameLength();
+        LittleEndian.putShort(data, 9 + offset, getUnknown());
+        StringUtil.putCompressedUnicode( getUsername(), data, 11 + offset );
+        return getRecordSize();
+    }
+
+    public int getRecordSize() {
+        return 11+getUsernameLength();
+    }
+
+    public short getSid() {
+        return sid;
+    }
+
+    /**
+     * Clone this record.
+     */
+    public Object clone() {
+      FileSharingRecord clone = new FileSharingRecord();
+      clone.setReadOnly(field_1_readonly);
+      clone.setPassword(field_2_password);
+      clone.setUsernameLength(field_3_username_length);
+      clone.setUnknown(field_4_unknown);
+      clone.setUsername(field_5_username);
+      return clone;
+    }
+
+}
index 48b0d3fd8ae55da5f1c084f4e020875f3b53edc8..8f78212616ac3edde4ab1c75a529ff3b05b814c4 100644 (file)
@@ -74,7 +74,7 @@ public class RecordFactory
                 PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class,
                 HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class, 
                 WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class,
-                NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class
+                NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class, FileSharingRecord.class
             };
     }
     private static Map           recordsMap  = recordsToMap(records);
index f051790018659d8325f323cd847916f3b8e1795c..a50d890bb42a23c209d948c146ee930d60405dea 100644 (file)
@@ -1372,6 +1372,22 @@ public class HSSFWorkbook
         }
     }
 
+    /**
+     * protect a workbook with a password (not encypted, just sets writeprotect
+     * flags and the password.
+     * @param password to set
+     */
+    public void writeProtectWorkbook( String password, String username ) {
+       this.workbook.writeProtectWorkbook(password, username);
+    }
+
+    /**
+     * removes the write protect flag
+     */
+    public void unwriteProtectWorkbook() {
+       this.workbook.unwriteProtectWorkbook();
+    }
+
     private byte[] newUID()
     {
         byte[] bytes = new byte[16];