001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.installer;
028:
029: import java.io.*;
030: import java.util.*;
031:
032: /**
033: * Handles the properties in a JAR manifest. Each property is know as a header
034: * in the syntax definition. A line that begins with a space is a continuation
035: * of the previous line, and the first space ignored. To save code this
036: * manifest parser uses lets its super class parse the key and value
037: * of property once it has read the entire line, including continuation lines.
038: * This means that this parser is lax on reporting illegal characters.
039: * <p>
040: * The BNF for the manifest syntax included below is extended as follows:
041: * <pre>
042: * ":":separates the name and value of a rule
043: * +: 1 or more
044: * *: 0 or more
045: * {}: encloses a list of alternatives
046: * ;: comment
047: * terminals can also be represented in UPPER CASE
048: * non-terminals are not encluded in angle brackets
049: * </pre><p>
050: * Syntax definition from the manifest spec:
051: * <p>
052: * In most cases, information contained within the manifest file or
053: * signature files is represented as so-called "name: value" pairs
054: * inspired by the RFC822 standard.
055: * <p>
056: * Groups of name-value pairs are known as a "section". Sections are
057: * separated from other sections by empty lines.
058: * <p>
059: * Binary data of any form is represented as base64. Continuations are
060: * required for binary data which causes line length to exceed 72
061: * bytes. Examples of binary data are digests and signatures.
062: * <p>
063: * Implementations shall support header values of up to 65535 bytes.
064: * <pre>
065: * section: *header +newline
066: * nonempty-section: +header +newline
067: * newline: CR LF | LF | CR (not followed by LF)
068: *
069: * ; That 'not followed by LF' probably requires some minor
070: * ; ugliness in the parser. Sorry.
071: *
072: * header: alphanum *headerchar ":" SPACE *otherchar newline
073: * *continuation
074: *
075: * continuation: SPACE *otherchar newline
076: *
077: * ; RFC822 has +(SPACE | TAB), but this way continuation lines
078: * ; never get mangled.
079: *
080: * alphanum: {"A"-"Z"} | {"a"-"z"} | {"0"-"9"}
081: *
082: * headerchar: alphanum | "-" | "_"
083: *
084: * otherchar: any Unicode character except NUL, CR and LF
085: *
086: * ; Also: To prevent mangling of files sent via straight e-mail, no
087: * ; header will start with the four letters "From".
088: *
089: * ; When version numbering is used:
090: *
091: * number: {"0"-"9"}+
092: *
093: * ; The number needn't be, e.g. 1.11 is considered to be later
094: * ; than 1.9. Both major and minor versions must be 3 digits or less.
095: *</pre>
096: */
097: public class ManifestProperties extends JadProperties {
098: /** Signals that there is no remainder. */
099: protected static final int NO_REMAINDER = -2;
100:
101: /** Holds the remainder from the last look ahead operation. */
102: protected int remainder = NO_REMAINDER;
103:
104: /**
105: * Constructor - creates an empty property list.
106: */
107: public ManifestProperties() {
108: }
109:
110: /**
111: * Read a portion of the manifest.
112: * @param inStream the current data source for the manifest
113: * @param enc the character set encoding of the manifest
114: * @param propertiesToLoad the names of the properties to load
115: * @exception IOException is thrown if an error occurs reading the
116: * manifest data stream.
117: * @exception InvalidJadException if the JAD is not formatted correctly.
118: */
119: public void partialLoad(InputStream inStream, String enc,
120: int propertiesToLoad) throws IOException,
121: InvalidJadException {
122: // reset any leftover remainder
123: remainder = NO_REMAINDER;
124: super .partialLoad(inStream, enc, propertiesToLoad);
125: }
126:
127: /**
128: * Reads one line using a given reader. CR, LF, or CR + LF end a line.
129: * However lines may be continued by beginning the next line with a space.
130: * The end of line and end of file characters and continuation space are
131: * dropped.
132: * @param in reader for a JAD
133: * @return one line of the JAD or null at the end of the JAD
134: * @exception IOException thrown by the reader
135: */
136: protected String readLine(Reader in) throws IOException {
137: int lastChar = 0;
138: int room;
139: int offset = 0;
140: int c;
141: char[] temp;
142:
143: room = lineBuffer.length;
144:
145: if (remainder != NO_REMAINDER) {
146: c = remainder;
147: remainder = NO_REMAINDER;
148: } else {
149: c = in.read();
150: }
151:
152: for (; c != -1; lastChar = c, c = in.read()) {
153: /*
154: * if we read the end of the line last time and the next line
155: * does not begin with a space we are done. But save this character
156: * for next time. CR | LF | CR LF ends a line.
157: */
158: if (lastChar == LF) {
159: if (c == SP) {
160: // Marks a continuation line, throw away the space
161: continue;
162: }
163:
164: remainder = c;
165: break;
166: }
167:
168: if (lastChar == CR) {
169: if (c == SP) {
170: // Marks a continuation line, throw away the space
171: continue;
172: }
173:
174: if (c != LF) {
175: remainder = c;
176: break;
177: }
178: }
179:
180: /*
181: * do not include the end of line characters and the end
182: * of file character.
183: */
184: if (c == CR || c == LF || c == EOF) {
185: continue;
186: }
187:
188: if (--room < 0) {
189: temp = new char[offset + 128];
190: room = temp.length - offset - 1;
191: System.arraycopy(lineBuffer, 0, temp, 0, offset);
192: lineBuffer = temp;
193: }
194:
195: lineBuffer[offset++] = (char) c;
196: }
197:
198: if ((c == -1) && (offset <= 0)) {
199: return null;
200: }
201:
202: return new String(lineBuffer, 0, offset);
203: }
204:
205: /**
206: * Check to see if all the chars in the key of a property are valid.
207: *
208: * @param key key to check
209: *
210: * @return false if a character is not valid for a key
211: */
212: protected boolean checkKeyChars(String key) {
213: char[] temp = key.toCharArray();
214: int len = temp.length;
215:
216: for (int i = 0; i < len; i++) {
217: char current = temp[i];
218:
219: if (current >= 'A' && current <= 'Z') {
220: continue;
221: }
222:
223: if (current >= 'a' && current <= 'z') {
224: continue;
225: }
226:
227: if (current >= '0' && current <= '9') {
228: continue;
229: }
230:
231: if (i > 0 && (current == '-' || current == '_')) {
232: continue;
233: }
234:
235: return false;
236: }
237:
238: return true;
239: }
240:
241: /**
242: * Check to see if all the chars in the value of a property are valid.
243: *
244: * @param value value to check
245: *
246: * @return false if a character is not valid for a value
247: */
248: protected boolean checkValueChars(String value) {
249: char[] temp = value.toCharArray();
250: int len = temp.length;
251:
252: // assume whitespace and new lines are trimmed
253: for (int i = 0; i < len; i++) {
254: if (temp[i] == 0) {
255: return false;
256: }
257: }
258:
259: return true;
260: }
261: }
|