001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hssf.record;
019:
020: import org.apache.poi.util.LittleEndian;
021: import org.apache.poi.util.StringUtil;
022:
023: /**
024: * Title: FileSharing<P>
025: * Description: stores the encrypted readonly for a workbook (write protect)
026: * REFERENCE: PG 314 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
027: * @author Andrew C. Oliver (acoliver at apache dot org)
028: */
029:
030: public class FileSharingRecord extends Record {
031: public final static short sid = 0x5b;
032: private short field_1_readonly;
033: private short field_2_password;
034: private byte field_3_username_length;
035: private short field_4_unknown; // not documented
036: private String field_5_username;
037:
038: public FileSharingRecord() {
039: }
040:
041: /**
042: * Constructs a FileSharing record and sets its fields appropriately.
043: * @param in the RecordInputstream to read the record from
044: */
045:
046: public FileSharingRecord(RecordInputStream in) {
047: super (in);
048: }
049:
050: protected void validateSid(short id) {
051: if (id != sid) {
052: throw new RecordFormatException("NOT A FILESHARING RECORD");
053: }
054: }
055:
056: protected void fillFields(RecordInputStream in) {
057: field_1_readonly = in.readShort();
058: field_2_password = in.readShort();
059: field_3_username_length = in.readByte();
060: field_4_unknown = in.readShort();
061: field_5_username = in
062: .readCompressedUnicode(field_3_username_length);
063: }
064:
065: //this is the world's lamest "security". thanks to Wouter van Vugt for making me
066: //not have to try real hard. -ACO
067: public static short hashPassword(String password) {
068: byte[] passwordCharacters = password.getBytes();
069: int hash = 0;
070: if (passwordCharacters.length > 0) {
071: int charIndex = passwordCharacters.length;
072: while (charIndex-- > 0) {
073: hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
074: hash ^= passwordCharacters[charIndex];
075: }
076: // also hash with charcount
077: hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
078: hash ^= passwordCharacters.length;
079: hash ^= (0x8000 | ('N' << 8) | 'K');
080: }
081: return (short) hash;
082: }
083:
084: /**
085: * set the readonly flag
086: *
087: * @param readonly 1 for true, not 1 for false
088: */
089: public void setReadOnly(short readonly) {
090: field_1_readonly = readonly;
091: }
092:
093: /**
094: * get the readonly
095: *
096: * @return short representing if this is read only (1 = true)
097: */
098: public short getReadOnly() {
099: return field_1_readonly;
100: }
101:
102: /**
103: * @param hashed password
104: */
105: public void setPassword(short password) {
106: field_2_password = password;
107: }
108:
109: /**
110: * @returns password hashed with hashPassword() (very lame)
111: */
112: public short getPassword() {
113: return field_2_password;
114: }
115:
116: /**
117: * @returns byte representing the length of the username field
118: */
119: public byte getUsernameLength() {
120: return field_3_username_length;
121: }
122:
123: /**
124: * @param byte representing the length of the username field
125: */
126: public void setUsernameLength(byte length) {
127: this .field_3_username_length = length;
128: }
129:
130: /**
131: * @returns username of the user that created the file
132: */
133: public String getUsername() {
134: return this .field_5_username;
135: }
136:
137: /**
138: * @param username of the user that created the file
139: */
140: public void setUsername(String username) {
141: this .field_5_username = username;
142: this .field_3_username_length = (byte) username.length();
143: }
144:
145: /**
146: * @return short value of a "bonus field" in Excel that was not doc'd
147: */
148: public short getUnknown() {
149: return field_4_unknown;
150: }
151:
152: /**
153: * @param unknown field value to set (bonus field that is not doc'd)
154: */
155: public void setUnknown(short unk) {
156: field_4_unknown = unk;
157: }
158:
159: public String toString() {
160: StringBuffer buffer = new StringBuffer();
161:
162: buffer.append("[FILESHARING]\n");
163: buffer.append(" .readonly = ").append(
164: getReadOnly() == 1 ? "true" : "false").append("\n");
165: buffer.append(" .password = ").append(
166: Integer.toHexString(getPassword())).append("\n");
167: buffer.append(" .userlen = ").append(
168: Integer.toHexString(getUsernameLength())).append("\n");
169: buffer.append(" .unknown = ").append(
170: Integer.toHexString(getUnknown())).append("\n");
171: buffer.append(" .username = ").append(getUsername())
172: .append("\n");
173: buffer.append("[/FILESHARING]\n");
174: return buffer.toString();
175: }
176:
177: public int serialize(int offset, byte[] data) {
178: LittleEndian.putShort(data, 0 + offset, sid);
179: LittleEndian.putShort(data, 2 + offset,
180: (short) (getRecordSize() - 4));
181: LittleEndian.putShort(data, 4 + offset, getReadOnly());
182: LittleEndian.putShort(data, 6 + offset, getPassword());
183: data[8 + offset] = getUsernameLength();
184: LittleEndian.putShort(data, 9 + offset, getUnknown());
185: StringUtil.putCompressedUnicode(getUsername(), data,
186: 11 + offset);
187: return getRecordSize();
188: }
189:
190: public int getRecordSize() {
191: return 11 + getUsernameLength();
192: }
193:
194: public short getSid() {
195: return sid;
196: }
197:
198: /**
199: * Clone this record.
200: */
201: public Object clone() {
202: FileSharingRecord clone = new FileSharingRecord();
203: clone.setReadOnly(field_1_readonly);
204: clone.setPassword(field_2_password);
205: clone.setUsernameLength(field_3_username_length);
206: clone.setUnknown(field_4_unknown);
207: clone.setUsername(field_5_username);
208: return clone;
209: }
210:
211: }
|