blob: 59114d5d73ba71c4f7ef970d9cc22b4024e8f872 [file] [log] [blame]
/**************************************************************
*
* 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.openoffice.xmerge.converter.palm;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* <p>This class contains data for a single Palm database for use during
* a conversion process.</p>
*
* <p>It contains zero or more <code>Record</code> objects stored in an
* array. The index of the <code>Record</code> object in the array is
* the <code>Record</code> id or number for that specific <code>Record</code> object.
* Note that this class does not check for maximum number of Records
* allowable in an actual PDB.</p>
*
* <p>This class also contains the PDB name associated with the Palm
* database it represents. A PDB name consists of 32 bytes of a
* certain encoding (extended ASCII in this case).</p>
*
* <p>The non default constructors take in a name parameter which may not
* be the exact PDB name to be used. The name parameter in
* <code>String</code> or <code>byte</code> array are converted to an exact
* <code>NAME_LENGTH</code> byte array. If the length of the name is less
* than <code>NAME_LENGTH</code>, it is padded with '\0' characters. If it
* is more, it gets truncated. The last character in the resulting byte
* array is always a '\0' character. The resulting byte array is stored in
* <code>bName</code>, and a corresponding String object <code>sName</code>
* that contains characters without the '\0' characters.</p>
*
* <p>The {@link #write write} method is called within the
* {@link org.openoffice.xmerge.converter.palm.PalmDocument#write
* PalmDocument.write} method for writing out its data to the <code>OutputStream</code>
* object.</p>
*
* <p>The {@link #read read} method is called within the
* {@link org.openoffice.xmerge.converter.palm.PalmDocument#read
* PalmDocument.read} method for reading in its data from the <code>InputStream</code>
* object.</p>
*
* @author Akhil Arora, Herbie Ong
* @see PalmDocument
* @see Record
*/
public final class PalmDB {
/* Backup attribute for a PDB. This corresponds to dmHdrAttrBackup. */
public final static short PDB_HEADER_ATTR_BACKUP = 0x0008;
/** Number of bytes for the name field in the PDB. */
public final static int NAME_LENGTH = 32;
/** List of <code>Record</code> objects. */
private Record[] records;
/** PDB name in bytes. */
private byte[] bName = null;
/** PDB name in String. */
private String sName = null;
/** Creator ID. */
private int creatorID = 0;
/** Type ID */
private int typeID = 0;
/**
* PDB version. Palm UInt16.
* It is treated as a number here, since there is no unsigned 16 bit
* in Java, int is used instead, but only 2 bytes are written out or
* read in.
*/
private int version = 0;
/**
* PDB attribute - flags for the database.
* Palm UInt16. Unsignedness should be irrelevant.
*/
private short attribute = 0;
/**
* Default constructor.
*
* @param creatorID The PDB Creator ID.
* @param typeID The PDB Type ID.
* @param version The PDB header version.
* @param attribute The PDB header attribute.
*/
public PalmDB(int creatorID, int typeID, int version, short attribute) {
records = new Record[0];
setAttributes(creatorID, typeID, version, attribute);
}
/**
* Constructor to create <code>PalmDB</code> object with
* <code>Record</code> objects. <code>recs.length</code>
* can be zero for an empty PDB.
*
* @param name Suggested PDB name in a <code>String</code>.
* @param creatorID The PDB Creator ID.
* @param typeID The PDB Type ID.
* @param version The PDB header version.
* @param attribute The PDB header attribute.
* @param recs Array of <code>Record</code> objects.
*
* @throws UnsupportedEncodingException If <code>name</code> is
* not properly encoded.
* @throws NullPointerException If <code>recs</code> is null.
*/
public PalmDB(String name, int creatorID, int typeID, int version,
short attribute, Record[] recs)
throws UnsupportedEncodingException {
this(name.getBytes(PdbUtil.ENCODING), creatorID, typeID, version,
attribute, recs);
}
/**
* Constructor to create object with <code>Record</code>
* objects. <code>recs.length</code> can be zero for an
* empty PDB.
*
* @param name Suggested PDB name in a <code>byte</code>
* array.
* @param creatorID The PDB Creator ID.
* @param typeID The PDB Type ID.
* @param version The PDB header version.
* @param attribute The PDB header attribute.
* @param recs Array of <code>Record</code> objects.
*
* @throws UnsupportedEncodingException If <code>name</code> is
* not properly encoded.
* @throws NullPointerException If recs is null.
*/
public PalmDB(byte[] name, int creatorID, int typeID, int version,
short attribute, Record[] recs) throws UnsupportedEncodingException {
store(name);
records = new Record[recs.length];
System.arraycopy(recs, 0, records, 0, recs.length);
setAttributes(creatorID, typeID, version, attribute);
}
/**
* Set the attributes for the <code>PalmDB</code> object.
*
* @param creatorID The PDB Creator ID.
* @param typeID The PDB Type ID.
* @param version The PDB header version.
* @param attribute The PDB header attribute.
*/
public void setAttributes (int creatorID, int typeID, int version, short attribute) {
this.creatorID = creatorID;
this.typeID = typeID;
this.version = version;
this.attribute = attribute;
}
/**
* This private method is mainly used by the constructors above.
* to store bytes into name and also create a <code>String</code>
* representation. and also by the <code>read</code> method.
*
* TODO: Note that this method assumes that the <code>byte</code>
* array parameter contains one character per <code>byte</code>,
* else it would truncate improperly.
*
* @param bytes PDB name in <code>byte</code> array.
*
* @throws UnsupportedEncodingException If ENCODING is
* not supported.
*/
private void store(byte[] bytes) throws UnsupportedEncodingException {
// note that this will initialize all bytes in name to 0.
bName = new byte[NAME_LENGTH];
// determine minimum length to copy over from bytes to bName.
// Note that the last byte in bName has to be '\0'.
int lastIndex = NAME_LENGTH - 1;
int len = (bytes.length < lastIndex)? bytes.length: lastIndex;
int i;
for (i = 0; i < len; i++) {
if (bytes[i] == 0) {
break;
}
bName[i] = bytes[i];
}
// set sName, no need to include the '\0' character.
sName = new String(bName, 0, i, PdbUtil.ENCODING);
}
/**
* Returns creator ID.
*
* @return The creator ID.
*/
public int getCreatorID() {
return creatorID;
}
/**
* Returns type ID.
*
* @return The type ID.
*/
public int getTypeID() {
return typeID;
}
/**
* Returns attribute flag.
*
* @return The attribute flag.
*/
public short getAttribute() {
return attribute;
}
/**
* Returns version.
*
* @return The version.
*/
public int getVersion() {
return version;
}
/**
* Return the number of Records contained in this
* PDB <code>PalmDB</code> object.
*
* @return Number of <code>Record</code> objects.
*/
public int getRecordCount() {
return records.length;
}
/**
* Return the specific <code>Record</code> object associated
* with the <code>Record</code> number.
*
* @param index <code>Record</code> index number.
*
* @return The <code>Record</code> object in the specified index
*
* @throws ArrayIndexOutOfBoundsException If index is out of bounds.
*/
public Record getRecord(int index) {
return records[index];
}
/**
* Return the list of <code>Record</code> objects.
*
* @return The array of <code>Record</code> objects.
*/
public Record[] getRecords() {
return records;
}
/**
* Return the PDB name associated with this object.
*
* @return The PDB name.
*/
public String getPDBNameString() {
return sName;
}
/**
* Return the PDB name associated with this object in
* <code>byte</code> array of exact length of 32 bytes.
*
* @return The PDB name in <code>byte</code> array of
* length 32.
*/
public byte[] getPDBNameBytes() {
return bName;
}
/**
* Write out the number of Records followed by what
* will be written out by each <code>Record</code> object.
*
* @param os The <code>OutputStream</code> to write the
* object.
*
* @throws IOException If any I/O error occurs.
*/
public void write(OutputStream os) throws IOException {
DataOutputStream out = new DataOutputStream(os);
// write out PDB name
out.write(bName);
// write out 2 bytes for number of records
out.writeShort(records.length);
// let each Record object write out its own info.
for (int i = 0; i < records.length; i++)
records[i].write(out);
}
/**
* Read the necessary data to create a PDB from
* the <code>InputStream</code>.
*
* @param is The <code>InputStream</code> to read data
* in order to restore the object.
*
* @throws IOException If any I/O error occurs.
*/
public void read(InputStream is) throws IOException {
DataInputStream in = new DataInputStream(is);
// read in the PDB name.
byte[] bytes = new byte[NAME_LENGTH];
in.readFully(bytes);
store(bytes);
// read in number of records
int nrec = in.readUnsignedShort();
records = new Record[nrec];
// read in the Record infos
for (int i = 0; i < nrec; i++) {
records[i] = new Record();
records[i].read(in);
}
}
/**
* Override equals method of <code>Object</code>.
*
* Two <code>PalmDB</code> objects are equal if they contain
* the same information, i.e. PDB name and Records.
*
* This is used primarily for testing purposes only for now.
*
* @param obj A <code>PalmDB</code> <code>Object</code> to
* compare.
*
* @return true if <code>obj</code> is equal to this, otherwise
* false.
*/
public boolean equals(Object obj) {
boolean bool = false;
if (obj instanceof PalmDB) {
PalmDB pdb = (PalmDB) obj;
checkLabel: {
// compare sName
if (!sName.equals(pdb.sName)) {
break checkLabel;
}
// compare bName
if (bName.length != pdb.bName.length) {
break checkLabel;
}
for (int i = 0; i < bName.length; i++) {
if (bName[i] != pdb.bName[i]) {
break checkLabel;
}
}
// compare each Record
if (records.length != pdb.records.length) {
break checkLabel;
}
for (int i = 0; i < records.length; i++) {
if (!records[i].equals(pdb.records[i])) {
break checkLabel;
}
}
// all checks done
bool = true;
}
}
return bool;
}
}