Mercurial > cgi-bin > hgweb.cgi > JpegWasher
comparison lib/mod/src/de/masters_of_disaster/ant/tasks/ar/ArOutputStream.java @ 33:3d86f0391168
Work on improving the build system.
author | David Barts <davidb@stashtea.com> |
---|---|
date | Fri, 24 Apr 2020 19:45:57 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
32:c06edc56669b | 33:3d86f0391168 |
---|---|
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 /** | |
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 { | |
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 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 /** | |
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 { | |
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 /** | |
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 { | |
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 /** | |
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 { | |
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 { | |
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 { | |
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 } |