1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc
.squirreljme
.plugin
.palmos
;
12 import java
.io
.ByteArrayOutputStream
;
13 import java
.io
.DataOutputStream
;
14 import java
.io
.IOException
;
15 import java
.io
.OutputStream
;
16 import java
.util
.ArrayList
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
22 * This class is used to build PalmOS databases and resource databases.
26 public final class PalmDatabaseBuilder
28 /** The limit to the name length. */
29 private static final int _NAME_LIMIT
=
32 /** Difference in the epoch in seconds. */
33 private static final long _EPOCH_DIFF_SECONDS
=
36 /** Difference in the epoch in milliseconds. */
37 private static final long _EPOCH_DIFF_MILLISECONDS
=
40 /** The type of database to create. */
41 protected final PalmDatabaseType dbtype
;
43 /** Attributes within the database. */
44 private final Set
<PalmDatabaseAttribute
> _attributes
=
47 /** The entries within the database. */
48 private final List
<PalmRecord
> _records
=
51 /** The creator of the database. */
52 private String _creator
=
55 /** The type of the database. */
56 private String _type
=
59 /** The name of the database. */
60 private String _name
=
64 private long _createtime
=
65 System
.currentTimeMillis();
67 /** Modification time */
68 private long _modtime
=
72 private long _backuptime
=
75 /** Modification number. */
76 private int _modcount
=
80 private int _version
=
84 * Initializes the database builder.
86 * @param __type The database type.
87 * @throws NullPointerException On null arguments.
90 public PalmDatabaseBuilder(PalmDatabaseType __type
)
91 throws NullPointerException
94 throw new NullPointerException("NARG");
100 * Adds the specified entry.
102 * @param __type The entry type.
103 * @param __id The ID to use.
104 * @return The stream to the entry data.
105 * @throws NullPointerException On null arguments.
108 public final OutputStream
addEntry(String __type
, int __id
)
109 throws NullPointerException
112 throw new NullPointerException("NARG");
114 // Create a record writer to write there
115 return new __RecordWriter__(__type
, __id
, this._records
);
119 * Sets the given attributes.
121 * @param __a The attribute to set.
122 * @return {@code this}.
125 public final PalmDatabaseBuilder
setAttributes(
126 PalmDatabaseAttribute
... __a
)
131 // Add the attributes
132 Set
<PalmDatabaseAttribute
> attributes
= this._attributes
;
133 for (PalmDatabaseAttribute attr
: __a
)
135 attributes
.add(attr
);
142 * Sets the backup time.
144 * @param __jt Java milliseconds time.
145 * @return {@code this}.
148 public final PalmDatabaseBuilder
setBackupTime(long __jt
)
150 this._backuptime
= __jt
;
155 * Sets the creation time.
157 * @param __jt Java milliseconds time.
158 * @return {@code this}.
161 public final PalmDatabaseBuilder
setCreateTime(long __jt
)
163 this._createtime
= __jt
;
168 * Sets the creator of the database.
170 * @param __creat The creator to use.
171 * @return {@code this}.
172 * @throws NullPointerException On null arguments.
175 public final PalmDatabaseBuilder
setCreator(String __creat
)
176 throws NullPointerException
179 throw new NullPointerException("NARG");
181 this._creator
= __creat
;
186 * Sets the modification count.
188 * @param __c The count to use.
189 * @return {@code this}.
192 public final PalmDatabaseBuilder
setModificationCount(int __c
)
194 this._modcount
= __c
;
199 * Sets the modification time.
201 * @param __jt Java milliseconds time.
202 * @return {@code this}.
205 public final PalmDatabaseBuilder
setModificationTime(long __jt
)
207 this._modtime
= __jt
;
212 * Sets the name of the database.
214 * @param __name The name to use.
215 * @return {@code this}.
216 * @throws NullPointerException On null arguments.
219 public final PalmDatabaseBuilder
setName(String __name
)
220 throws NullPointerException
223 throw new NullPointerException("NARG");
230 * Sets the type of the database.
232 * @param __type The type to use.
233 * @return {@code this}.
234 * @throws NullPointerException On null arguments.
237 public final PalmDatabaseBuilder
setType(String __type
)
238 throws NullPointerException
241 throw new NullPointerException("NARG");
248 * Sets the version number.
250 * @param __v The version number.
251 * @return {@code this}.
254 public final PalmDatabaseBuilder
setVersion(int __v
)
261 * Returns the byte array representing the database.
263 * @return The byte array of the database.
266 public final byte[] toByteArray()
268 // Just write to a stream
269 try (ByteArrayOutputStream baos
= new ByteArrayOutputStream())
271 // Write the database info
274 // Return the resulting array
275 return baos
.toByteArray();
278 // {@squirreljme.error BP01 Could not write the database.}
279 catch (IOException e
)
281 throw new RuntimeException("BP01", e
);
286 * Writes the database to the output.
288 * @param __out The output stream.
289 * @throws IOException On write errors.
290 * @throws NullPointerException On null arguments.
293 public final void writeTo(OutputStream __out
)
294 throws IOException
, NullPointerException
297 throw new NullPointerException("NARG");
299 // Open data output to write to
300 DataOutputStream dos
= new DataOutputStream(__out
);
302 // Write the name bytes
303 byte[] namebytes
= this._name
.getBytes("utf-8");
304 int namelen
= namebytes
.length
;
305 dos
.write(namebytes
, 0, Math
.min(namelen
,
306 PalmDatabaseBuilder
._NAME_LIMIT
));
309 for (int i
= namelen
; i
< PalmDatabaseBuilder
._NAME_LIMIT
; i
++)
312 // Determine attribute bit-field
314 for (PalmDatabaseAttribute attr
: this._attributes
)
317 // Make sure the attribute flag is always correct because if it was
318 // specified it would make the database not valid to be handled
319 PalmDatabaseType dbtype
= this.dbtype
;
321 if ((isrc
= (dbtype
== PalmDatabaseType
.RESOURCE
)))
322 attrs
|= PalmDatabaseAttribute
.RESOURCE_DATABASE
.bit
;
324 attrs
&= ~PalmDatabaseAttribute
.RESOURCE_DATABASE
.bit
;
327 dos
.writeShort(attrs
);
330 dos
.writeShort(this._version
);
332 // Creation/Modification/Backup Time (In Mac OS epoch seconds)
334 (int)((this._createtime
+ PalmDatabaseBuilder
._EPOCH_DIFF_MILLISECONDS
) / 1000L));
336 (int)((this._modtime
+ PalmDatabaseBuilder
._EPOCH_DIFF_MILLISECONDS
) / 1000L));
338 (int)((this._backuptime
+ PalmDatabaseBuilder
._EPOCH_DIFF_MILLISECONDS
) / 1000L));
340 // Modification count
341 dos
.writeInt(this._modcount
);
350 dos
.writeInt(PalmDatabaseBuilder
.__fourToInt(this._type
));
353 dos
.writeInt(PalmDatabaseBuilder
.__fourToInt(this._creator
));
358 // Next record list (unused in files)
361 // Need to work with records now
362 List
<PalmRecord
> records
= this._records
;
363 int numrecords
= records
.size();
365 // Write record count
366 dos
.writeShort(numrecords
);
368 // Determine the base offset for entry data
369 int offset
= 78 + ((isrc ?
10 : 8) * numrecords
);
371 // Write table data for records
372 for (int i
= 0; i
< numrecords
; i
++)
374 PalmRecord pr
= records
.get(i
);
380 dos
.writeInt(PalmDatabaseBuilder
.__fourToInt(pr
.type
));
383 dos
.writeShort(pr
.id
);
386 dos
.writeInt(offset
);
393 dos
.writeInt(offset
);
398 // Unique ID (padding)
404 // Offset is increased by length
409 for (int i
= 0; i
< numrecords
; i
++)
410 dos
.write(records
.get(i
)._data
);
414 * Converts a four string to an integer.
416 * @param __four The string to convert.
417 * @return The resulting value.
418 * @throws NullPointerException On null arguments.
421 private static int __fourToInt(String __four
)
422 throws NullPointerException
425 throw new NullPointerException("NARG");
427 // There must be at least four characters
429 if (__four
.length() < 4)
431 StringBuilder sb
= new StringBuilder();
438 return ((__four
.charAt(0) & 0xFF) << 24) |
439 ((__four
.charAt(1) & 0xFF) << 16) |
440 ((__four
.charAt(2) & 0xFF) << 8) |
441 ((__four
.charAt(3) & 0xFF));