2007-07-18 13:00:14 -04:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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 ;
2008-03-07 06:36:14 -05:00
import org.apache.poi.util.POILogFactory ;
import org.apache.poi.util.POILogger ;
2007-07-18 13:00:14 -04:00
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 {
2008-03-07 06:36:14 -05:00
private static POILogger logger = POILogFactory . getLogger ( FileSharingRecord . class ) ;
2007-07-18 13:00:14 -04:00
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 ( ) ;
2008-03-07 06:36:14 -05:00
// Is this really correct? The latest docs
// seem to hint there's nothing between the
// username length and the username string
2007-07-18 13:00:14 -04:00
field_4_unknown = in . readShort ( ) ;
2008-03-07 06:36:14 -05:00
// Ensure we don't try to read more data than
// there actually is
if ( field_3_username_length > in . remaining ( ) ) {
logger . log ( POILogger . WARN , " FileSharingRecord defined a username of length " + field_3_username_length + " , but only " + in . remaining ( ) + " bytes were left, truncating " ) ;
field_3_username_length = ( byte ) in . remaining ( ) ;
}
if ( field_3_username_length > 0 ) {
field_5_username = in . readCompressedUnicode ( field_3_username_length ) ;
} else {
field_5_username = " " ;
}
2007-07-18 13:00:14 -04:00
}
//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 ;
}
}