View Javadoc
1 /* ------------------------------------------------------------------- 2 * Java source file for the class MIMEHeader 3 * 4 * Copyright (c), 2002, Masahiro Takatsuka. 5 * All Rights Researved. 6 * 7 * Original Author: Masahiro Takatsuka (masa@jbeans.net) 8 * $Author: takatsukam $ 9 * 10 * $Date: 2003/07/25 04:51:47 $ 11 * 12 * $Id: MIMEHeader.java,v 1.1.1.1 2003/07/25 04:51:47 takatsukam Exp $ 13 * 14 * Reference: Document no: 15 * ___ ___ 16 * 17 * To Do: 18 * ___ 19 * 20 ------------------------------------------------------------------- */ 21 22 /* --------------------------- Package ---------------------------- */ 23 package net.jbeans.util.jar; 24 25 /* ------------------ Import classes (packages) ------------------- *//package-summary/html">color="#329900"> ------------------ Import classes (packages) ------------------- *//package-summary.html">color="#329900">/* ------------------ Import classes (packages) ------------------- *//package-summary.html">color="#329900"> ------------------ Import classes (packages) ------------------- */ 26 import java.io.*; 27 28 /*==================================================================== 29 Implementation of class MIMEHeader 30 ====================================================================*/ 31 /*** 32 * An RFC 844 or MIME message header. Includes methods for parsing headers 33 * from incoming streams, fetching values, setting values, and printing 34 * headers. Key values of null are legal: they indicate lines in the header 35 * that don't have a valid key, but do have a value (this isn't legal 36 * according to the standard, but lines like this are everywhere). 37 * 38 * @version $Revision: 1.1.1.1 $ 39 * @author Masahiro Takatsuka (masa@jbeans.net) 40 */ 41 42 final class MIMEHeader { 43 private String[] keys; 44 private String[] values; 45 private int nkeys; 46 47 MIMEHeader () { 48 grow(); 49 } 50 51 MIMEHeader (InputStream is) throws java.io.IOException { 52 parseHeader(is); 53 } 54 55 /*** 56 * Find the value that corresponds to this key. 57 * It finds only the first occurrence of the key. 58 * @param k the key to find. 59 * @return null if not found. 60 */ 61 final String findValue(String k) { 62 if (k == null) { 63 for (int i = this.nkeys; --i >= 0;) 64 if (this.keys[i] == null) 65 return this.values[i]; 66 } else 67 for (int i = this.nkeys; --i >= 0;) { 68 if (k.equalsIgnoreCase(this.keys[i])) 69 return this.values[i]; 70 } 71 return null; 72 } 73 74 final String getKey(int n) { 75 if (n < 0 || n >= this.nkeys) return null; 76 return this.keys[n]; 77 } 78 79 final String getValue(int n) { 80 if (n < 0 || n >= this.nkeys) return null; 81 return this.values[n]; 82 } 83 84 /*** Find the next value that corresponds to this key. 85 * It finds the first value that follows v. To iterate 86 * over all the values of a key use: 87 * <pre> 88 * for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) { 89 * ... 90 * } 91 * </pre> 92 */ 93 final String findNextValue(String k, String v) { 94 boolean foundV = false; 95 if (k == null) { 96 for (int i = this.nkeys; --i >= 0;) 97 if (this.keys[i] == null) 98 if (foundV) 99 return this.values[i]; 100 else if (this.values[i] == v) 101 foundV = true; 102 } else 103 for (int i = this.nkeys; --i >= 0;) 104 if (k.equalsIgnoreCase(this.keys[i])) 105 if (foundV) 106 return this.values[i]; 107 else if (this.values[i] == v) 108 foundV = true; 109 return null; 110 } 111 112 /*** Prints the key-value pairs represented by this 113 header. Also prints the RFC required blank line 114 at the end. Omits pairs with a null key. */ 115 final void print(PrintWriter p) { 116 for (int i = 0; i < this.nkeys; i++) 117 if (this.keys[i] != null) 118 p.print(this.keys[i] + 119 (this.values[i] != null ? ": "+this.values[i]: "") + "\r\n"); 120 p.print("\r\n"); 121 p.flush(); 122 } 123 124 /*** Adds a key value pair to the end of the 125 header. Duplicates are allowed */ 126 final void add(String k, String v) { 127 grow(); 128 this.keys[this.nkeys] = k; 129 this.values[this.nkeys] = v; 130 this.nkeys++; 131 } 132 133 /*** Prepends a key value pair to the beginning of the 134 header. Duplicates are allowed */ 135 final void prepend(String k, String v) { 136 grow(); 137 for (int i = this.nkeys; i > 0; i--) { 138 this.keys[i] = this.keys[i-1]; 139 this.values[i] = this.values[i-1]; 140 } 141 this.keys[0] = k; 142 this.values[0] = v; 143 this.nkeys++; 144 } 145 146 /*** Overwrite the previous key/val pair at location 'i' 147 * with the new k/v. If the index didn't exist before 148 * the key/val is simply tacked onto the end. 149 */ 150 final void set(int i, String k, String v) { 151 grow(); 152 if (i < 0) { 153 return; 154 } else if (i > this.nkeys) { 155 add(k, v); 156 } else { 157 this.keys[i] = k; 158 this.values[i] = v; 159 } 160 } 161 162 163 /*** grow the key/value arrays as needed */ 164 void grow() { 165 if (this.keys == null || this.nkeys >= this.keys.length) { 166 String[] nk = new String[this.nkeys + 4]; 167 String[] nv = new String[this.nkeys + 4]; 168 if (this.keys != null) 169 System.arraycopy(this.keys, 0, nk, 0, this.nkeys); 170 if (this.values != null) 171 System.arraycopy(this.values, 0, nv, 0, this.nkeys); 172 this.keys = nk; 173 this.values = nv; 174 } 175 } 176 177 /*** Sets the value of a key. If the key already 178 exists in the header, it's value will be 179 changed. Otherwise a new key/value pair will 180 be added to the end of the header. */ 181 final void set(String k, String v) { 182 for (int i = this.nkeys; --i >= 0;) 183 if (k.equalsIgnoreCase(this.keys[i])) { 184 this.values[i] = v; 185 return; 186 } 187 add(k, v); 188 } 189 190 /*** Convert a message-id string to canonical form (strips off 191 leading and trailing <>s) */ 192 final static String canonicalID(String id) { 193 if (id == null) 194 return ""; 195 int st = 0; 196 int len = id.length(); 197 boolean substr = false; 198 int c; 199 while (st < len && ((c = id.charAt(st)) == '<' || 200 c <= ' ')) { 201 st++; 202 substr = true; 203 } 204 while (st < len && ((c = id.charAt(len - 1)) == '>' || 205 c <= ' ')) { 206 len--; 207 substr = true; 208 } 209 return substr ? id.substring(st, len) : id; 210 } 211 212 /*** Parse a MIME header from an input stream. */ 213 final void parseHeader(InputStream is) throws java.io.IOException { 214 this.nkeys = 0; 215 if (is == null) 216 return; 217 char s[] = new char[10]; 218 int firstc = is.read(); 219 while (firstc != '\n' && firstc != '\r' && firstc >= 0) { 220 int len = 0; 221 int keyend = -1; 222 int c; 223 boolean inKey = firstc > ' '; 224 s[len++] = (char) firstc; 225 parseloop:{ 226 parseloop2: while ((c = is.read()) >= 0) { 227 switch (c) { 228 case ':': 229 if (inKey && len > 0) 230 keyend = len; 231 inKey = false; 232 break; 233 case '\t': 234 c = ' '; 235 case ' ': 236 inKey = false; 237 break; 238 case '\r': 239 case '\n': 240 firstc = is.read(); 241 if (c == '\r' && firstc == '\n') { 242 firstc = is.read(); 243 if (firstc == '\r') 244 firstc = is.read(); 245 } 246 if (firstc == '\n' || firstc == '\r' || firstc > ' ') 247 break parseloop; 248 /* continuation */ 249 continue parseloop2; 250 } 251 if (len >= s.length) { 252 char ns[] = new char[s.length * 2]; 253 System.arraycopy(s, 0, ns, 0, len); 254 s = ns; 255 } 256 s[len++] = (char) c; 257 } 258 firstc = -1; 259 } 260 while (len > 0 && s[len - 1] <= ' ') 261 len--; 262 String k; 263 if (keyend <= 0) { 264 k = null; 265 keyend = 0; 266 } else { 267 k = String.copyValueOf(s, 0, keyend); 268 if (keyend < len && s[keyend] == ':') 269 keyend++; 270 while (keyend < len && s[keyend] <= ' ') 271 keyend++; 272 } 273 String v; 274 if (keyend >= len) 275 v = new String(); 276 else 277 v = String.copyValueOf(s, keyend, len - keyend); 278 add(k, v); 279 } 280 } 281 282 public final String toString() { 283 String result = super.toString(); 284 for (int i = 0; i < this.keys.length; i++) { 285 result += "{"+this.keys[i]+": "+this.values[i]+"}"; 286 } 287 return result; 288 } 289 }

This page was automatically generated by Maven