001: package org.objectweb.salome_tmf.plugins;
002:
003: import java.io.InputStream;
004: import java.io.PrintWriter;
005:
006: /** An RFC 844 or MIME message header. Includes methods
007: for parsing headers from incoming streams, fetching
008: values, setting values, and printing headers.
009: Key values of null are legal: they indicate lines in
010: the header that don't have a valid key, but do have
011: a value (this isn't legal according to the standard,
012: but lines like this are everywhere). */
013: public class MessageHeader {
014: private String keys[];
015: private String values[];
016: private int nkeys;
017:
018: public MessageHeader() {
019: grow();
020: }
021:
022: public MessageHeader(InputStream is) throws java.io.IOException {
023: parseHeader(is);
024: }
025:
026: /**
027: * Find the value that corresponds to this key.
028: * It finds only the first occurrence of the key.
029: * @param k the key to find.
030: * @return null if not found.
031: */
032: public String findValue(String k) {
033: if (k == null) {
034: for (int i = nkeys; --i >= 0;)
035: if (keys[i] == null)
036: return values[i];
037: } else
038: for (int i = nkeys; --i >= 0;) {
039: if (k.equalsIgnoreCase(keys[i]))
040: return values[i];
041: }
042: return null;
043: }
044:
045: public String getKey(int n) {
046: if (n < 0 || n >= nkeys)
047: return null;
048: return keys[n];
049: }
050:
051: public String getValue(int n) {
052: if (n < 0 || n >= nkeys)
053: return null;
054: return values[n];
055: }
056:
057: /** Find the next value that corresponds to this key.
058: * It finds the first value that follows v. To iterate
059: * over all the values of a key use:
060: * <pre>
061: * for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
062: * ...
063: * }
064: * </pre>
065: */
066: public String findNextValue(String k, String v) {
067: boolean foundV = false;
068: if (k == null) {
069: for (int i = nkeys; --i >= 0;)
070: if (keys[i] == null)
071: if (foundV)
072: return values[i];
073: else if (values[i] == v)
074: foundV = true;
075: } else
076: for (int i = nkeys; --i >= 0;)
077: if (k.equalsIgnoreCase(keys[i]))
078: if (foundV)
079: return values[i];
080: else if (values[i] == v)
081: foundV = true;
082: return null;
083: }
084:
085: /** Prints the key-value pairs represented by this
086: header. Also prints the RFC required blank line
087: at the end. Omits pairs with a null key. */
088: public void print(PrintWriter p) {
089: for (int i = 0; i < nkeys; i++)
090: if (keys[i] != null)
091: p.print(keys[i]
092: + (values[i] != null ? ": " + values[i] : "")
093: + "\r\n");
094: p.print("\r\n");
095: p.flush();
096: }
097:
098: /** Adds a key value pair to the end of the
099: header. Duplicates are allowed */
100: public void add(String k, String v) {
101: grow();
102: keys[nkeys] = k;
103: values[nkeys] = v;
104: nkeys++;
105: }
106:
107: /** Prepends a key value pair to the beginning of the
108: header. Duplicates are allowed */
109: public void prepend(String k, String v) {
110: grow();
111: for (int i = nkeys; i > 0; i--) {
112: keys[i] = keys[i - 1];
113: values[i] = values[i - 1];
114: }
115: keys[0] = k;
116: values[0] = v;
117: nkeys++;
118: }
119:
120: /** Overwrite the previous key/val pair at location 'i'
121: * with the new k/v. If the index didn't exist before
122: * the key/val is simply tacked onto the end.
123: */
124:
125: public void set(int i, String k, String v) {
126: grow();
127: if (i < 0) {
128: return;
129: } else if (i > nkeys) {
130: add(k, v);
131: } else {
132: keys[i] = k;
133: values[i] = v;
134: }
135: }
136:
137: /** grow the key/value arrays as needed */
138:
139: private void grow() {
140: if (keys == null || nkeys >= keys.length) {
141: String[] nk = new String[nkeys + 4];
142: String[] nv = new String[nkeys + 4];
143: if (keys != null)
144: System.arraycopy(keys, 0, nk, 0, nkeys);
145: if (values != null)
146: System.arraycopy(values, 0, nv, 0, nkeys);
147: keys = nk;
148: values = nv;
149: }
150: }
151:
152: /** Sets the value of a key. If the key already
153: exists in the header, it's value will be
154: changed. Otherwise a new key/value pair will
155: be added to the end of the header. */
156: public void set(String k, String v) {
157: for (int i = nkeys; --i >= 0;)
158: if (k.equalsIgnoreCase(keys[i])) {
159: values[i] = v;
160: return;
161: }
162: add(k, v);
163: }
164:
165: /** Convert a message-id string to canonical form (strips off
166: leading and trailing <>s) */
167: public static String canonicalID(String id) {
168: if (id == null)
169: return "";
170: int st = 0;
171: int len = id.length();
172: boolean substr = false;
173: int c;
174: while (st < len && ((c = id.charAt(st)) == '<' || c <= ' ')) {
175: st++;
176: substr = true;
177: }
178: while (st < len
179: && ((c = id.charAt(len - 1)) == '>' || c <= ' ')) {
180: len--;
181: substr = true;
182: }
183: return substr ? id.substring(st, len) : id;
184: }
185:
186: /** Parse a MIME header from an input stream. */
187: public void parseHeader(InputStream is) throws java.io.IOException {
188: nkeys = 0;
189: if (is == null)
190: return;
191: char s[] = new char[10];
192: int firstc = is.read();
193: while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
194: int len = 0;
195: int keyend = -1;
196: int c;
197: boolean inKey = firstc > ' ';
198: s[len++] = (char) firstc;
199: parseloop: {
200: parseloop2: while ((c = is.read()) >= 0) {
201: switch (c) {
202: case ':':
203: if (inKey && len > 0)
204: keyend = len;
205: inKey = false;
206: break;
207: case '\t':
208: c = ' ';
209: case ' ':
210: inKey = false;
211: break;
212: case '\r':
213: case '\n':
214: firstc = is.read();
215: if (c == '\r' && firstc == '\n') {
216: firstc = is.read();
217: if (firstc == '\r')
218: firstc = is.read();
219: }
220: if (firstc == '\n' || firstc == '\r'
221: || firstc > ' ')
222: break parseloop;
223: /* continuation */
224: continue parseloop2;
225: }
226: if (len >= s.length) {
227: char ns[] = new char[s.length * 2];
228: System.arraycopy(s, 0, ns, 0, len);
229: s = ns;
230: }
231: s[len++] = (char) c;
232: }
233: firstc = -1;
234: }
235: while (len > 0 && s[len - 1] <= ' ')
236: len--;
237: String k;
238: if (keyend <= 0) {
239: k = null;
240: keyend = 0;
241: } else {
242: k = String.copyValueOf(s, 0, keyend);
243: if (keyend < len && s[keyend] == ':')
244: keyend++;
245: while (keyend < len && s[keyend] <= ' ')
246: keyend++;
247: }
248: String v;
249: if (keyend >= len)
250: v = new String();
251: else
252: v = String.copyValueOf(s, keyend, len - keyend);
253: add(k, v);
254: }
255: }
256:
257: public String toString() {
258: String result = super .toString();
259: for (int i = 0; i < keys.length; i++) {
260: result += "{" + keys[i] + ": " + values[i] + "}";
261: }
262: return result;
263: }
264: }
|