1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 import java.io.OutputStream; 29 import java.io.InputStream; 30 import java.io.DataOutputStream; 31 import java.io.DataInputStream; 32 import java.io.IOException; 33 import java.io.UnsupportedEncodingException; 34 35 /** 36 * <p>This class contains data for a single Palm database for use during 37 * a conversion process.</p> 38 * 39 * <p>It contains zero or more <code>Record</code> objects stored in an 40 * array. The index of the <code>Record</code> object in the array is 41 * the record id or number for that specific <code>Record</code> object. 42 * Note that this class does not check for maximum number of records 43 * allowable in an actual pdb.</p> 44 * 45 * <p>This class also contains the pdb name associated with the Palm database 46 * it represents. A pdb name consists of 32 bytes of a certain encoding 47 * (extended ASCII in this case).</p> 48 * 49 * <p>The non default constructors take in a name parameter which may not 50 * be the exact pdb name to be used. The name parameter in 51 * <code>String</code> or <code>byte[]</code> are converted to an exact 52 * <code>NAME_LENGTH</code> byte array. If the length of the name is less 53 * than <code>NAME_LENGTH</code>, it is padded with '\0' characters. If it 54 * is more, it gets truncated. The last character in the resulting byte 55 * array is always a '\0' character. The resulting byte array is stored in 56 * <code>bName</code>, and a corresponding String object <code>sName</code> 57 * that contains characters without the '\0' characters.</p> 58 * 59 * <p>The {@link #write write} method is called within the 60 * {@link zensync.util.palm.PalmDBSet#write PalmDBSet.write} method 61 * for writing out its data to the <code>OutputStream</code> object.</p> 62 * 63 * <p>The {@link #read read} method is called within the 64 * {@link zensync.util.palm.PalmDBSet#read PalmDBSet.read} method 65 * for reading in its data from the <code>InputStream</code> object.</p> 66 * 67 * @author Akhil Arora, Herbie Ong 68 * @see PalmDBSet 69 * @see Record 70 */ 71 72 public final class PalmDB { 73 74 /** number of bytes for the name field in the pdb */ 75 public final static int NAME_LENGTH = 32; 76 77 /** list of Record objects */ 78 private Record[] records; 79 80 /** pdb name in bytes */ 81 private byte[] bName = null; 82 83 /** pdb name in String */ 84 private String sName = null; 85 86 87 /** 88 * Default constructor for use after a read(). 89 */ 90 91 public PalmDB() { 92 93 records = new Record[0]; 94 } 95 96 /** 97 * Constructor to create object with Record objects. 98 * recs.length can be zero for an empty pdb. 99 * 100 * @param name suggested pdb name in String 101 * @param recs array of Record objects 102 * @throws NullPointerException if recs is null 103 */ 104 105 public PalmDB(String name, Record[] recs) 106 throws UnsupportedEncodingException { 107 108 this(name.getBytes(PDBUtil.ENCODING), recs); 109 } 110 111 /** 112 * Constructor to create object with Record objects. 113 * recs.length can be zero for an empty pdb. 114 * 115 * @param name suggested pdb name in byte array 116 * @param recs array of Record objects 117 * @throws NullPointerException if recs is null 118 */ 119 120 public PalmDB(byte[] name, Record[] recs) 121 throws UnsupportedEncodingException { 122 123 store(name); 124 125 records = new Record[recs.length]; 126 System.arraycopy(recs, 0, records, 0, recs.length); 127 } 128 129 /** 130 * This private method is mainly used by the constructors above. 131 * to store bytes into name and also create a String representation. 132 * and also by the read method. 133 * 134 * TODO: Note that this method assumes that the byte array parameter 135 * contains one character per byte, else it would truncate 136 * improperly. 137 * 138 * @param bytes pdb name in byte array 139 * @throws UnsupportedEncodingException if ENCODING is not supported 140 */ 141 142 private void store(byte[] bytes) throws UnsupportedEncodingException { 143 144 // note that this will initialize all bytes in name to 0. 145 bName = new byte[NAME_LENGTH]; 146 147 // determine minimum length to copy over from bytes to bName. 148 // Note that the last byte in bName has to be '\0'. 149 150 int lastIndex = NAME_LENGTH - 1; 151 152 int len = (bytes.length < lastIndex)? bytes.length: lastIndex; 153 154 int i; 155 156 for (i = 0; i < len; i++) { 157 158 if (bytes[i] == 0) { 159 break; 160 } 161 162 bName[i] = bytes[i]; 163 } 164 165 // set sName, no need to include the '\0' character. 166 sName = new String(bName, 0, i, PDBUtil.ENCODING); 167 } 168 169 /** 170 * Return the number of records contained in this 171 * pdb PalmDB object. 172 * 173 * @return int number of Record objects 174 */ 175 176 public int getRecordCount() { 177 178 return records.length; 179 } 180 181 /** 182 * Return the specific Record object associated 183 * with the record number. 184 * 185 * @param index record index number 186 * @return Record the Record object in the specified index 187 * @throws ArrayIndexOutOfBoundsException if index is out of bounds 188 */ 189 190 public Record getRecord(int index) { 191 192 return records[index]; 193 } 194 195 /** 196 * Return the list of Record objects 197 * 198 * @return Record[] the list of Record objects 199 */ 200 201 public Record[] getRecords() { 202 203 return records; 204 } 205 206 /** 207 * Return the PDBName associated with this object in String 208 * 209 * @return String pdb name in String 210 */ 211 212 public String getPDBNameString() { 213 214 return sName; 215 } 216 217 /** 218 * Return the PDBName associated with this object 219 * in byte array of exact length of 32 bytes. 220 * 221 * @return byte[] pdb name in byte[] of length 32. 222 */ 223 224 public byte[] getPDBNameBytes() { 225 226 return bName; 227 } 228 229 /** 230 * Write out the number of records followed by what 231 * will be written out by each Record object. 232 * 233 * @param os the stream to write the object to 234 * @throws IOException if any I/O error occurs 235 */ 236 237 public void write(OutputStream os) throws IOException { 238 239 DataOutputStream out = new DataOutputStream(os); 240 241 // write out pdb name 242 out.write(bName); 243 244 // write out 2 bytes for number of records 245 out.writeShort(records.length); 246 247 // let each Record object write out its own info. 248 for (int i = 0; i < records.length; i++) 249 records[i].write(out); 250 } 251 252 /** 253 * Read the necessary data to create a pdb from 254 * the input stream. 255 * 256 * @param is the stream to read data from in order 257 * to restore the object 258 * @throws IOException if any I/O error occurs 259 */ 260 261 public void read(InputStream is) throws IOException { 262 263 DataInputStream in = new DataInputStream(is); 264 265 // read in the pdb name. 266 byte[] bytes = new byte[NAME_LENGTH]; 267 in.readFully(bytes); 268 store(bytes); 269 270 // read in number of records 271 int nrec = in.readUnsignedShort(); 272 records = new Record[nrec]; 273 274 // read in the Record infos 275 for (int i = 0; i < nrec; i++) { 276 277 records[i] = new Record(); 278 records[i].read(in); 279 } 280 } 281 282 /** 283 * Override equals method of Object. 284 * 285 * 2 PalmDB objects are equal if they contain the same information, 286 * i.e. pdb name and records. 287 * 288 * This is used primarily for testing purposes only for now. 289 * 290 * @param obj a PalmDB object to compare with 291 * @return boolean true if obj is equal to this, else false. 292 */ 293 294 public boolean equals(Object obj) { 295 296 boolean bool = false; 297 298 if (obj instanceof PalmDB) { 299 300 PalmDB pdb = (PalmDB) obj; 301 302 checkLabel: { 303 304 // compare sName 305 306 if (!sName.equals(pdb.sName)) { 307 308 break checkLabel; 309 } 310 311 // compare bName 312 313 if (bName.length != pdb.bName.length) { 314 315 break checkLabel; 316 } 317 318 for (int i = 0; i < bName.length; i++) { 319 320 if (bName[i] != pdb.bName[i]) { 321 322 break checkLabel; 323 } 324 } 325 326 // compare each Record 327 328 if (records.length != pdb.records.length) { 329 330 break checkLabel; 331 } 332 333 for (int i = 0; i < records.length; i++) { 334 335 if (!records[i].equals(pdb.records[i])) { 336 337 break checkLabel; 338 } 339 } 340 341 // all checks done 342 bool = true; 343 } 344 } 345 346 return bool; 347 } 348 } 349