1 package de.masters_of_disaster.ant.tasks.ar; 2 3 import java.io.FilterOutputStream ; 4 import java.io.OutputStream ; 5 import java.io.IOException ; 6 7 12 public class ArOutputStream extends FilterOutputStream { 13 14 public static final int LONGFILE_ERROR = 0; 15 16 17 public static final int LONGFILE_TRUNCATE = 1; 18 19 20 public static final int LONGFILE_GNU = 2; 21 22 23 public static final int LONGFILE_BSD = 3; 24 25 protected int currSize; 26 protected int currBytes; 27 protected byte[] oneBuf; 28 protected int longFileMode = LONGFILE_ERROR; 29 protected boolean writingStarted = false; 30 protected boolean inEntry = false; 31 32 public ArOutputStream(OutputStream os) throws IOException { 33 super(os); 34 if (null == os) { 35 throw new NullPointerException ("os must not be null"); 36 } 37 this.out.write(ArConstants.ARMAGIC,0,ArConstants.ARMAGIC.length); 38 this.oneBuf = new byte[1]; 39 } 40 41 public void setLongFileMode(int longFileMode) { 42 if (writingStarted) { 43 throw new IllegalStateException ("longFileMode cannot be changed after writing to the archive has begun"); 44 } 45 if (LONGFILE_GNU == longFileMode) { 46 throw new UnsupportedOperationException ("GNU variant isn't implemented yet"); 47 } 48 if (LONGFILE_BSD == longFileMode) { 49 throw new UnsupportedOperationException ("BSD variant isn't implemented yet"); 50 } 51 this.longFileMode = longFileMode; 52 } 53 54 65 public void putNextEntry(ArEntry entry) throws IOException { 66 writingStarted = true; 67 if (inEntry) { 68 throw new IOException ("the current entry has to be closed before starting a new one"); 69 } 70 String filename = entry.getFilename(); 71 if ((filename.length() >= ArConstants.NAMELEN) 72 && (longFileMode != LONGFILE_TRUNCATE)) { 73 throw new RuntimeException ("file name \"" + entry.getFilename() 74 + "\" is too long ( > " 75 + ArConstants.NAMELEN + " bytes )"); 76 } 77 if (-1 != filename.indexOf(' ')) { 78 if (longFileMode == LONGFILE_TRUNCATE) { 79 entry.setFilename(filename.replace(' ','_')); 80 } else { 81 throw new RuntimeException ("file name \"" + entry.getFilename() 82 + "\" contains spaces"); 83 } 84 } 85 86 byte[] headerBuf = new byte[ArConstants.HEADERLENGTH]; 87 entry.writeEntryHeader(headerBuf); 88 this.out.write(headerBuf,0,ArConstants.HEADERLENGTH); 89 90 this.currBytes = 0; 91 this.currSize = (int) entry.getSize(); 92 inEntry = true; 93 } 94 95 100 public void closeEntry() throws IOException { 101 if (!inEntry) { 102 throw new IOException ("we are not in an entry currently"); 103 } 104 105 if (this.currBytes < this.currSize) { 106 throw new IOException ("entry closed at '" + this.currBytes 107 + "' before the '" + this.currSize 108 + "' bytes specified in the header were written"); 109 } 110 111 if (1 == (this.currSize & 1)) { 112 this.out.write(ArConstants.PADDING,0,1); 113 } 114 115 inEntry = false; 116 } 117 118 125 public void write(int b) throws IOException { 126 this.oneBuf[0] = (byte) b; 127 this.write(this.oneBuf, 0, 1); 128 } 129 130 137 public void write(byte[] wBuf) throws IOException { 138 this.write(wBuf, 0, wBuf.length); 139 } 140 141 151 public void write(byte[] wBuf, int wOffset, int numToWrite) throws IOException { 152 if (!inEntry) { 153 throw new IOException ("we are not in an entry currently"); 154 } 155 156 if ((this.currBytes + numToWrite) > this.currSize) { 157 throw new IOException ("request to write '" + numToWrite 158 + "' bytes exceeds size in header of '" 159 + this.currSize + "' bytes"); 160 } 161 162 if (numToWrite > 0) { 163 this.out.write(wBuf,wOffset,numToWrite); 164 this.currBytes += numToWrite; 165 } 166 } 167 } 168 | Popular Tags |