summaryrefslogtreecommitdiffstats
path: root/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm
diff options
context:
space:
mode:
Diffstat (limited to 'xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm')
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java360
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java148
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java128
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java168
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java145
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java35
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java176
-rw-r--r--xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package-info.java122
8 files changed, 1282 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 000000000..2f6ca0114
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDB.java
@@ -0,0 +1,360 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+package org.openoffice.xmerge.converter.palm;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * This class contains data for a single Palm database for use during a
+ * conversion process.
+ *
+ * <p>It contains zero or more {@code Record} objects stored in an array. The
+ * index of the {@code Record} object in the array is the {@code Record} id or
+ * number for that specific {@code Record} 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} or
+ * {@code byte} array are converted to an exact {@code NAME_LENGTH} byte array.
+ * If the length of the name is less than {@code NAME_LENGTH}, it is padded
+ * with {@code '\0'} characters. If it is more, it gets truncated. The last
+ * character in the resulting byte array is always a {@code '\0'} character.
+ * The resulting byte array is stored in {@code bName}, and a corresponding
+ * {@code String} object {@code sName} that contains characters without the
+ * {@code '\0'} characters.</p>
+ *
+ * <p>The {@code 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} object.</p>
+ *
+ * <p>The {@code 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} object.</p>
+ *
+ * @see PalmDocument
+ * @see Record
+ */
+
+public final class PalmDB {
+
+ /** Number of bytes for the name field in the PDB. */
+ public static final int NAME_LENGTH = 32;
+
+ /** List of {@code Record} 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,
+ * {@code 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} object with {@code Record} objects.
+ *
+ * <p>{@code recs.length} can be zero for an empty PDB.</p>
+ *
+ * @param name Suggested PDB name in a {@code String}.
+ * @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} objects.
+ *
+ * @throws UnsupportedEncodingException If {@code name} is not properly
+ * encoded.
+ * @throws NullPointerException If {@code recs} is {@code 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} objects.
+ *
+ * <p>{@code recs.length} can be zero for an empty PDB.</p>
+ *
+ * @param name Suggested PDB name in a {@code byte} 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} objects.
+ *
+ * @throws UnsupportedEncodingException If {@code name} is not properly
+ * encoded.
+ * @throws NullPointerException If {@code recs} is {@code 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} 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.
+ */
+ private 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.
+ *
+ * <p>to store bytes into name and also create a {@code String}
+ * representation, and also by the {@code read} method.</p>
+ *
+ * <p>TODO: Note that this method assumes that the {@code byte} array
+ * parameter contains one character per {@code byte}, else it would
+ * truncate improperly.</p>
+ *
+ * @param bytes PDB name in {@code byte<} 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} object.
+ *
+ * @return Number of {@code Record} objects.
+ */
+ public int getRecordCount() {
+ return records.length;
+ }
+
+ /**
+ * Return the specific {@code Record} object associated with the
+ * {@code Record} number.
+ *
+ * @param index {@code Record} index number.
+ *
+ * @return The {@code Record} 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} objects.
+ *
+ * @return The array of {@code Record} 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} array of
+ * exact length of 32 bytes.
+ *
+ * @return The PDB name in {@code byte} array of length 32.
+ */
+ public byte[] getPDBNameBytes() {
+ return bName;
+ }
+
+ /**
+ * Override equals method of {@code Object}.
+ *
+ * <p>Two {@code PalmDB} objects are equal if they contain the same
+ * information, i.e. PDB name and Records.</p>
+ *
+ * <p>This is used primarily for testing purposes only for now.</p>
+ *
+ * @param obj A {@code PalmDB} {@code Object} to compare.
+ *
+ * @return {@code true} if {@code obj} is equal to this, otherwise
+ * {@code false}.
+ */
+ @Override
+ 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;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+}
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 000000000..b7fb67bcf
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PalmDocument.java
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+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;
+
+/**
+ * A {@code PalmDocument} is palm implementation of the {@code Document}
+ * interface.
+ *
+ * <p>This implementation allows the Palm device format to be read via an
+ * {@code InputStream} and written via an {@code OutputStream}.</p>
+ */
+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} from an {@code InputStream}.
+ *
+ * @param is {@code InputStream} 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} with {@code Record} objects.
+ *
+ * <p>{@code recs.length} can be zero for an empty PDB.</p>
+ *
+ * @param name Suggested PDB name in {@code String}.
+ * @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} objects.
+ *
+ * @throws NullPointerException If {@code recs} is {@code 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}.
+ *
+ * @param is {@code InputStream} 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;
+ 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} to an {@code OutputStream}.
+ *
+ * @param os The {@code OutputStream} 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} contained in this object.
+ *
+ * @return The {@code PalmDB}.
+ */
+ public PalmDB getPdb() {
+ return pdb;
+ }
+
+ /**
+ * Sets the {@code PalmDocument} to a new {@code PalmDB} value.
+ *
+ * @param pdb The new {@code PalmDB} 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}.
+ */
+ public String getFileName() {
+ return fileName + ".pdb";
+ }
+
+ /**
+ * Returns the {@code Document} name.
+ *
+ * @return The {@code Document} name.
+ */
+ public String getName() {
+ return fileName;
+ }
+} \ No newline at end of file
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 000000000..b3fbd4df0
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbDecoder.java
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+package org.openoffice.xmerge.converter.palm;
+
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+
+/**
+ * Provides functionality to decode a PDB formatted file into a {@code PalmDB}
+ * object given an {@code InputStream}.
+ *
+ * <p>This class is only used by the {@code PalmDB} object.</p>
+ *
+ * <p>Sample usage:</p>
+ * <blockquote><pre>{@code PdbDecoder decoder = new PdbDecoder("sample.pdb");
+ * PalmDB palmDB = decoder.parse();}</pre></blockquote>
+ *
+ * <p>This decoder has the following assumptions on the PDB file:</p>
+ * <ol>
+ * <li>There is only one RecordList section in the PDB.</li>
+ * <li>The {@code Record} indices in the RecordList are sorted in order, i.e.
+ * the first {@code Record} index refers to {@code Record} 0, and so
+ * forth.</li>
+ * <li>The raw {@code Record} in the {@code Record} section are sorted as
+ * well in order, i.e. first {@code Record} comes ahead of second
+ * {@code Record}, etc.</li>
+ * </ol>
+ *
+ * <p>Other decoders assume these as well.</p>
+ *
+ * @see PalmDB
+ * @see Record
+ */
+public final class PdbDecoder {
+
+ /**
+ * This method decodes a PDB file into a {@code PalmDB} object.
+ *
+ * <p>First, the header data is read using the {@code PdbHeader.read}
+ * method. Next, the RecordList section is read and the {@code Record}
+ * offsets are stored for use when parsing the Records. Based on these
+ * offsets, the bytes corresponding to each {@code Record} are read and
+ * each is stored in a {@code Record} object. Lastly, the data is used
+ * to create a {@code PalmDB} object.</p>
+ *
+ * @param b {@code byte[]} 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 lastIndex = header.numRecords - 1;
+
+ for (int i = 0; i < lastIndex; i++) {
+
+ //dis.seek(recOffset[i]);
+ dis.reset();
+ int nBytesToSkip = recOffset[i];
+ while (nBytesToSkip > 0) {
+ nBytesToSkip -= dis.skip(nBytesToSkip);
+ }
+ int len = recOffset[i+1] - recOffset[i];
+ byte[] bytes = new byte[len];
+ dis.readFully(bytes);
+ recArray[i] = new Record(bytes, recAttrs[i]);
+ }
+
+ // last record
+ dis.reset();
+ int len = dis.available() - recOffset[lastIndex];
+ int nBytesToSkip = recOffset[lastIndex];
+ while (nBytesToSkip > 0) {
+ nBytesToSkip -= dis.skip(nBytesToSkip);
+ }
+ byte[] 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 000000000..ba32aed20
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbEncoder.java
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+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;
+
+/**
+ * Provides functionality to encode a {@code PalmDB} object into a PDB
+ * formatted file given a file {@code OutputStream}.
+ *
+ * <p>This class is only used by the {@code PalmDB} object.</p>
+ *
+ * <p>One needs to create one {@code PdbEncoder} object per {@code PalmDB}
+ * object to be encoded. This class keeps the PDB header data and functionality
+ * in the {@code PdbHeader} class.</p>
+ *
+ * <p>Sample usage:</p>
+ * <blockquote><pre>{@code PdbEncoder encoder = new PdbEncoder(palmDB, "STRW", "data");
+ * encoder.write(new FileOutputStream("sample.pdb"));}</pre></blockquote>
+ *
+ * @see PalmDB
+ * @see Record
+ */
+public final class PdbEncoder {
+
+ /** PDB header. */
+ private final PdbHeader header;
+
+ /** the PalmDB object. */
+ private final PalmDB db;
+
+ /** The pattern for unique_id=0x00BABE(start). */
+ private static final int START_UNIQUE_ID = 0x00BABE;
+
+
+ /**
+ * Constructor.
+ *
+ * @param db The {@code PalmDB} 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();
+ }
+
+ /**
+ * Write out a PDB into the given {@code OutputStream}.
+ *
+ * <p>First, write out the header data by using the {@code PdbHeader.write}
+ * method. Next, calculate the RecordList section and write it out. Lastly,
+ * write out the bytes corresponding to each {@code Record}.</p>
+ *
+ * <p>The RecordList section contains a list of {@code Record} index info,
+ * where each {@code Record} index info contains:</p>
+ *
+ * <ul>
+ * <li>4 bytes local offset of the {@code Record} from the top of the
+ * PDB.</li>
+ * <li>1 byte of {@code Record} attribute.</li>
+ * <li>3 bytes unique {@code Record} ID.</li>
+ * </ul>
+ *
+ * <p>There should be a total of {@code header.numRecords} of {@code Record}
+ * index info.</p>
+ *
+ * @param os {@code OutputStream} 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 = (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();
+ }
+} \ No newline at end of file
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 000000000..280c6e3db
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbHeader.java
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+package org.openoffice.xmerge.converter.palm;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * Class used only internally by {@code PdbEncoder} and {@code PdbDecoder} to
+ * store, read and write a PDB header.
+ *
+ * <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} and {@code write} methods should handle them
+ * properly.</p>
+ *
+ * @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. */
+ private long lastBackupDate = 0;
+
+ /**
+ * Incremented every time a {@code Record} is added, deleted or modified.
+ * Palm UInt32.
+ */
+ private long modificationNumber = 0;
+
+ /** Optional field. Palm UInt32. Unsignedness should be irrelevant. */
+ private int appInfoID = 0;
+
+ /** Optional field. Palm UInt32. Unsignedness should be irrelevant. */
+ private 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;
+
+ /** ??? */
+ private int uniqueIDSeed = 0;
+
+ /** See numRecords. 4 bytes. */
+ private int nextRecordListID = 0;
+
+ /**
+ * Number of Records stored in the database header.
+ * If all the {@code Record} entries cannot fit in the header, then
+ * {@code nextRecordList} has the local ID of a RecordList that contains
+ * the next set of {@code Record}.
+ * Palm UInt16.
+ */
+ int numRecords = 0;
+
+ /**
+ * Read in the data for the PDB header.
+ *
+ * <p>Need to preserve the unsigned value for some of the fields.</p>
+ *
+ * @param in A {@code DataInput} 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 = in.readInt() & 0xffffffffL;
+ modificationDate = in.readInt() & 0xffffffffL;
+ lastBackupDate = in.readInt() & 0xffffffffL;
+ modificationNumber = 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} 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);
+ }
+} \ No newline at end of file
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 000000000..829c1c733
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/PdbUtil.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+package org.openoffice.xmerge.converter.palm;
+
+/**
+ * Contains common static methods and constants for use within the package.
+ */
+public final class PdbUtil {
+
+ /** Difference in seconds from Jan 01, 1904 to Jan 01, 1970. */
+ static final long TIME_DIFF = 2082844800;
+
+ /** Encoding scheme used. */
+ static final String ENCODING = "8859_1";
+
+ /** Size of a PDB header in bytes. */
+ static final int HEADER_SIZE = 78;
+
+} \ No newline at end of file
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 000000000..12d7a0256
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/Record.java
@@ -0,0 +1,176 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+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;
+
+/**
+ * Contains the raw bytes for a {@code Record} in a PDB.
+ *
+ * <p>Note that it is not associated with a {@code Record} number or ID.</p>
+ *
+ * @see PalmDocument
+ * @see PalmDB
+ */
+public final class Record {
+
+ /** {@code Record} {@code byte} array. */
+ private byte[] data;
+
+ /** {@code Record} attributes. */
+ private byte attributes = 0;
+
+ /**
+ * Default constructor.
+ */
+ public Record() {
+ data = new byte[0];
+ }
+
+ /**
+ * Constructor to create a {@code Record} filled with bytes.
+ *
+ * <p>Note that this does not check for 64k {@code Record} sizes. User of
+ * this class must check for that.</p>
+ *
+ * @param d {@code byte} array contents for this object.
+ */
+ public Record(byte[] d) {
+ this(d, (byte) 0);
+ }
+
+ /**
+ * Constructor to create a {@code Record} filled with bytes and assign
+ * {@code Record} attributes.
+ *
+ * <p>Note that this does not check for 64k {@code Record} sizes. User of
+ * this class must check for that.</p>
+ *
+ * @param d {@code byte} array contents for this object.
+ * @param attrs {@code Record} 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}.
+ *
+ * @return Contents in {@code byte} array
+ */
+ public byte[] getBytes() {
+ return data;
+ }
+
+ /**
+ * <p>This method returns the {@code Record} attributes.</p>
+ *
+ * <blockquote><pre>{@code Record} attributes consists of (from high to low bit)
+ *
+ * delete (1) - dirty (1) - busy (1) - secret (1) - category (4)</pre></blockquote>
+ *
+ * @return {@code Record} attribute.
+ */
+ public byte getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * Write out the {@code Record} attributes and {@code Record} length
+ * followed by the data in this {@code Record} object.
+ *
+ * @param outs The {@code OutputStream} 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}.
+ *
+ * @param ins The {@code InputStream} to read data from in order to
+ * restore the {@code object}.
+ *
+ * @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);
+ }
+
+ /**
+ * Override equals method of {@code Object}.
+ *
+ * <p>Two {@code Record} 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} object to compare with
+ *
+ * @return {@code true} if {@code obj} is equal, otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Record)) {
+ return false;
+ }
+ Record rec = (Record) obj;
+ if (rec.getAttributes() != attributes) {
+ return false;
+ }
+ if (rec.getSize() == data.length) {
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] != rec.data[i]) {
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+}
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package-info.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package-info.java
new file mode 100644
index 000000000..4cc9fcd90
--- /dev/null
+++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm/package-info.java
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+/**
+ * Provides classes for converting Palm database data to/from a
+ * {@code PalmDocument} object, which can be used by the framework.
+ *
+ * <p>This package provides classes that handle the writing of data to an
+ * {@code OutputStream} object for the {@link
+ * org.openoffice.xmerge.DocumentSerializer DocumentSerializer} interface for;
+ * as well as the reading of data from an {@code InputStream} 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"></a>
+ *
+ * <h2>Palm database converter specific I/O stream format</h2>
+ *
+ * <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} class takes care of the writing and reading
+ * of this format through its {@code write} and {@code read} 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}
+ * object via the {@code DocumentSerializer} 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}.
+ * Thus, if there is more than one worksheet in the document, more than one
+ * {@code PalmDocument} will be produced by the {@code DocumentSerializer}.</p>
+ *
+ * <p>A {@code DocumentSerializer} creates a {@code ConvertData} object, which
+ * contains all of the {@code PalmDocuments}. The {@link
+ * org.openoffice.xmerge.converter.palm.PalmDocument#write write} method to
+ * write to the given {@code OutputStream}.
+ * The {@code PalmDocument} object will take care of writing the data in the
+ * <a href=#streamformat>specified format</a>.</p>
+ *
+ * <p>A {@code DocumentDeserializer} can use the {@code PalmDocument} object's
+ * {@link org.openoffice.xmerge.converter.palm.PalmDocument#read read} method
+ * to fill in all the {@code PalmDocument} object's data.</p>
+ *
+ * <h2>PDB file encoding/decoding</h2>
+ *
+ * <p>The {@code PalmDocument} object's read and write functions are provided by
+ * the {@code PdbDecoder} and {@code PdbEncoder} objects.
+ * The {@code PdbEncoder} class provides the functionality of encoding a
+ * {@code PalmDB} object into an {@code InputStream}, while the
+ * {@code PdbDecoder} class provides the functionality of decoding a PDB file
+ * into an {@code OutputStream}.</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>
+ *
+ * <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>
+ */
+package org.openoffice.xmerge.converter.palm;