/************************************************************** * * 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.xml.sxw.wordsmith; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.*; import java.io.UnsupportedEncodingException; import java.util.List; import java.util.ArrayList; import java.util.Vector; import org.openoffice.xmerge.converter.palm.*; /** * This class is used by {@link * org.openoffice.xmerge.converter.xml.sxw.wordsmith.DocumentDeserializerImpl * DocumentDeserializerImpl} to encode the WordSmith format. * * @author David Proulx */ // DJP: replace 4096 w/ a defined constant final class WSEncoder { /* DJP: These should probably go somewhere else! */ /** Constant for uncompressed version. */ public static final short UNCOMPRESSED = 1; /** Constant for compressed version. */ public static final short COMPRESSED = 2; /** Constant used for spare fields. */ public static final int SPARE = 0; /* WordSmith Header information. */ private short version; private int textLen; private short maxRecSize; private int textRecCount = 0; /* WordSmith document elements. */ WseHeader header = null; WseFontTable ft = null; WseColorTable ct = null; private Vector elements; // paragraphs & text runs /* Totals for the WordSmith document. */ int nrParagraphs = 0; int nrAtoms = 0; int nrChars = 0; /** * Default constructor creates a header and * a text buffer for holding all the text in * the WordSmith database. */ WSEncoder() { version = 1; textLen = 0; maxRecSize = 4096; elements = new Vector(); } /** * This method adds a new element to the WordSmith document. * * @param elem WordSmith document element to add */ void addElement(Wse elem) { if (elem.getClass() == WseHeader.class) header = (WseHeader)elem; else if (elem.getClass() == WseFontTable.class) ft = (WseFontTable)elem; else if (elem.getClass() == WseColorTable.class) ct = (WseColorTable)elem; else elements.addElement(elem); } /** * This method encodes the information given to * an array of palm Records in the WordSmith database format. * * @return Record array holding WordSmith contents. * * @throws IOException If any I/O error occurs. */ Record[] getRecords() throws IOException { Vector allRecs = new Vector(); int nElements = elements.size(); // Count up the number of paragraphs, atoms, and characters. int currElement = 0; while (currElement < nElements) { Wse e = (Wse)elements.elementAt(currElement++); if (e.getClass() == WsePara.class) nrParagraphs++; if (e.getClass() == WseTextRun.class) { nrAtoms++; nrChars += ((WseTextRun)e).getText().length(); } } byte[] currRec = new byte[4096]; int currRecLen = 0; // This code assumes that the WordSmith header, font table, // and color table total less than 4096 bytes. header = new WseHeader(nrParagraphs, nrAtoms, nrChars, ft, ct); System.arraycopy(header.getBytes(), 0, currRec, currRecLen, header.getByteCount()); currRecLen += header.getByteCount(); if (ft != null) { System.arraycopy(ft.getBytes(), 0, currRec, currRecLen, ft.getByteCount()); currRecLen += ft.getByteCount(); } if (ct != null) { System.arraycopy(ct.getBytes(), 0, currRec, currRecLen, ct.getByteCount()); currRecLen += ct.getByteCount(); } currElement = 0; while (currElement < nElements) { Wse e = (Wse)elements.elementAt(currElement++); int length = e.getByteCount(); if ((length + currRecLen) <= 4096) { System.arraycopy(e.getBytes(), 0, currRec, currRecLen, length); currRecLen += length; } else { // Copy in enough to get to full size, then create a // new Record and add it to the Vector. int firstPartLen = 4096 - currRecLen; System.arraycopy(e.getBytes(), 0, currRec, currRecLen, firstPartLen); Record r = new Record(currRec); allRecs.addElement(r); // Put the remainder at the beginning of the next record currRecLen = 0; System.arraycopy(e.getBytes(), firstPartLen, currRec, currRecLen, length - firstPartLen); currRecLen += length - firstPartLen; } } // Processed all the elements. Write out any remaining partial record. if (currRecLen > 0) { byte[] partial = new byte[currRecLen]; System.arraycopy(currRec, 0, partial, 0, currRecLen); Record rr = new Record(partial); allRecs.addElement(rr); } // Record 0 is the WordSmith header. Do it last since it // contains totals for the entire document. It goes // before everything else. ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); dos.writeShort(version); dos.writeShort(0); dos.writeInt(textLen); dos.writeShort(allRecs.size()); dos.writeShort(maxRecSize); dos.writeInt(0); allRecs.insertElementAt(new Record(bos.toByteArray()), 0); // Convert Vector of Records to an array and return it. int nRecs = allRecs.size(); Record recs[] = new Record[nRecs]; for (int i = 0; i < nRecs; i++) recs[i] = (Record)allRecs.elementAt(i); return recs; } }