diff options
Diffstat (limited to 'xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm')
8 files changed, 1725 insertions, 0 deletions
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java new file mode 100644 index 000000000000..00f0f91a1691 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java @@ -0,0 +1,472 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: PalmDB.java,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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; + } +} + diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java new file mode 100644 index 000000000000..f039dab382ee --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java @@ -0,0 +1,180 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: PalmDocument.java,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package org.openoffice.xmerge.converter.palm; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ByteArrayOutputStream; + +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import org.openoffice.xmerge.Document; + +/** + * <p> A <code>PalmDocument</code> is palm implementaion of the + * <code>Docuemnt</code> interface.</p> + * + * <p>This implementation allows the Palm device format to be + * read via an <code>InputStream</code> and written via an + * <code>OutputStream</code>.</p> + * + * @author Martin Maher + */ + +public class PalmDocument + implements Document { + + /** + * The internal representation of a pdb. + */ + private PalmDB pdb; + + /** + * The file name. + */ + private String fileName; + + /** + * Constructor to create a <code>PalmDocument</code> + * from an <code>InputStream</code>. + * + * @param is <code>InputStream</code> containing a PDB. + * + * @throws IOException If any I/O error occurs. + */ + public PalmDocument(InputStream is) throws IOException { + read(is); + } + + + /** + * Constructor to create a <code>PalmDocument</code> with + * <code>Record</code> objects. <code>recs.length</code> + * can be zero for an empty PDB. + * + * @param name Suggested PDB name in <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 NullPointerException If <code>recs</code> is null. + */ + public PalmDocument(String name, int creatorID, int typeID, int version, + short attribute, Record[] recs) + throws UnsupportedEncodingException { + pdb = new PalmDB(name, creatorID, typeID, version, attribute, recs); + fileName = pdb.getPDBNameString(); + } + + + /** + * Reads in a file from the <code>InputStream</code>. + * + * @param is <code>InputStream</code> to read in its content. + * + * @throws IOException If any I/O error occurs. + */ + + public void read(InputStream is) throws IOException { + PdbDecoder decoder = new PdbDecoder(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + int n = 0; + while ((n = is.read(buf)) > 0) { + baos.write(buf, 0, n); + } + byte[] bytearr = baos.toByteArray(); + pdb = decoder.parse(bytearr); + fileName = pdb.getPDBNameString(); + } + + + /** + * Writes the <code>PalmDocument</code> to an <code>OutputStream</code>. + * + * @param is The <code>OutputStream</code> to write the content. + * + * @throws IOException If any I/O error occurs. + */ + public void write(OutputStream os) throws IOException { + PdbEncoder encoder = new PdbEncoder(pdb); + encoder.write(os); + } + + + /** + * Returns the <code>PalmDB</code> contained in this object. + * + * @return The <code>PalmDB</code>. + */ + public PalmDB getPdb() { + return pdb; + } + + + /** + * Sets the <code>PalmDocument</code> to a new <code>PalmDB</code> + * value. + * + * @param pdb The new <code>PalmDB</code> value. + */ + public void setPdb(PalmDB pdb) { + this.pdb = pdb; + + String name = pdb.getPDBNameString(); + fileName = name; + } + + + /** + * Returns the name of the file. + * + * @return The name of the file represented in the + * <code>PalmDocument</code>. + */ + public String getFileName() { + return fileName + ".pdb"; + } + + + /** + * Returns the <code>Document</code> name. + * + * @return The <code>Document</code> name. + */ + public String getName() { + return fileName; + } +} + diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java new file mode 100644 index 000000000000..f6df00664b27 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java @@ -0,0 +1,236 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: PdbDecoder.java,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package org.openoffice.xmerge.converter.palm; + +import java.io.RandomAccessFile; +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; + +/** + * <p>Provides functionality to decode a PDB formatted file into + * a <code>PalmDB</code> object given an <code>InputStream</code>. + * This class is only used by the <code>PalmDB</code> object.</p> + * + * <p>Sample usage:</p> + * + * <blockquote><pre><code> + * PdbDecoder decoder = new PdbDecoder("sample.pdb"); + * PalmDB palmDB = decoder.parse(); + * </code></pre></blockquote> + * + * <p>This decoder has the following assumptions on the PDB file:</p> + * + * <p><ol> + * <li>There is only one RecordList section in the PDB.</li> + * <li>The <code>Record</code> indices in the RecordList are sorted in + * order, i.e. the first <code>Record</code> index refers to + * <code>Record</code> 0, and so forth.</li> + * <li>The raw <code>Record</code> in the <code>Record</code> section + * are sorted as well in order, i.e. first <code>Record</code> + * comes ahead of second <code>Record</code>, etc.</li> + * </ol></p> + * + * <p>Other decoders assume these as well.</p> + * + * @author Herbie Ong + * @see PalmDB + * @see Record + */ +public final class PdbDecoder { + + + /** + * <p>This method decodes a PDB file into a <code>PalmDB</code> + * object.</p> + * + * <p>First, the header data is read using the <code>PdbHeader</code> + * <code>read</code> method. Next, the RecordList section is + * read and the <code>Record</code> offsets are stored for use when + * parsing the Records. Based on these offsets, the bytes + * corresponding to each <code>Record</code> are read and each is + * stored in a <code>Record</code> object. Lastly, the data is + * used to create a <code>PalmDB</code> object.</p> + * + * @param fileName PDB file name. + * + * @throws IOException If I/O error occurs. + */ + public PalmDB parse(String fileName) throws IOException { + + RandomAccessFile file = new RandomAccessFile(fileName, "r"); + + // read the PDB header + PdbHeader header = new PdbHeader(); + header.read(file); + + Record recArray[] = new Record[header.numRecords]; + if (header.numRecords != 0) { + + // read in the record indices + offsets + + int recOffset[] = new int[header.numRecords]; + byte recAttrs[] = new byte[header.numRecords]; + + for (int i = 0; i < header.numRecords; i++) { + + recOffset[i] = file.readInt(); + + // read in attributes (1 byte) + unique id (3 bytes) + // take away the unique id, store the attributes + + int attr = file.readInt(); + recAttrs[i] = (byte) (attr >>> 24); + } + + + // read the records + + int len = 0; + byte[] bytes = null; + + int lastIndex = header.numRecords - 1; + + for (int i = 0; i < lastIndex; i++) { + + file.seek(recOffset[i]); + len = recOffset[i+1] - recOffset[i]; + bytes = new byte[len]; + file.readFully(bytes); + recArray[i] = new Record(bytes, recAttrs[i]); + } + + // last record + file.seek(recOffset[lastIndex]); + len = (int) file.length() - recOffset[lastIndex]; + bytes = new byte[len]; + file.readFully(bytes); + recArray[lastIndex] = new Record(bytes, recAttrs[lastIndex]); + + } + + file.close(); + + // create PalmDB and return it + PalmDB pdb = new PalmDB(header.pdbName, header.creatorID, + header.typeID, header.version, header.attribute, recArray); + + return pdb; + } + + /** + * <p>This method decodes a PDB file into a <code>PalmDB</code> + * object.</p> + * + * <p>First, the header data is read using the <code>PdbHeader</code> + * <code>read</code> method. Next, the RecordList section is + * read and the <code>Record</code> offsets are stored for use when + * parsing the Records. Based on these offsets, the bytes + * corresponding to each <code>Record</code> are read and each is + * stored in a <code>Record</code> object. Lastly, the data is + * used to create a <code>PalmDB</code> object.</p> + * + * @param b <code>byte[]</code> containing PDB. + * + * @throws IOException If I/O error occurs. + */ + + public PalmDB parse(byte[] b) throws IOException { + + ByteArrayInputStream bais = new ByteArrayInputStream(b); + DataInputStream dis = new DataInputStream(bais); + + // read the PDB header + + PdbHeader header = new PdbHeader(); + header.read(dis); + + Record recArray[] = new Record[header.numRecords]; + if (header.numRecords != 0) { + + // read in the record indices + offsets + + int recOffset[] = new int[header.numRecords]; + byte recAttrs[] = new byte[header.numRecords]; + + for (int i = 0; i < header.numRecords; i++) { + + recOffset[i] = dis.readInt(); + + // read in attributes (1 byte) + unique id (3 bytes) + // take away the unique id, store the attributes + + int attr = dis.readInt(); + recAttrs[i] = (byte) (attr >>> 24); + } + + // read the records + + int len = 0; + byte[] bytes = null; + + int lastIndex = header.numRecords - 1; + + for (int i = 0; i < lastIndex; i++) { + + //dis.seek(recOffset[i]); + dis.reset(); + dis.skip(recOffset[i]); + len = recOffset[i+1] - recOffset[i]; + bytes = new byte[len]; + dis.readFully(bytes); + recArray[i] = new Record(bytes, recAttrs[i]); + } + + // last record + + dis.reset(); + len = (int) dis.available() - recOffset[lastIndex]; + dis.skip(recOffset[lastIndex]); + bytes = new byte[len]; + dis.readFully(bytes); + recArray[lastIndex] = new Record(bytes, recAttrs[lastIndex]); + } + + + + // create PalmDB and return it + + PalmDB pdb = new PalmDB(header.pdbName, header.creatorID, + header.typeID, header.version, header.attribute, recArray); + + return pdb; + } + + + +} + diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java new file mode 100644 index 000000000000..2081290ccf47 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java @@ -0,0 +1,199 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: PdbEncoder.java,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package org.openoffice.xmerge.converter.palm; + +import java.io.OutputStream; +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Date; + +/** + * <p>Provides functionality to encode a <code>PalmDB</code> object + * into a PDB formatted file given a file <code>OutputStream</code>. + * This class is only used by the <code>PalmDB</code> object.</p> + * + * <p>One needs to create one <code>PdbEncoder</code> object per + * <code>PalmDB</code> object to be encoded. This class keeps + * the PDB header data and functionality in the <code>PdbHeader</code> + * class.</p> + * + * <p>Sample usage:</p> + * + * <blockquote><pre><code> + * PdbEncoder encoder = new PdbEncoder(palmDB, "STRW", "data"); + * encoder.write(new FileOutputStream("sample.pdb")); + * </code></pre></blockquote> + * + * @author Herbie Ong + * @see PalmDB + * @see Record + */ +public final class PdbEncoder { + + /** PDB header. */ + private PdbHeader header = null; + + /** the PalmDB object. */ + private PalmDB db = null; + + /** + * The pattern for unique_id=0x00BABE(start). + */ + private final static int START_UNIQUE_ID = 0x00BABE; + + + /** + * Constructor. + * + * @param db The <code>PalmDB</code> to be encoded. + */ + public PdbEncoder(PalmDB db) { + + header = new PdbHeader(); + header.version = db.getVersion(); + + header.attribute = db.getAttribute(); + + this.db = db; + + header.pdbName = db.getPDBNameBytes(); + header.creatorID = db.getCreatorID(); + header.typeID = db.getTypeID(); + + // set the following dates to current date + Date date = new Date(); + header.creationDate = (date.getTime() / 1000) + PdbUtil.TIME_DIFF; + header.modificationDate = header.creationDate; + + header.numRecords = db.getRecordCount(); + } + + + /** + * <p>Write out a PDB into the given <code>OutputStream</code>.</p> + * + * <p>First, write out the header data by using the + * <code>PdbHeader</code> <code>write</code> method. Next, + * calculate the RecordList section and write it out. + * Lastly, write out the bytes corresponding to each + * <code>Record</code>.</p> + * + * <p>The RecordList section contains a list of + * <code>Record</code> index info, where each <code>Record</code> + * index info contains:</p> + * + * <p><ul> + * <li>4 bytes local offset of the <code>Record</code> from the + * top of the PDB.</li> + * <li>1 byte of <code>Record</code> attribute.</li> + * <li>3 bytes unique <code>Record</code> ID.</li> + * </ul></p> + * + * <p>There should be a total of <code>header.numRecords</code> + * of <code>Record</code> index info</p>. + * + * @param os <code>OutputStream</code> to write out PDB. + * + * @throws IOException If I/O error occurs. + */ + public void write(OutputStream os) throws IOException { + + BufferedOutputStream bos = new BufferedOutputStream(os); + DataOutputStream dos = new DataOutputStream(bos); + + // write out the PDB header + header.write(dos); + + if (header.numRecords > 0) { + + // compute for recOffset[] + + int recOffset[] = new int[header.numRecords]; + byte recAttr[] = new byte[header.numRecords]; + + // first recOffset will be at PdbUtil.HEADER_SIZE + all the + // record indices (@ 8 bytes each) + recOffset[0] = PdbUtil.HEADER_SIZE + (header.numRecords * 8); + + int lastIndex = header.numRecords - 1; + + for (int i = 0; i < lastIndex; i++) { + + Record rec = db.getRecord(i); + int size = rec.getSize(); + recAttr[i] = rec.getAttributes(); + + recOffset[i+1] = recOffset[i] + size; + } + + // grab the last record's attribute. + + Record lastRec = db.getRecord(lastIndex); + recAttr[lastIndex] = lastRec.getAttributes(); + + + int uid = START_UNIQUE_ID; + + for (int i = 0; i < header.numRecords; i++) { + + // write out each record offset + dos.writeInt(recOffset[i]); + + // write out record attribute (recAttr) and + // unique ID (uid) in 4 bytes (int) chunk. + // unique ID's have to be unique, thus + // increment each time. + int attr = (((int) recAttr[i]) << 24 ); + attr |= uid; + dos.writeInt(attr); + uid++; + } + + // write out the raw records + + for (int i = 0; i < header.numRecords; i++) { + + Record rec = db.getRecord(i); + byte bytes[] = rec.getBytes(); + dos.write(bytes); + } + + } else { + + // placeholder bytes if there are no records in the list. + dos.writeShort(0); + } + + dos.flush(); + } +} + diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java new file mode 100644 index 000000000000..c79acf6d20bb --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java @@ -0,0 +1,165 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: PdbHeader.java,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package org.openoffice.xmerge.converter.palm; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * <p>Class used only internally by <code>PdbEncoder</code> and + * <code>PdbDecoder</code> to store, read and write a PDB header.</p> + * + * <p>Note that fields are intended to be accessible only at the + * package level.</p> + * + * <p>Some of the fields are internally represented using a + * larger type since Java does not have unsigned types. + * Some are not since they are not relevant for now. + * The <code>read</code> and <code>write</code> methods should + * handle them properly.</p> + * + * @author Herbie Ong + * @see PalmDB + * @see Record + */ +final class PdbHeader { + + + /** Name of the database. 32 bytes. */ + byte[] pdbName = null; + + /** + * Flags for the database. Palm UInt16. Unsignedness should be + * irrelevant. + */ + short attribute = 0; + + /** Application-specific version for the database. Palm UInt16. */ + int version = 0; + + /** Date created. Palm UInt32. */ + long creationDate = 0; + + /** Date last modified. Palm UInt32. */ + long modificationDate = 0; + + /** Date last backup. Palm UInt32. */ + long lastBackupDate = 0; + + /** + * Incremented every time a <code>Record</code> is + * added, deleted or modified. Palm UInt32. + */ + long modificationNumber = 0; + + /** Optional field. Palm UInt32. Unsignedness should be irrelevant. */ + int appInfoID = 0; + + /** Optional field. Palm UInt32. Unsignedness should be irrelevant. */ + int sortInfoID = 0; + + /** Database type ID. Palm UInt32. Unsignedness should be irrelevant. */ + int typeID = 0; + + /** Database creator ID. Palm UInt32. Unsignedness should be irrelevant. */ + int creatorID = 0; + + /** ??? */ + int uniqueIDSeed = 0; + + /** See numRecords. 4 bytes. */ + int nextRecordListID = 0; + + /** + * Number of Records stored in the database header. + * If all the <code>Record</code> entries cannot fit in the header, + * then <code>nextRecordList</code> has the local ID of a + * RecordList that contains the next set of <code>Record</code>. + * Palm UInt16. + */ + int numRecords = 0; + + + /** + * Read in the data for the PDB header. Need to + * preserve the unsigned value for some of the fields. + * + * @param di A <code>DataInput</code> object. + * + * @throws IOException If any I/O error occurs. + */ + public void read(DataInput in) throws IOException { + + pdbName = new byte[PalmDB.NAME_LENGTH]; + in.readFully(pdbName); + attribute = in.readShort(); + version = in.readUnsignedShort(); + creationDate = ((long) in.readInt()) & 0xffffffffL; + modificationDate = ((long) in.readInt()) & 0xffffffffL; + lastBackupDate = ((long) in.readInt()) & 0xffffffffL; + modificationNumber = ((long) in.readInt()) & 0xffffffffL; + appInfoID = in.readInt(); + sortInfoID = in.readInt(); + creatorID = in.readInt(); + typeID = in.readInt(); + uniqueIDSeed = in.readInt(); + nextRecordListID = in.readInt(); + numRecords = in.readUnsignedShort(); + } + + + /** + * Write out PDB header data. + * + * @param out A <code>DataOutput</code> object. + * + * @throws IOException If any I/O error occurs. + */ + public void write(DataOutput out) throws IOException { + + out.write(pdbName); + out.writeShort(attribute); + out.writeShort(version); + out.writeInt((int) creationDate); + out.writeInt((int) modificationDate); + out.writeInt((int) lastBackupDate); + out.writeInt((int) modificationNumber); + out.writeInt(appInfoID); + out.writeInt(sortInfoID); + out.writeInt(typeID); + out.writeInt(creatorID); + out.writeInt(uniqueIDSeed); + out.writeInt(nextRecordListID); + out.writeShort(numRecords); + } +} + diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java new file mode 100644 index 000000000000..cb50b9d7cb76 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java @@ -0,0 +1,108 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: PdbUtil.java,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package org.openoffice.xmerge.converter.palm; + +/** + * Contains common static methods and constants for use within the package. + * + * @author Herbie Ong + */ +public final class PdbUtil { + + /** Difference in seconds from Jan 01, 1904 to Jan 01, 1970. */ + final static long TIME_DIFF = 2082844800; + + /** Encoding scheme used. */ + final static String ENCODING = "8859_1"; + + /** Size of a PDB header in bytes. */ + final static int HEADER_SIZE = 78; + + + /** + * <p>This method converts a 4 letter string into the Palm ID + * integer.</p> + * + * <p>It is normally used to convert the Palm creator ID string into + * the integer version of it. Also use for data types, etc.</p> + * + * @param s Four character <code>String</code>. + * + * @return Palm ID representing the <code>String</code>. + * + * @throws ArrayIndexOutOfBoundsException If <code>String</code> + * parameter contains less than four characters. + */ + public static int intID(String s) { + + int id = -1; + int temp = 0; + + // grab the first char and put it in the high bits + // note that we only want 8 lower bits of it. + temp = (int) s.charAt(0); + id = temp << 24; + + // grab the second char and add it in. + temp = ((int) s.charAt(1)) & 0x00ff; + id += temp << 16; + + // grab the second char and add it in. + temp = ((int) s.charAt(2)) & 0x00ff; + id += temp << 8; + + // grab the last char and add it in + id += ((int) s.charAt(3)) & 0x00ff; + + return id; + } + + + /** + * This method converts an integer into a <code>String</code> + * given the Palm ID format. + * + * @param i Palm ID. + * + * @return <code>String</code> representation. + */ + public static String stringID(int i) { + + char ch[] = new char[4]; + ch[0] = (char) (i >>> 24); + ch[1] = (char) ((i >> 16) & 0x00ff); + ch[2] = (char) ((i >> 8) & 0x00ff); + ch[3] = (char) (i & 0x00ff); + + return new String(ch); + } +} + diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java new file mode 100644 index 000000000000..6475fdbc9537 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java @@ -0,0 +1,219 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: Record.java,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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; + +/** + * <p>Contains the raw bytes for a <code>Record</code> in a PDB.</p> + * + * <p>Note that it is not associated with a <code>Record</code> number + * or ID.</p> + * + * @author Akhil Arora, Herbie Ong + * @see PalmDocument + * @see PalmDB + */ +public final class Record { + + /** <code>Record</code> <code>byte</code> array. */ + private byte[] data; + + /** <code>Record</code> attributes. */ + private byte attributes = 0; + + + /** + * Default constructor. + */ + public Record() { + + data = new byte[0]; + } + + + /** + * <p>Constructor to create a <code>Record</code> filled with + * bytes.</p> + * + * <p>Note that this does not check for 64k <code>Record</code> + * sizes. User of this class must check for that.</p> + * + * @param d <code>byte</code> array contents for this object. + */ + public Record(byte[] d) { + + this(d, (byte) 0); + } + + + /** + * <p>Constructor to create a <code>Record</code> filled with + * bytes and assign <code>Record</code> attributes.</p> + * + * <p>Note that this does not check for 64k <code>Record</code> + * sizes. User of this class must check for that.</p> + * + * @param d <code>byte</code> array contents for this object. + * @param attrs <code>Record</code> attributes. + */ + public Record(byte[] d, byte attrs) { + + data = new byte[d.length]; + attributes = attrs; + System.arraycopy(d, 0, data, 0, d.length); + } + + + /** + * This method returns the number of bytes in this object. + * + * @return Number of bytes in this object. + */ + public int getSize() { + + return data.length; + } + + + /** + * This method returns the contents of this <code>Object</code>. + * + * @return Contents in <code>byte</code> array + */ + public byte[] getBytes() { + + return data; + } + + + /** + * <p>This method returns the <code>Record</code> attributes.</p> + * + * <blockquote><pre> + * <code>Record</code> attributes consists of (from high to low bit) + * + * delete (1) - dirty (1) - busy (1) - secret (1) - category (4) + * </pre></blockquote> + * + * @return <code>Record</code> attribute. + */ + public byte getAttributes() { + + return attributes; + } + + + /** + * Write out the <code>Record</code> attributes and + * <code>Record</code> length followed by the data in this + * <code>Record</code> object. + * + * @param out The <code>OutputStream</code> to write the object. + * + * @throws IOException If any I/O error occurs. + */ + public void write(OutputStream outs) throws IOException { + + DataOutputStream out = new DataOutputStream(outs); + out.writeByte(attributes); + out.writeShort(data.length); + out.write(data); + } + + + /** + * Read the necessary data to create a PDB from + * the <code>InputStream</code>. + * + * @param in The <code>InputStream</code> to read data from + * in order to restore the <code>object</code>. + * + * @throws IOException If any I/O error occurs. + */ + public void read(InputStream ins) throws IOException { + + DataInputStream in = new DataInputStream(ins); + attributes = in.readByte(); + int len = in.readUnsignedShort(); + data = new byte[len]; + in.readFully(data); + } + + + /** + * <p>Override equals method of <code>Object</code>.</p> + * + * <p>Two <code>Record</code> objects are equal if they contain + * the same bytes in the array and the same attributes.</p> + * + * <p>This is used primarily for testing purposes only for now.</p> + * + * @param obj A <code>Record</code> object to compare with + * + * @return true if obj is equal, otherwise false. + */ + public boolean equals(Object obj) { + + boolean bool = false; + + if (obj instanceof Record) { + + Record rec = (Record) obj; + + checkLabel: { + + if (rec.getAttributes() != attributes) { + + break checkLabel; + } + + if (rec.getSize() == data.length) { + + for (int i = 0; i < data.length; i++) { + + if (data[i] != rec.data[i]) { + break checkLabel; + } + } + + bool = true; + } + } + } + return bool; + } +} + diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package.html b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package.html new file mode 100644 index 000000000000..8f5159b23d6d --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package.html @@ -0,0 +1,146 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- + #************************************************************************* + # + DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + + Copyright 2008 by Sun Microsystems, Inc. + + OpenOffice.org - a multi-platform office productivity suite + + $RCSfile: package.html,v $ + + $Revision: 1.4 $ + + This file is part of OpenOffice.org. + + OpenOffice.org is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + OpenOffice.org is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details + (a copy is included in the LICENSE file that accompanied this code). + + You should have received a copy of the GNU Lesser General Public License + version 3 along with OpenOffice.org. If not, see + <http://www.openoffice.org/license.html> + for a copy of the LGPLv3 License. + + #************************************************************************* + --> +<html> +<head> +<title>org.openoffice.xmerge.converter.palm package</title> +</head> + +<body bgcolor="white"> + +<p>Provides classes for converting Palm database data to/from a +<code>PalmDocument</code> object, which can be used by the framework. + +<p>This package provides classes that handle the writing of data to +an <code>OutputStream</code> object for the +{@link org.openoffice.xmerge.DocumentSerializer DocumentSerializer} +interface for; as well as the reading of data from an <code>InputStream</code> +object for the framework's +{@link org.openoffice.xmerge.DocumentDeserializer DocumentDeserializer} +interface. Both these framework interfaces are simply converters from +server-side documents to device specific documents and vice-versa. +Since all Palm databases have a general record oriented format, a Palm +database converter specific I/O stream format is specified for the Palm +sync client application to handle the byte stream in a generic way. +This also means that Palm database converters should read and/or write +using this I/O stream format as specified in the next section.</p> + +<a name="streamformat"> +<h2>Palm database converter specific I/O stream format</h2> +</a> + +<p>Note that the format of the byte stream is not exactly that of a PDB +file encoding. It does not need to contain the PDB header information +nor record indices section. Instead, it contains the following ...</p> + +<pre> + set header + 4 bytes - creator id + 4 bytes - type id + 2 bytes - PDB header version + 2 bytes - PDB header attribute + unsigned 2 bytes - number of PDB data to follow + + for each PDB, + 32 bytes - name of PDB i + unsigned 2 bytes - number of records in PDB i + + for each record contained in PDB i, + 1 byte - record attributes + unsigned 2 bytes - size of record j in PDB i + x bytes - data +</pre> + +<p>Note that each PDB section is appended by another if there is more +than one.</p> + +<p>Since the <code>PalmDocument</code> class takes care of the writing +and reading of this format through its <code>write</code> and +<code>read</code> methods, respectively, this format shall also be +referred to as the <b>PalmDocument stream format</b>.</p> + +<h2>Usage of the classes for the specified I/O stream</h2> + +<p>When converting from a server document to device document(s), the +framework requires writing the device document(s) to an +<code>OutputStream</code> object via the <code>DocumentSerializer</code> +interface. Note that a single server document may be converted +into multiple PDB's on the Palm device. Each worksheet in the document +is converted into a <code>PalmDocument</code> . Thus, if there is more +than one worksheet in the document, more than one <code>PalmDocument</code> +will be produced by the <code>DocumentSerializer</code>.</p> + +<p>A <code>DocumentSerializer</code> creates a <code>ConvertData</code> object, +which contains all of the <code>PalmDocuments</code>. The +{@link org.openoffice.xmerge.converter.palm.PalmDocument#write write} +method to write to the given <code>OutputStream</code>. The <code>PalmDocument</code> +object will take care of writing the data in the +<a href=#streamformat>specified format</a>.</p> + +<p>A <code>DocumentDeserializer</code> can use the <code>PalmDocument</code> object's +{@link org.openoffice.xmerge.converter.palm.PalmDocument#read read} +method to fill in all the <code>PalmDocument</code> object's data.</p> + +<h2>PDB file encoding/decoding</h2> + +<p>The <code>PalmDocument</code> object's read and write functions are provided +by the <code>PdbDecoder</code> and <code>PdbEncoder</code> objects. The +<code>PdbEncoder</code> class provides the functionality of encoding a +<code>PalmDB</code> object into an <code>InputStream</code>, while the +<code>PdbDecoder</code> class provides the functionality of decoding a +PDB file into an <code>OutputStream</code>.</p> + +<p>Refer to the class description of each for usage.</p> + +<h2>Important Note</h2> + +<p>Methods in these classes are not thread safe for performance reasons. +Users of these classes will have to make sure that the usage of these classes +are done in a proper manner. Possibly more on this later.</p> + +<h2>TODO list</h2> + +<p><ol> +<li>Merge the PalmDB, PdbDecoder and PdbEncoder classes into the + PalmDocument class.</li> +<li>After reading more on the palm file format spec, I realized + that there are certain optional fields that may need to be addressed + still, like the appInfo block and sortInfo block.</li> +<li>The current PdbDecoder only returns a PalmDB object. There are other + information that we may want to expose from the PDB decoding process.</li> +<li>Investigate on different language encoding on the Palm and how that + affects the PDB name.</li> +</ol></p> + +</body> +</html> |