1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 package org.openoffice.xmerge.converter.xml.sxw.wordsmith; 25 26 import java.io.ByteArrayOutputStream; 27 import java.io.DataOutputStream; 28 import java.io.*; 29 import java.io.UnsupportedEncodingException; 30 import java.util.List; 31 import java.util.ArrayList; 32 import java.util.Vector; 33 34 import org.openoffice.xmerge.converter.palm.*; 35 36 /** 37 * This class is used by {@link 38 * org.openoffice.xmerge.converter.xml.sxw.wordsmith.DocumentDeserializerImpl 39 * DocumentDeserializerImpl} to encode the WordSmith format. 40 * 41 * @author David Proulx 42 */ 43 44 // DJP: replace 4096 w/ a defined constant 45 46 final class WSEncoder { 47 48 /* DJP: These should probably go somewhere else! */ 49 /** Constant for uncompressed version. */ 50 public static final short UNCOMPRESSED = 1; 51 52 /** Constant for compressed version. */ 53 public static final short COMPRESSED = 2; 54 55 /** Constant used for spare fields. */ 56 public static final int SPARE = 0; 57 58 /* WordSmith Header information. */ 59 private short version; 60 private int textLen; 61 private short maxRecSize; 62 private int textRecCount = 0; 63 64 65 /* WordSmith document elements. */ 66 WseHeader header = null; 67 WseFontTable ft = null; 68 WseColorTable ct = null; 69 private Vector elements; // paragraphs & text runs 70 71 /* Totals for the WordSmith document. */ 72 int nrParagraphs = 0; 73 int nrAtoms = 0; 74 int nrChars = 0; 75 76 77 /** 78 * Default constructor creates a header and 79 * a text buffer for holding all the text in 80 * the WordSmith database. 81 */ WSEncoder()82 WSEncoder() { 83 version = 1; 84 textLen = 0; 85 maxRecSize = 4096; 86 elements = new Vector(); 87 } 88 89 90 /** 91 * This method adds a new element to the WordSmith document. 92 * 93 * @param elem WordSmith document element to add 94 */ addElement(Wse elem)95 void addElement(Wse elem) { 96 if (elem.getClass() == WseHeader.class) 97 header = (WseHeader)elem; 98 else if (elem.getClass() == WseFontTable.class) 99 ft = (WseFontTable)elem; 100 else if (elem.getClass() == WseColorTable.class) 101 ct = (WseColorTable)elem; 102 else 103 elements.addElement(elem); 104 } 105 106 107 /** 108 * This method encodes the information given to 109 * an array of palm Records in the WordSmith database format. 110 * 111 * @return <code>Record</code> array holding WordSmith contents. 112 * 113 * @throws IOException If any I/O error occurs. 114 */ getRecords()115 Record[] getRecords() throws IOException { 116 117 Vector allRecs = new Vector(); 118 int nElements = elements.size(); 119 120 // Count up the number of paragraphs, atoms, and characters. 121 int currElement = 0; 122 while (currElement < nElements) { 123 Wse e = (Wse)elements.elementAt(currElement++); 124 if (e.getClass() == WsePara.class) 125 nrParagraphs++; 126 if (e.getClass() == WseTextRun.class) { 127 nrAtoms++; 128 nrChars += ((WseTextRun)e).getText().length(); 129 } 130 } 131 132 byte[] currRec = new byte[4096]; 133 int currRecLen = 0; 134 135 // This code assumes that the WordSmith header, font table, 136 // and color table total less than 4096 bytes. 137 header = new WseHeader(nrParagraphs, nrAtoms, nrChars, ft, ct); 138 System.arraycopy(header.getBytes(), 0, 139 currRec, currRecLen, header.getByteCount()); 140 currRecLen += header.getByteCount(); 141 142 if (ft != null) { 143 System.arraycopy(ft.getBytes(), 0, currRec, currRecLen, 144 ft.getByteCount()); 145 currRecLen += ft.getByteCount(); 146 } 147 if (ct != null) { 148 System.arraycopy(ct.getBytes(), 0, currRec, currRecLen, 149 ct.getByteCount()); 150 currRecLen += ct.getByteCount(); 151 } 152 153 currElement = 0; 154 while (currElement < nElements) { 155 Wse e = (Wse)elements.elementAt(currElement++); 156 int length = e.getByteCount(); 157 if ((length + currRecLen) <= 4096) { 158 System.arraycopy(e.getBytes(), 0, currRec, currRecLen, length); 159 currRecLen += length; 160 } else { 161 // Copy in enough to get to full size, then create a 162 // new Record and add it to the Vector. 163 int firstPartLen = 4096 - currRecLen; 164 System.arraycopy(e.getBytes(), 0, currRec, currRecLen, 165 firstPartLen); 166 Record r = new Record(currRec); 167 allRecs.addElement(r); 168 169 // Put the remainder at the beginning of the next record 170 currRecLen = 0; 171 System.arraycopy(e.getBytes(), firstPartLen, currRec, 172 currRecLen, length - firstPartLen); 173 currRecLen += length - firstPartLen; 174 } 175 } 176 177 // Processed all the elements. Write out any remaining partial record. 178 if (currRecLen > 0) { 179 byte[] partial = new byte[currRecLen]; 180 System.arraycopy(currRec, 0, partial, 0, currRecLen); 181 Record rr = new Record(partial); 182 allRecs.addElement(rr); 183 } 184 185 186 // Record 0 is the WordSmith header. Do it last since it 187 // contains totals for the entire document. It goes 188 // before everything else. 189 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 190 DataOutputStream dos = new DataOutputStream(bos); 191 dos.writeShort(version); 192 dos.writeShort(0); 193 dos.writeInt(textLen); 194 dos.writeShort(allRecs.size()); 195 dos.writeShort(maxRecSize); 196 dos.writeInt(0); 197 allRecs.insertElementAt(new Record(bos.toByteArray()), 0); 198 199 // Convert Vector of Records to an array and return it. 200 int nRecs = allRecs.size(); 201 Record recs[] = new Record[nRecs]; 202 for (int i = 0; i < nRecs; i++) 203 recs[i] = (Record)allRecs.elementAt(i); 204 return recs; 205 } 206 207 } 208 209