blob: 68bd04b3886836506cafd6727f4d2d96aede3e9d [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
package org.openoffice.xmerge.converter.palm;
import java.io.OutputStream;
import java.io.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();
}
}