Make Exported just be SquirrelJMEVendorApi.
[SquirrelJME.git] / modules / tool-manifest-writer / src / main / java / net / multiphasicapps / tool / manifest / writer / MutableJavaManifest.java
blob1f1d0267b55e9b0b2af2dd62318c27e6b4d68b7a
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 net.multiphasicapps.tool.manifest.writer;
12 import cc.squirreljme.jvm.manifest.JavaManifest;
13 import cc.squirreljme.jvm.manifest.JavaManifestAttributes;
14 import cc.squirreljme.jvm.manifest.JavaManifestException;
15 import cc.squirreljme.jvm.manifest.JavaManifestKey;
16 import java.io.ByteArrayInputStream;
17 import java.io.ByteArrayOutputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.OutputStream;
21 import java.io.OutputStreamWriter;
22 import java.io.Writer;
23 import java.util.AbstractMap;
24 import java.util.LinkedHashMap;
25 import java.util.Map;
26 import java.util.Set;
28 /**
29 * This is a mutable version of {@link JavaManifest}.
31 * This class is not thread safe.
33 * @since 2016/09/19
35 public class MutableJavaManifest
36 extends AbstractMap<String, MutableJavaManifestAttributes>
38 /** The maximum number of columns a manifest may have. */
39 private static final int _COLUMN_LIMIT =
40 71;
42 /** Main attributes. */
43 protected final Map<String, MutableJavaManifestAttributes> attributes =
44 new LinkedHashMap<>();
46 /**
47 * This initializes a new empty manifest.
49 * @since 2016/09/19
51 public MutableJavaManifest()
53 // Always add a main attribute
54 this.attributes.put("", new MutableJavaManifestAttributes());
57 /**
58 * Initializes the mutable manifest using a copy of the data from an
59 * immutable manifest.
61 * @param __man The immutable manifest.
62 * @throws NullPointerException On null arguments.
63 * @since 2016/12/26
65 public MutableJavaManifest(JavaManifest __man)
66 throws NullPointerException
68 // Check
69 if (__man == null)
70 throw new NullPointerException("NARG");
72 // Go through and add
73 for (Map.Entry<String, JavaManifestAttributes> e :
74 __man.entrySet())
76 // Create new attribute set
77 MutableJavaManifestAttributes attr;
78 this.put(e.getKey(), (attr = new MutableJavaManifestAttributes()));
80 // Copy values
81 for (Map.Entry<JavaManifestKey, String> f :
82 e.getValue().entrySet())
83 attr.put(f.getKey(), f.getValue());
86 // If no main attributes were set then make sure they exist
87 if (!this.containsKey(""))
88 this.put("", new MutableJavaManifestAttributes());
91 /**
92 * Initializes the mutable manifest using a copy of the data from the
93 * given mutable manifest.
95 * @param __man The mutable manifest to copy from.
96 * @throws NullPointerException On null arguments.
97 * @since 2016/12/26
99 public MutableJavaManifest(MutableJavaManifest __man)
100 throws NullPointerException
102 // Check
103 if (__man == null)
104 throw new NullPointerException("NARG");
106 // Go through and add
107 for (Map.Entry<String, MutableJavaManifestAttributes> e :
108 __man.entrySet())
110 // Create new attribute set
111 MutableJavaManifestAttributes attr;
112 this.put(e.getKey(), (attr = new MutableJavaManifestAttributes()));
114 // Copy values
115 for (Map.Entry<JavaManifestKey, String> f :
116 e.getValue().entrySet())
117 attr.put(f.getKey(), f.getValue());
120 // If no main attributes were set then make sure they exist
121 if (!this.containsKey(""))
122 this.put("", new MutableJavaManifestAttributes());
126 * Builds the specified manifest.
128 * @return The built manifest.
129 * @throws RuntimeException If the manifest could not be built.
130 * @since 2017/11/17
132 public final JavaManifest build()
133 throws RuntimeException
137 byte[] bytes;
138 try (ByteArrayOutputStream baos = new ByteArrayOutputStream())
140 // Write to output
141 this.write(baos);
143 // Extract array
144 bytes = baos.toByteArray();
147 // Read in manifest
148 try (InputStream is = new ByteArrayInputStream(bytes))
150 return new JavaManifest(is);
154 // {@squirreljme.error AB01 Failed to build the immutable manifest
155 // from the mutable one.}
156 catch (IOException e)
158 throw new JavaManifestException("AB01", e);
163 * {@inheritDoc}
164 * @since 2016/09/19
166 @Override
167 public final Set<Map.Entry<String, MutableJavaManifestAttributes>>
168 entrySet()
170 return this.attributes.entrySet();
174 * Returns the mapping of main attributes.
176 * @return The main attribute mapping.
177 * @since 2016/09/19
179 public final MutableJavaManifestAttributes getMainAttributes()
181 return this.get("");
185 * {@inheritDoc}
186 * @since 2016/09/19
188 @Override
189 public final MutableJavaManifestAttributes put(String __k,
190 MutableJavaManifestAttributes __v)
191 throws NullPointerException
193 // Check
194 if (__k == null || __v == null)
195 throw new NullPointerException("NARG");
197 // {@squirreljme.error AB02 The specified value is of the wrong
198 // class type.}
199 if (!(__v instanceof MutableJavaManifestAttributes))
200 throw new ClassCastException("AB02");
202 // Put
203 return this.attributes.put(__k, __v);
207 * Writes the manifest data to the given output stream.
209 * @param __os The stream to get the manifest data written to.
210 * @return {@code __os}.
211 * @throws IOException On write errors.
212 * @throws NullPointerException On null arguments.
213 * @since 2016/09/19
215 public final OutputStream write(OutputStream __os)
216 throws IOException, NullPointerException
218 if (__os == null)
219 throw new NullPointerException("NARG");
221 this.write(new OutputStreamWriter(__os, "utf-8"));
223 return __os;
227 * Writes the manifest data to the given output stream.
229 * @param __os The stream to get the manifest data written to.
230 * @return {@code __os}.
231 * @throws IOException On write errors.
232 * @throws NullPointerException On null arguments.
233 * @since 2016/09/19
235 public final Appendable write(Appendable __os)
236 throws IOException, NullPointerException
238 // Check
239 if (__os == null)
240 throw new NullPointerException("NARG");
242 // Write main attribute first
243 this.__write(__os, this.getMainAttributes());
245 // Write other attributes
246 for (Map.Entry<String, MutableJavaManifestAttributes> e :
247 this.attributes.entrySet())
249 // Ignore the main attribute
250 String k = e.getKey();
251 if (k.equals(""))
252 continue;
254 // Sub-attributes are always spaced after the previous one
255 __os.append("\r\n");
257 // Write the name
258 this.__write(__os, "Name", k);
260 // Write values
261 this.__write(__os, e.getValue());
264 // Java ME has no flushable so we only know two classes which are
265 if (__os instanceof OutputStream)
266 ((OutputStream)__os).flush();
267 else if (__os instanceof Writer)
268 ((Writer)__os).flush();
270 return __os;
274 * Writes attributes to the output.
276 * @param __w The stream to write to.
277 * @throws IOException On write errors.
278 * @throws NullPointerException On null arguments.
279 * @since 2016/09/19
281 private void __write(Appendable __w, MutableJavaManifestAttributes __a)
282 throws IOException, NullPointerException
284 // Check
285 if (__w == null || __a == null)
286 throw new NullPointerException("NARG");
288 // The attribute version is always first
289 JavaManifestKey verk = new JavaManifestKey("MANIFEST-VERSION");
290 String ver = __a.get(verk);
291 if (ver != null)
292 this.__write(__w, "MANIFEST-VERSION", ver);
293 else
294 this.__write(__w, "MANIFEST-VERSION", "1.0");
296 // Write all value
297 for (Map.Entry<JavaManifestKey, String> e : __a.entrySet())
299 // Do not write the version twice
300 JavaManifestKey k = e.getKey();
301 if (verk.equals(k))
302 continue;
304 // Write pair
305 this.__write(__w, k.inputString(), e.getValue());
310 * Writes the given key and value to the output.
312 * @param __w The stream to write to.
313 * @param __k The key to write.
314 * @param __v The value to write.
315 * @throws NullPointerException On null arguments.
316 * @since 2016/09/19
318 private void __write(Appendable __w, String __k, String __v)
319 throws IOException, NullPointerException
321 // Check
322 if (__w == null || __k == null || __v == null)
323 throw new NullPointerException("NARG");
325 // Write pair
326 int col = 0;
327 for (int z = 0; z < 2; z++)
329 String s = (z == 0 ? __k : __v);
331 // Print it
332 int n = s.length();
333 for (int i = 0; i < n; i++)
335 // Ignore out of range characters
336 char c = s.charAt(i);
337 if (c < ' ')
338 continue;
340 // Would be on a new line?
341 int nextcol = col + 1;
342 boolean newline = false;
343 if (nextcol >= MutableJavaManifest._COLUMN_LIMIT)
345 // If the current character is a space then it will
346 // be lost on the following line.
347 if (c == ' ')
348 __w.append(' ');
349 __w.append("\r\n");
350 newline = true;
352 // Indent next line with space as long as this is not
353 // the last character being written
354 __w.append(' ');
356 // Set next column
357 nextcol = 1;
360 // Write the character, but if a space was written early then
361 // do not write it
362 if ((c == ' ' && !newline) || c != ' ')
363 __w.append(c);
365 // Set new column
366 col = nextcol;
369 // Add spacer
370 if (z == 0)
372 __w.append(": ");
373 col += 2;
377 // Write newline
378 __w.append("\r\n");