1 7 8 package java.util.jar; 9 10 import java.io.FilterInputStream ; 11 import java.io.DataOutputStream ; 12 import java.io.InputStream ; 13 import java.io.OutputStream ; 14 import java.io.IOException ; 15 import java.util.Map ; 16 import java.util.HashMap ; 17 import java.util.Iterator ; 18 19 32 public class Manifest implements Cloneable { 33 private Attributes attr = new Attributes (); 35 36 private Map entries = new HashMap (); 38 39 42 public Manifest() { 43 } 44 45 51 public Manifest(InputStream is) throws IOException { 52 read(is); 53 } 54 55 60 public Manifest(Manifest man) { 61 attr.putAll(man.getMainAttributes()); 62 entries.putAll(man.getEntries()); 63 } 64 65 69 public Attributes getMainAttributes() { 70 return attr; 71 } 72 73 79 public Map <String ,Attributes > getEntries() { 80 return entries; 81 } 82 83 93 public Attributes getAttributes(String name) { 94 return (Attributes )getEntries().get(name); 95 } 96 97 100 public void clear() { 101 attr.clear(); 102 entries.clear(); 103 } 104 105 114 public void write(OutputStream out) throws IOException { 115 DataOutputStream dos = new DataOutputStream (out); 116 attr.writeMain(dos); 118 Iterator it = entries.entrySet().iterator(); 120 while (it.hasNext()) { 121 Map.Entry e = (Map.Entry )it.next(); 122 StringBuffer buffer = new StringBuffer ("Name: "); 123 String value = (String )e.getKey(); 124 if (value != null) { 125 byte[] vb = value.getBytes("UTF8"); 126 value = new String (vb, 0, 0, vb.length); 127 } 128 buffer.append(value); 129 buffer.append("\r\n"); 130 make72Safe(buffer); 131 dos.writeBytes(buffer.toString()); 132 ((Attributes )e.getValue()).write(dos); 133 } 134 dos.flush(); 135 } 136 137 140 static void make72Safe(StringBuffer line) { 141 int length = line.length(); 142 if (length > 72) { 143 int index = 70; 144 while (index < length - 2) { 145 line.insert(index, "\r\n "); 146 index += 72; 147 length += 3; 148 } 149 } 150 return; 151 } 152 153 161 public void read(InputStream is) throws IOException { 162 FastInputStream fis = new FastInputStream(is); 164 byte[] lbuf = new byte[512]; 166 attr.read(fis, lbuf); 168 int ecount = 0, acount = 0; 170 int asize = 2; 172 int len; 174 String name = null; 175 boolean skipEmptyLines = true; 176 byte[] lastline = null; 177 178 while ((len = fis.readLine(lbuf)) != -1) { 179 if (lbuf[--len] != '\n') { 180 throw new IOException ("manifest line too long"); 181 } 182 if (len > 0 && lbuf[len-1] == '\r') { 183 --len; 184 } 185 if (len == 0 && skipEmptyLines) { 186 continue; 187 } 188 skipEmptyLines = false; 189 190 if (name == null) { 191 name = parseName(lbuf, len); 192 if (name == null) { 193 throw new IOException ("invalid manifest format"); 194 } 195 if (fis.peek() == ' ') { 196 lastline = new byte[len - 6]; 198 System.arraycopy(lbuf, 6, lastline, 0, len - 6); 199 continue; 200 } 201 } else { 202 byte[] buf = new byte[lastline.length + len - 1]; 204 System.arraycopy(lastline, 0, buf, 0, lastline.length); 205 System.arraycopy(lbuf, 1, buf, lastline.length, len - 1); 206 if (fis.peek() == ' ') { 207 lastline = buf; 209 continue; 210 } 211 name = new String (buf, 0, buf.length, "UTF8"); 212 lastline = null; 213 } 214 Attributes attr = getAttributes(name); 215 if (attr == null) { 216 attr = new Attributes (asize); 217 entries.put(name, attr); 218 } 219 attr.read(fis, lbuf); 220 ecount++; 221 acount += attr.size(); 222 asize = Math.max(2, acount / ecount); 226 227 name = null; 228 skipEmptyLines = true; 229 } 230 } 231 232 private String parseName(byte[] lbuf, int len) { 233 if (toLower(lbuf[0]) == 'n' && toLower(lbuf[1]) == 'a' && 234 toLower(lbuf[2]) == 'm' && toLower(lbuf[3]) == 'e' && 235 lbuf[4] == ':' && lbuf[5] == ' ') { 236 try { 237 return new String (lbuf, 6, len - 6, "UTF8"); 238 } 239 catch (Exception e) { 240 } 241 } 242 return null; 243 } 244 245 private int toLower(int c) { 246 return (c >= 'A' && c <= 'Z') ? 'a' + (c - 'A') : c; 247 } 248 249 257 public boolean equals(Object o) { 258 if (o instanceof Manifest ) { 259 Manifest m = (Manifest )o; 260 return attr.equals(m.getMainAttributes()) && 261 entries.equals(m.getEntries()); 262 } else { 263 return false; 264 } 265 } 266 267 270 public int hashCode() { 271 return attr.hashCode() + entries.hashCode(); 272 } 273 274 282 public Object clone() { 283 return new Manifest (this); 284 } 285 286 289 static class FastInputStream extends FilterInputStream { 290 private byte buf[]; 291 private int count = 0; 292 private int pos = 0; 293 294 FastInputStream(InputStream in) { 295 this(in, 8192); 296 } 297 298 FastInputStream(InputStream in, int size) { 299 super(in); 300 buf = new byte[size]; 301 } 302 303 public int read() throws IOException { 304 if (pos >= count) { 305 fill(); 306 if (pos >= count) { 307 return -1; 308 } 309 } 310 return buf[pos++] & 0xff; 311 } 312 313 public int read(byte[] b, int off, int len) throws IOException { 314 int avail = count - pos; 315 if (avail <= 0) { 316 if (len >= buf.length) { 317 return in.read(b, off, len); 318 } 319 fill(); 320 avail = count - pos; 321 if (avail <= 0) { 322 return -1; 323 } 324 } 325 if (len > avail) { 326 len = avail; 327 } 328 System.arraycopy(buf, pos, b, off, len); 329 pos += len; 330 return len; 331 } 332 333 337 public int readLine(byte[] b, int off, int len) throws IOException { 338 byte[] tbuf = this.buf; 339 int total = 0; 340 while (total < len) { 341 int avail = count - pos; 342 if (avail <= 0) { 343 fill(); 344 avail = count - pos; 345 if (avail <= 0) { 346 return -1; 347 } 348 } 349 int n = len - total; 350 if (n > avail) { 351 n = avail; 352 } 353 int tpos = pos; 354 int maxpos = tpos + n; 355 while (tpos < maxpos && tbuf[tpos++] != '\n') ; 356 n = tpos - pos; 357 System.arraycopy(tbuf, pos, b, off, n); 358 off += n; 359 total += n; 360 pos = tpos; 361 if (tbuf[tpos-1] == '\n') { 362 break; 363 } 364 } 365 return total; 366 } 367 368 public byte peek() throws IOException { 369 if (pos == count) 370 fill(); 371 return buf[pos]; 372 } 373 374 public int readLine(byte[] b) throws IOException { 375 return readLine(b, 0, b.length); 376 } 377 378 public long skip(long n) throws IOException { 379 if (n <= 0) { 380 return 0; 381 } 382 long avail = count - pos; 383 if (avail <= 0) { 384 return in.skip(n); 385 } 386 if (n > avail) { 387 n = avail; 388 } 389 pos += n; 390 return n; 391 } 392 393 public int available() throws IOException { 394 return (count - pos) + in.available(); 395 } 396 397 public void close() throws IOException { 398 if (in != null) { 399 in.close(); 400 in = null; 401 buf = null; 402 } 403 } 404 405 private void fill() throws IOException { 406 count = pos = 0; 407 int n = in.read(buf, 0, buf.length); 408 if (n > 0) { 409 count = n; 410 } 411 } 412 } 413 } 414 | Popular Tags |