| /* ==================================================================== |
| 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.aggregates; |
| |
| import org.apache.poi.hssf.model.RecordStream; |
| import org.apache.poi.hssf.record.ObjectProtectRecord; |
| import org.apache.poi.hssf.record.PasswordRecord; |
| import org.apache.poi.hssf.record.ProtectRecord; |
| import org.apache.poi.hssf.record.Record; |
| import org.apache.poi.hssf.record.ScenarioProtectRecord; |
| import org.apache.poi.poifs.crypt.CryptoFunctions; |
| import org.apache.poi.util.RecordFormatException; |
| |
| /** |
| * Groups the sheet protection records for a worksheet. |
| * <p> |
| * |
| * See OOO excelfileformat.pdf sec 4.18.2 'Sheet Protection in a Workbook |
| * (BIFF5-BIFF8)' |
| * |
| * @author Josh Micich |
| */ |
| public final class WorksheetProtectionBlock extends RecordAggregate { |
| // Every one of these component records is optional |
| // (The whole WorksheetProtectionBlock may not be present) |
| private ProtectRecord _protectRecord; |
| private ObjectProtectRecord _objectProtectRecord; |
| private ScenarioProtectRecord _scenarioProtectRecord; |
| private PasswordRecord _passwordRecord; |
| |
| /** |
| * Creates an empty WorksheetProtectionBlock |
| */ |
| public WorksheetProtectionBlock() { |
| // all fields empty |
| } |
| |
| /** |
| * @return <code>true</code> if the specified Record sid is one belonging to |
| * the 'Page Settings Block'. |
| */ |
| public static boolean isComponentRecord(int sid) { |
| switch (sid) { |
| case ProtectRecord.sid: |
| case ObjectProtectRecord.sid: |
| case ScenarioProtectRecord.sid: |
| case PasswordRecord.sid: |
| return true; |
| } |
| return false; |
| } |
| |
| private boolean readARecord(RecordStream rs) { |
| switch (rs.peekNextSid()) { |
| case ProtectRecord.sid: |
| checkNotPresent(_protectRecord); |
| _protectRecord = (ProtectRecord) rs.getNext(); |
| break; |
| case ObjectProtectRecord.sid: |
| checkNotPresent(_objectProtectRecord); |
| _objectProtectRecord = (ObjectProtectRecord) rs.getNext(); |
| break; |
| case ScenarioProtectRecord.sid: |
| checkNotPresent(_scenarioProtectRecord); |
| _scenarioProtectRecord = (ScenarioProtectRecord) rs.getNext(); |
| break; |
| case PasswordRecord.sid: |
| checkNotPresent(_passwordRecord); |
| _passwordRecord = (PasswordRecord) rs.getNext(); |
| break; |
| default: |
| // all other record types are not part of the PageSettingsBlock |
| return false; |
| } |
| return true; |
| } |
| |
| private void checkNotPresent(org.apache.poi.hssf.record.Record rec) { |
| if (rec != null) { |
| throw new RecordFormatException("Duplicate PageSettingsBlock record (sid=0x" |
| + Integer.toHexString(rec.getSid()) + ")"); |
| } |
| } |
| |
| public void visitContainedRecords(RecordVisitor rv) { |
| // Replicates record order from Excel 2007, though this is not critical |
| |
| visitIfPresent(_protectRecord, rv); |
| visitIfPresent(_objectProtectRecord, rv); |
| visitIfPresent(_scenarioProtectRecord, rv); |
| visitIfPresent(_passwordRecord, rv); |
| } |
| |
| private static void visitIfPresent(org.apache.poi.hssf.record.Record r, RecordVisitor rv) { |
| if (r != null) { |
| rv.visitRecord(r); |
| } |
| } |
| |
| public PasswordRecord getPasswordRecord() { |
| return _passwordRecord; |
| } |
| |
| public ScenarioProtectRecord getHCenter() { |
| return _scenarioProtectRecord; |
| } |
| |
| /** |
| * This method reads {@link WorksheetProtectionBlock} records from the supplied RecordStream |
| * until the first non-WorksheetProtectionBlock record is encountered. As each record is read, |
| * it is incorporated into this WorksheetProtectionBlock. |
| * <p> |
| * As per the OOO documentation, the protection block records can be expected to be written |
| * together (with no intervening records), but earlier versions of POI (prior to Jun 2009) |
| * didn't do this. Workbooks with sheet protection created by those earlier POI versions |
| * seemed to be valid (Excel opens them OK). So PO allows continues to support reading of files |
| * with non continuous worksheet protection blocks. |
| * |
| * <p> |
| * <b>Note</b> - when POI writes out this WorksheetProtectionBlock, the records will always be |
| * written in one consolidated block (in the standard ordering) regardless of how scattered the |
| * records were when they were originally read. |
| */ |
| public void addRecords(RecordStream rs) { |
| while (true) { |
| if (!readARecord(rs)) { |
| break; |
| } |
| } |
| } |
| |
| /** |
| * @return the ProtectRecord. If one is not contained in the sheet, then one |
| * is created. |
| */ |
| private ProtectRecord getProtect() { |
| if (_protectRecord == null) { |
| _protectRecord = new ProtectRecord(false); |
| } |
| return _protectRecord; |
| } |
| |
| /** |
| * @return the PasswordRecord. If one is not contained in the sheet, then |
| * one is created. |
| */ |
| private PasswordRecord getPassword() { |
| if (_passwordRecord == null) { |
| _passwordRecord = createPassword(); |
| } |
| return _passwordRecord; |
| } |
| |
| /** |
| * protect a spreadsheet with a password (not encrypted, just sets protect |
| * flags and the password. |
| * |
| * @param password to set. Pass <code>null</code> to remove all protection |
| * @param shouldProtectObjects are protected |
| * @param shouldProtectScenarios are protected |
| */ |
| public void protectSheet(String password, boolean shouldProtectObjects, |
| boolean shouldProtectScenarios) { |
| if (password == null) { |
| _passwordRecord = null; |
| _protectRecord = null; |
| _objectProtectRecord = null; |
| _scenarioProtectRecord = null; |
| return; |
| } |
| |
| ProtectRecord prec = getProtect(); |
| PasswordRecord pass = getPassword(); |
| prec.setProtect(true); |
| pass.setPassword((short)CryptoFunctions.createXorVerifier1(password)); |
| if (_objectProtectRecord == null && shouldProtectObjects) { |
| ObjectProtectRecord rec = createObjectProtect(); |
| rec.setProtect(true); |
| _objectProtectRecord = rec; |
| } |
| if (_scenarioProtectRecord == null && shouldProtectScenarios) { |
| ScenarioProtectRecord srec = createScenarioProtect(); |
| srec.setProtect(true); |
| _scenarioProtectRecord = srec; |
| } |
| } |
| |
| public boolean isSheetProtected() { |
| return _protectRecord != null && _protectRecord.getProtect(); |
| } |
| |
| public boolean isObjectProtected() { |
| return _objectProtectRecord != null && _objectProtectRecord.getProtect(); |
| } |
| |
| public boolean isScenarioProtected() { |
| return _scenarioProtectRecord != null && _scenarioProtectRecord.getProtect(); |
| } |
| |
| /** |
| * creates an ObjectProtect record with protect set to false. |
| */ |
| private static ObjectProtectRecord createObjectProtect() { |
| ObjectProtectRecord retval = new ObjectProtectRecord(); |
| retval.setProtect(false); |
| return retval; |
| } |
| |
| /** |
| * creates a ScenarioProtect record with protect set to false. |
| */ |
| private static ScenarioProtectRecord createScenarioProtect() { |
| ScenarioProtectRecord retval = new ScenarioProtectRecord(); |
| retval.setProtect(false); |
| return retval; |
| } |
| |
| /** |
| * creates a Password record with password set to 0x0000. |
| */ |
| private static PasswordRecord createPassword() { |
| return new PasswordRecord(0x0000); |
| } |
| |
| public int getPasswordHash() { |
| if (_passwordRecord == null) { |
| return 0; |
| } |
| return _passwordRecord.getPassword(); |
| } |
| } |