Removal of old and deprecated UIForm code.
[SquirrelJME.git] / modules / cldc-compact / src / main / java / cc / squirreljme / jvm / manifest / JavaManifest.java
blob3fedbda1ff29b55f934ff21df29a820310b7e374
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 Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc.squirreljme.jvm.manifest;
12 import java.io.BufferedReader;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.InputStreamReader;
16 import java.io.Reader;
17 import java.util.AbstractMap;
18 import java.util.HashMap;
19 import java.util.LinkedHashMap;
20 import java.util.Map;
21 import java.util.Set;
23 /**
24 * This contains decoders for the standard Java manifest format.
26 * This class is immutable.
28 * @since 2016/05/20
30 public final class JavaManifest
31 extends AbstractMap<String, JavaManifestAttributes>
33 /** The attributes defined in this manifest file. */
34 private final Map<String, JavaManifestAttributes> _attributes;
36 /**
37 * Initializes a blank manifest.
39 * @since 2018/02/10
41 public JavaManifest()
43 // Initialize a blank set of main attributes
44 Map<String, JavaManifestAttributes> backing = new HashMap<>();
45 backing.put("", new JavaManifestAttributes());
47 // Lock in the backing map
48 this._attributes = backing;
51 /**
52 * Decodes the manifest from the given input stream, it is treated as
53 * UTF-8 as per the JAR specification.
55 * @param __is The input stream for the manifest data.
56 * @throws IOException On read errors.
57 * @throws JavaManifestException If the manifest is malformed.
58 * @throws NullPointerException On null arguments.
59 * @since 2016/05/20
61 public JavaManifest(InputStream __is)
62 throws IOException, JavaManifestException, NullPointerException
64 this(new BufferedReader(
65 new InputStreamReader(__is, "utf-8")));
68 /**
69 * Decodes the manifest from the given reader.
71 * @param __r The characters which make up the manifest.
72 * @throws IOException On read errors.
73 * @throws JavaManifestException If the manifest is malformed.
74 * @throws NullPointerException On null arguments.
75 * @since 2018/11/22
77 public JavaManifest(Reader __r)
78 throws IOException, JavaManifestException, NullPointerException
80 // Check
81 if (__r == null)
82 throw new NullPointerException("NARG");
84 // The backing map and temporary key/value pairs for each
85 // attribute set
86 String curname = "";
87 Map<String, JavaManifestAttributes> backing = new LinkedHashMap<>();
88 Map<JavaManifestKey, String> working = new LinkedHashMap<>();
90 // Read input file line by line, since it is more efficient than
91 // character by character
92 StringBuilder vsb = new StringBuilder(128);
93 BufferedReader br = new BufferedReader(__r);
94 for (String pln = null;;)
96 // End of EOF
97 String ln = (pln != null ? pln : br.readLine());
98 pln = null;
99 if (ln == null)
100 break;
102 // If the line is blank, it starts a new attribute block
103 if (ln.isEmpty())
105 // Store the current working set
106 if (working != null)
108 backing.put(curname, new JavaManifestAttributes(working));
110 // It was stored in the map, so forget it
111 curname = null;
112 working = null;
115 // Skip blank line
116 continue;
119 // This will be a name: value line, so find the colon on it
120 /* {@squirreljme.error BB01 Expected colon to appear on the
121 manifest line, to split a name/value pair.} */
122 int col = ln.indexOf(':');
123 if (col < 0)
124 throw new JavaManifestException("BB01");
126 // Read key and value
127 String key = ln.substring(0, col);
129 /* {@squirreljme.error BB02 Manifest key contains an invalid
130 character.} */
131 for (int i = 0, n = key.length(); i < n; i++)
132 if (!JavaManifest.__isKeyChar(key.charAt(i)))
133 throw new JavaManifestException(
134 String.format("BB02 %s", key));
136 // Need to skip the actual colon
137 col++;
139 // Skip spaces at the start of the value line
140 int n = ln.length();
141 while (col < n && ln.charAt(col) == ' ')
142 col++;
144 // Place value as it is now into a temporary buffer
145 vsb.append(ln, col, n);
147 // Read the next line to determine if it is a continuation
148 for (;;)
150 // Stop at EOF
151 pln = br.readLine();
152 if (pln == null)
153 break;
155 // If this is a non-continuation line, it will be a blank
156 // line or some other value, so redo the loop
157 if (!pln.startsWith(" "))
158 break;
160 // Stop at the first non-space
161 int nsp = 1;
162 for (n = pln.length(); nsp < n; nsp++)
163 if (pln.charAt(nsp) != ' ')
164 break;
166 // Append split into the buffer
167 vsb.append(pln, nsp, n);
169 // Clear the line, so it is not repeated
170 pln = null;
173 // Build key and value
174 JavaManifestKey ak = new JavaManifestKey(key);
175 String av = vsb.toString();
177 // Was this the start of a new section?
178 if (curname == null)
180 /* {@squirreljme.error BB03 New section must start with
181 {@code Name: value}. (The input section)} */
182 if (!"name".equals(ak.string))
183 throw new JavaManifestException("BB03 " + ak);
185 // The current name becomes the value
186 curname = av;
188 // Empty map to store values into
189 working = new HashMap<>();
192 // Otherwise, add to the map
193 else
194 working.put(ak, av);
196 // Clear the value
197 vsb.setLength(0);
200 // Make sure the attribute is added to the set
201 if (working != null)
202 backing.put(curname, new JavaManifestAttributes(working));
204 // Lock in the backing map
205 this._attributes = backing;
209 * {@inheritDoc}
210 * @since 2016/05/20
212 @Override
213 public boolean containsKey(Object __k)
215 return this._attributes.containsKey(__k);
219 * {@inheritDoc}
220 * @since 2016/05/20
222 @Override
223 public Set<Map.Entry<String, JavaManifestAttributes>> entrySet()
225 return this._attributes.entrySet();
229 * {@inheritDoc}
230 * @since 2016/05/20
231 * @param __k
233 @Override
234 public JavaManifestAttributes get(Object __k)
236 return this._attributes.get(__k);
240 * Returns the mapping of main attributes.
242 * @return The main attribute mapping.
243 * @since 2016/05/29
245 public JavaManifestAttributes getMainAttributes()
247 return this._attributes.get("");
251 * {@inheritDoc}
252 * @since 2016/05/20
254 @Override
255 public int size()
257 return this._attributes.size();
261 * Returns {@code true} if the specified character is an alpha-numeric
262 * character.
264 * @param __c The character to check.
265 * @return {@code true} if an alpha-numeric character.
266 * @since 2016/05/29
268 private static boolean __isAlphaNum(char __c)
270 return (__c >= 'A' && __c <= 'Z') ||
271 (__c >= 'a' && __c <= 'z') ||
272 (__c >= '0' && __c <= '9');
276 * Returns {@code true} if the character is part of a character which would
277 * be used for key values.
279 * @param __c The character to check.
280 * @return {@code true} if a key character.
281 * @since 2016/05/29
283 private static boolean __isKeyChar(char __c)
285 return JavaManifest.__isAlphaNum(__c) || __c == '_' || __c == '-';