Add input and output jars as inputs for VMCompactLibraryTask.
[SquirrelJME.git] / buildSrc / src / main / java / cc / squirreljme / plugin / palmos / PalmDatabaseBuilder.java
blob61da14a3c92a46d56f61f0f8bcfc9258b957aed1
1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
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;
19 import java.util.Set;
21 /**
22 * This class is used to build PalmOS databases and resource databases.
24 * @since 2019/07/13
26 public final class PalmDatabaseBuilder
28 /** The limit to the name length. */
29 private static final int _NAME_LIMIT =
30 32;
32 /** Difference in the epoch in seconds. */
33 private static final long _EPOCH_DIFF_SECONDS =
34 2082844800L;
36 /** Difference in the epoch in milliseconds. */
37 private static final long _EPOCH_DIFF_MILLISECONDS =
38 2082844800_000L;
40 /** The type of database to create. */
41 protected final PalmDatabaseType dbtype;
43 /** Attributes within the database. */
44 private final Set<PalmDatabaseAttribute> _attributes =
45 new HashSet<>();
47 /** The entries within the database. */
48 private final List<PalmRecord> _records =
49 new ArrayList<>();
51 /** The creator of the database. */
52 private String _creator =
53 "????";
55 /** The type of the database. */
56 private String _type =
57 "????";
59 /** The name of the database. */
60 private String _name =
61 "Untitled";
63 /** Creation time. */
64 private long _createtime =
65 System.currentTimeMillis();
67 /** Modification time */
68 private long _modtime =
69 this._createtime;
71 /** Backup time. */
72 private long _backuptime =
75 /** Modification number. */
76 private int _modcount =
79 /** The version. */
80 private int _version =
83 /**
84 * Initializes the database builder.
86 * @param __type The database type.
87 * @throws NullPointerException On null arguments.
88 * @since 2019/07/13
90 public PalmDatabaseBuilder(PalmDatabaseType __type)
91 throws NullPointerException
93 if (__type == null)
94 throw new NullPointerException("NARG");
96 this.dbtype = __type;
99 /**
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.
106 * @since 2019/07/13
108 public final OutputStream addEntry(String __type, int __id)
109 throws NullPointerException
111 if (__type == null)
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}.
123 * @since 2019/07/13
125 public final PalmDatabaseBuilder setAttributes(
126 PalmDatabaseAttribute... __a)
128 if (__a == null)
129 return this;
131 // Add the attributes
132 Set<PalmDatabaseAttribute> attributes = this._attributes;
133 for (PalmDatabaseAttribute attr : __a)
134 if (attr != null)
135 attributes.add(attr);
137 // Return self
138 return this;
142 * Sets the backup time.
144 * @param __jt Java milliseconds time.
145 * @return {@code this}.
146 * @since 2019/07/13
148 public final PalmDatabaseBuilder setBackupTime(long __jt)
150 this._backuptime = __jt;
151 return this;
155 * Sets the creation time.
157 * @param __jt Java milliseconds time.
158 * @return {@code this}.
159 * @since 2019/07/13
161 public final PalmDatabaseBuilder setCreateTime(long __jt)
163 this._createtime = __jt;
164 return this;
168 * Sets the creator of the database.
170 * @param __creat The creator to use.
171 * @return {@code this}.
172 * @throws NullPointerException On null arguments.
173 * @since 2019/07/13
175 public final PalmDatabaseBuilder setCreator(String __creat)
176 throws NullPointerException
178 if (__creat == null)
179 throw new NullPointerException("NARG");
181 this._creator = __creat;
182 return this;
186 * Sets the modification count.
188 * @param __c The count to use.
189 * @return {@code this}.
190 * @since 2019/07/13
192 public final PalmDatabaseBuilder setModificationCount(int __c)
194 this._modcount = __c;
195 return this;
199 * Sets the modification time.
201 * @param __jt Java milliseconds time.
202 * @return {@code this}.
203 * @since 2019/07/13
205 public final PalmDatabaseBuilder setModificationTime(long __jt)
207 this._modtime = __jt;
208 return this;
212 * Sets the name of the database.
214 * @param __name The name to use.
215 * @return {@code this}.
216 * @throws NullPointerException On null arguments.
217 * @since 2019/07/13
219 public final PalmDatabaseBuilder setName(String __name)
220 throws NullPointerException
222 if (__name == null)
223 throw new NullPointerException("NARG");
225 this._name = __name;
226 return this;
230 * Sets the type of the database.
232 * @param __type The type to use.
233 * @return {@code this}.
234 * @throws NullPointerException On null arguments.
235 * @since 2019/07/13
237 public final PalmDatabaseBuilder setType(String __type)
238 throws NullPointerException
240 if (__type == null)
241 throw new NullPointerException("NARG");
243 this._type = __type;
244 return this;
248 * Sets the version number.
250 * @param __v The version number.
251 * @return {@code this}.
252 * @since 2019/07/13
254 public final PalmDatabaseBuilder setVersion(int __v)
256 this._version = __v;
257 return this;
261 * Returns the byte array representing the database.
263 * @return The byte array of the database.
264 * @since 2019/07/13
266 public final byte[] toByteArray()
268 // Just write to a stream
269 try (ByteArrayOutputStream baos = new ByteArrayOutputStream())
271 // Write the database info
272 this.writeTo(baos);
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.
291 * @since 2019/07/13
293 public final void writeTo(OutputStream __out)
294 throws IOException, NullPointerException
296 if (__out == null)
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));
308 // Pad shorter names
309 for (int i = namelen; i < PalmDatabaseBuilder._NAME_LIMIT; i++)
310 dos.write(0);
312 // Determine attribute bit-field
313 int attrs = 0;
314 for (PalmDatabaseAttribute attr : this._attributes)
315 attrs |= attr.bit;
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;
320 boolean isrc;
321 if ((isrc = (dbtype == PalmDatabaseType.RESOURCE)))
322 attrs |= PalmDatabaseAttribute.RESOURCE_DATABASE.bit;
323 else
324 attrs &= ~PalmDatabaseAttribute.RESOURCE_DATABASE.bit;
326 // Write attributes
327 dos.writeShort(attrs);
329 // Write version
330 dos.writeShort(this._version);
332 // Creation/Modification/Backup Time (In Mac OS epoch seconds)
333 dos.writeInt(
334 (int)((this._createtime + PalmDatabaseBuilder._EPOCH_DIFF_MILLISECONDS) / 1000L));
335 dos.writeInt(
336 (int)((this._modtime + PalmDatabaseBuilder._EPOCH_DIFF_MILLISECONDS) / 1000L));
337 dos.writeInt(
338 (int)((this._backuptime + PalmDatabaseBuilder._EPOCH_DIFF_MILLISECONDS) / 1000L));
340 // Modification count
341 dos.writeInt(this._modcount);
343 // Application Info
344 dos.writeInt(0);
346 // Sorting info
347 dos.writeInt(0);
349 // Type
350 dos.writeInt(PalmDatabaseBuilder.__fourToInt(this._type));
352 // Creator
353 dos.writeInt(PalmDatabaseBuilder.__fourToInt(this._creator));
355 // Unique ID
356 dos.writeInt(0);
358 // Next record list (unused in files)
359 dos.writeInt(0);
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);
376 // Resource entry
377 if (isrc)
379 // Type
380 dos.writeInt(PalmDatabaseBuilder.__fourToInt(pr.type));
382 // ID
383 dos.writeShort(pr.id);
385 // Offset
386 dos.writeInt(offset);
389 // Database entry
390 else
392 // Offset
393 dos.writeInt(offset);
395 // No attributes
396 dos.write(0);
398 // Unique ID (padding)
399 dos.write(0);
400 dos.write(0);
401 dos.write(0);
404 // Offset is increased by length
405 offset += pr.length;
408 // Write all records
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.
419 * @since 2019/07/13
421 private static int __fourToInt(String __four)
422 throws NullPointerException
424 if (__four == null)
425 throw new NullPointerException("NARG");
427 // There must be at least four characters
428 String use = __four;
429 if (__four.length() < 4)
431 StringBuilder sb = new StringBuilder();
432 sb.append(__four);
433 sb.setLength(4);
434 use = sb.toString();
437 // Convert
438 return ((__four.charAt(0) & 0xFF) << 24) |
439 ((__four.charAt(1) & 0xFF) << 16) |
440 ((__four.charAt(2) & 0xFF) << 8) |
441 ((__four.charAt(3) & 0xFF));