diff options
Diffstat (limited to 'xmerge/source/xmerge/java/org/openoffice/xmerge/converter/palm')
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; |