protected ProtectRecord protect = null;
protected PageBreakRecord rowBreaks = null;
protected PageBreakRecord colBreaks = null;
+ protected ObjectProtectRecord objprotect = null;
+ protected ScenarioProtectRecord scenprotect = null;
+ protected PasswordRecord password = null;
public static final byte PANE_LOWER_RIGHT = (byte)0;
{
retval.protect = (ProtectRecord) rec;
}
+ else if ( rec.getSid() == ObjectProtectRecord.sid )
+ {
+ retval.objprotect = (ObjectProtectRecord) rec;
+ }
+ else if ( rec.getSid() == ScenarioProtectRecord.sid )
+ {
+ retval.scenprotect = (ScenarioProtectRecord) rec;
+ }
+ else if ( rec.getSid() == PasswordRecord.sid )
+ {
+ retval.password = (PasswordRecord) rec;
+ }
else if (rec.getSid() == PageBreakRecord.HORIZONTAL_SID)
{
retval.rowBreaks = (PageBreakRecord)rec;
ProtectRecord retval = new ProtectRecord();
retval.setProtect(false);
- // by default even when we support encryption we won't
+ return retval;
+ }
+
+ /**
+ * creates an ObjectProtect record with protect set to false.
+ * @see org.apache.poi.hssf.record.ObjectProtectRecord
+ * @see org.apache.poi.hssf.record.Record
+ * @return an ObjectProtectRecord
+ */
+ protected ObjectProtectRecord createObjectProtect()
+ {
+ if (log.check( POILogger.DEBUG ))
+ log.log(POILogger.DEBUG, "create protect record with protection disabled");
+ ObjectProtectRecord retval = new ObjectProtectRecord();
+
+ retval.setProtect(false);
+ return retval;
+ }
+
+ /**
+ * creates a ScenarioProtect record with protect set to false.
+ * @see org.apache.poi.hssf.record.ScenarioProtectRecord
+ * @see org.apache.poi.hssf.record.Record
+ * @return a ScenarioProtectRecord
+ */
+ protected ScenarioProtectRecord createScenarioProtect()
+ {
+ if (log.check( POILogger.DEBUG ))
+ log.log(POILogger.DEBUG, "create protect record with protection disabled");
+ ScenarioProtectRecord retval = new ScenarioProtectRecord();
+
+ retval.setProtect(false);
return retval;
}
return protect;
}
+ /** Returns the PasswordRecord.
+ * If one is not contained in the sheet, then one is created.
+ */
+ public PasswordRecord getPassword()
+ {
+ if (password == null) {
+ password = createPassword();
+ //Insert the newly created password record at the end of the record (just before the EOF)
+ int loc = findFirstRecordLocBySid(EOFRecord.sid);
+ records.add(loc, password);
+ }
+ return password;
+ }
+
+ /**
+ * creates a Password record with password set to 00.
+ * @see org.apache.poi.hssf.record.PasswordRecord
+ * @see org.apache.poi.hssf.record.Record
+ * @return a PasswordRecord
+ */
+ protected PasswordRecord createPassword()
+ {
+ if (log.check( POILogger.DEBUG ))
+ log.log(POILogger.DEBUG, "create password record with 00 password");
+ PasswordRecord retval = new PasswordRecord();
+
+ retval.setPassword((short)00);
+ return retval;
+ }
+
+ /**
+
/**
* Sets whether the gridlines are shown in a viewer.
* @param show whether to show gridlines or not
}
}
+ /**
+ * protect a spreadsheet with a password (not encypted, just sets protect
+ * flags and the password.
+ * @param password to set
+ * @param objects are protected
+ * @param scenarios are protected
+ */
+ public void protectSheet( String password, boolean objects, boolean scenarios ) {
+ int protIdx = -1;
+ ProtectRecord prec = getProtect();
+ PasswordRecord pass = getPassword();
+ prec.setProtect(true);
+ pass.setPassword(PasswordRecord.hashPassword(password));
+ if((objprotect == null && objects) || (scenprotect != null && scenarios)) {
+ protIdx = records.indexOf( protect );
+ }
+ if(objprotect == null && objects) {
+ ObjectProtectRecord rec = createObjectProtect();
+ rec.setProtect(true);
+ records.add(protIdx+1,rec);
+ objprotect = rec;
+ }
+ if(scenprotect == null && scenarios) {
+ ScenarioProtectRecord srec = createScenarioProtect();
+ srec.setProtect(true);
+ records.add(protIdx+2,srec);
+ scenprotect = srec;
+ }
+ }
+
+ /**
+ * unprotect objects in the sheet (will not protect them, but any set to false are
+ * unprotected.
+ * @param sheet is unprotected (false = unprotect)
+ * @param objects are unprotected (false = unprotect)
+ * @param scenarios are unprotected (false = unprotect)
+ */
+ public void unprotectSheet( boolean sheet, boolean objects, boolean scenarios ) {
+ int protIdx = -1;
+ if (!sheet) {
+ ProtectRecord prec = getProtect();
+ prec.setProtect(sheet);
+ PasswordRecord pass = getPassword();
+ pass.setPassword((short)00);
+ }
+ if(objprotect != null && !objects) {
+ objprotect.setProtect(false);
+ }
+ if(scenprotect != null && !scenarios) {
+ scenprotect.setProtect(false);
+ }
+ }
+
+ /**
+ * @return {sheet is protected, objects are proteced, scenarios are protected}
+ */
+ public boolean[] isProtected() {
+ return new boolean[] { (protect != null && protect.getProtect()),
+ (objprotect != null && objprotect.getProtect()),
+ (scenprotect != null && scenprotect.getProtect())};
+ }
+
// private void collapseColumn( short columnNumber )
// {
// int idx = findColumnIdx( columnNumber, 0 );
* @version 2.0-pre
*/
-public class PasswordRecord
- extends Record
-{
+public class PasswordRecord extends Record {
public final static short sid = 0x13;
private short field_1_password; // not sure why this is only 2 bytes, but it is... go figure
- public PasswordRecord()
- {
+ public PasswordRecord() {
}
/**
* @param in the RecordInputstream to read the record from
*/
- public PasswordRecord(RecordInputStream in)
- {
+ public PasswordRecord(RecordInputStream in) {
super(in);
}
- protected void validateSid(short id)
- {
- if (id != sid)
- {
+ protected void validateSid(short id) {
+ if (id != sid) {
throw new RecordFormatException("NOT A PASSWORD RECORD");
}
}
- protected void fillFields(RecordInputStream in)
- {
+ protected void fillFields(RecordInputStream in) {
field_1_password = in.readShort();
}
+ //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 password
*
* @param password representing the password
*/
- public void setPassword(short password)
- {
+ public void setPassword(short password) {
field_1_password = password;
}
*
* @return short representing the password
*/
-
- public short getPassword()
- {
+ public short getPassword() {
return field_1_password;
}
- public String toString()
- {
+ public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("[PASSWORD]\n");
return buffer.toString();
}
- public int serialize(int offset, byte [] data)
- {
+ public int serialize(int offset, byte [] data) {
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset,
(( short ) 0x02)); // 2 bytes (6 total)
return getRecordSize();
}
- public int getRecordSize()
- {
+ public int getRecordSize() {
return 6;
}
- public short getSid()
- {
+ public short getSid() {
return sid;
}
* Description: defines whether a sheet or workbook is protected (HSSF DOES NOT SUPPORT ENCRYPTION)<P>
* (kindly ask the US government to stop having arcane stupid encryption laws and we'll support it) <P>
* (after all terrorists will all use US-legal encrypton right??)<P>
+ * HSSF now supports the simple "protected" sheets (where they are not encrypted and open office et al
+ * ignore the password record entirely).
* REFERENCE: PG 373 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org)
- * @version 2.0-pre
*/
public class ProtectRecord
PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class,
HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class,
WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class,
- NoteRecord.class
+ NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class
};
}
private static Map recordsMap = recordsToMap(records);
* @return true => protection enabled; false => protection disabled
*/
public boolean getProtect() {
- return getSheet().getProtect().getProtect();
+ return getSheet().isProtected()[0];
+ }
+
+ /**
+ * @return hashed password
+ */
+ public short getPassword() {
+ return getSheet().getPassword().getPassword();
+ }
+
+ /**
+ * Answer whether object protection is enabled or disabled
+ * @return true => protection enabled; false => protection disabled
+ */
+ public boolean getObjectProtect() {
+ return getSheet().isProtected()[1];
+ }
+
+ /**
+ * Answer whether scenario protection is enabled or disabled
+ * @return true => protection enabled; false => protection disabled
+ */
+ public boolean getScenarioProtect() {
+ return getSheet().isProtected()[2];
}
/**
* Sets the protection on enabled or disabled
* @param protect true => protection enabled; false => protection disabled
+ * @deprecated use protectSheet(String, boolean, boolean)
*/
public void setProtect(boolean protect) {
getSheet().getProtect().setProtect(protect);
}
+ /**
+ * Sets the protection enabled as well as the password
+ * @param password to set for protection
+ */
+ public void protectSheet(String password) {
+ getSheet().protectSheet(password, true, true); //protect objs&scenarios(normal)
+ }
+
/**
* Sets the zoom magnication for the sheet. The zoom is expressed as a
* fraction. For example to express a zoom of 75% use 3 for the numerator
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.record.HCenterRecord;
import org.apache.poi.hssf.record.ProtectRecord;
+import org.apache.poi.hssf.record.PasswordRecord;
import org.apache.poi.hssf.record.SCLRecord;
import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.WSBoolRecord;
*
*
* @author Glen Stampoultzis (glens at apache.org)
+ * @author Andrew C. Oliver (acoliver apache org)
*/
public class TestHSSFSheet
assertTrue(hssfSheet.getProtect());
}
+ public void testProtectSheet() {
+ short expected = (short)0xfef1;
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet s = wb.createSheet();
+ s.protectSheet("abcdefghij");
+ Sheet sheet = s.getSheet();
+ ProtectRecord protect = sheet.getProtect();
+ PasswordRecord pass = sheet.getPassword();
+ assertTrue("protection should be on",protect.getProtect());
+ assertTrue("object protection should be on",sheet.isProtected()[1]);
+ assertTrue("scenario protection should be on",sheet.isProtected()[2]);
+ assertEquals("well known value for top secret hash should be "+Integer.toHexString(expected).substring(4),expected,pass.getPassword());
+ }
+
public void testZoom()
throws Exception