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