KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > masters_of_disaster > ant > tasks > ar > ArOutputStream


1 package de.masters_of_disaster.ant.tasks.ar;
2
3 import java.io.FilterOutputStream JavaDoc;
4 import java.io.OutputStream JavaDoc;
5 import java.io.IOException JavaDoc;
6
7 /**
8  * The ArOutputStream writes an ar archive as an OutputStream.
9  * Methods are provided to put entries, and then write their contents
10  * by writing to this stream using write().
11  */

12 public class ArOutputStream extends FilterOutputStream JavaDoc {
13     /** Fail if a long file name is required in the archive or the name contains spaces. */
14     public static final int LONGFILE_ERROR = 0;
15
16     /** Long paths will be truncated in the archive. Spaces are replaced by '_' */
17     public static final int LONGFILE_TRUNCATE = 1;
18
19     /** GNU ar variant is used to store long file names and file names with spaced in the archive. */
20     public static final int LONGFILE_GNU = 2;
21
22     /** BSD ar variant is used to store long file names and file names with spaced in the archive. */
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 JavaDoc os) throws IOException JavaDoc {
33         super(os);
34         if (null == os) {
35             throw new NullPointerException JavaDoc("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 JavaDoc("longFileMode cannot be changed after writing to the archive has begun");
44         }
45         if (LONGFILE_GNU == longFileMode) {
46             throw new UnsupportedOperationException JavaDoc("GNU variant isn't implemented yet");
47         }
48         if (LONGFILE_BSD == longFileMode) {
49             throw new UnsupportedOperationException JavaDoc("BSD variant isn't implemented yet");
50         }
51         this.longFileMode = longFileMode;
52     }
53
54     /**
55      * Put an entry on the output stream. This writes the entry's
56      * header record and positions the output stream for writing
57      * the contents of the entry. Once this method is called, the
58      * stream is ready for calls to write() to write the entry's
59      * contents. Once the contents are written, closeEntry()
60      * <B>MUST</B> be called to ensure that all buffered data
61      * is completely written to the output stream.
62      *
63      * @param entry The ArEntry to be written to the archive.
64      */

65     public void putNextEntry(ArEntry entry) throws IOException JavaDoc {
66         writingStarted = true;
67         if (inEntry) {
68             throw new IOException JavaDoc("the current entry has to be closed before starting a new one");
69         }
70         String JavaDoc filename = entry.getFilename();
71         if ((filename.length() >= ArConstants.NAMELEN)
72               && (longFileMode != LONGFILE_TRUNCATE)) {
73             throw new RuntimeException JavaDoc("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 JavaDoc("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     /**
96      * Close an entry. This method MUST be called for all file
97      * entries that contain data. The reason is that we must
98      * pad an entries data if it is of odd size.
99      */

100     public void closeEntry() throws IOException JavaDoc {
101         if (!inEntry) {
102             throw new IOException JavaDoc("we are not in an entry currently");
103         }
104
105         if (this.currBytes < this.currSize) {
106             throw new IOException JavaDoc("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     /**
119      * Writes a byte to the current ar archive entry.
120      *
121      * This method simply calls write( byte[], int, int ).
122      *
123      * @param b The byte to write to the archive.
124      */

125     public void write(int b) throws IOException JavaDoc {
126         this.oneBuf[0] = (byte) b;
127         this.write(this.oneBuf, 0, 1);
128     }
129
130     /**
131      * Writes bytes to the current ar archive entry.
132      *
133      * This method simply calls write( byte[], int, int ).
134      *
135      * @param wBuf The buffer to write to the archive.
136      */

137     public void write(byte[] wBuf) throws IOException JavaDoc {
138         this.write(wBuf, 0, wBuf.length);
139     }
140
141     /**
142      * Writes bytes to the current ar archive entry. This method
143      * is aware of the current entry and will throw an exception if
144      * you attempt to write bytes past the length specified for the
145      * current entry.
146      *
147      * @param wBuf The buffer to write to the archive.
148      * @param wOffset The offset in the buffer from which to get bytes.
149      * @param numToWrite The number of bytes to write.
150      */

151     public void write(byte[] wBuf, int wOffset, int numToWrite) throws IOException JavaDoc {
152         if (!inEntry) {
153             throw new IOException JavaDoc("we are not in an entry currently");
154         }
155
156         if ((this.currBytes + numToWrite) > this.currSize) {
157             throw new IOException JavaDoc("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