View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.vafer.jdeb.ar;
17  
18  import java.io.IOException;
19  import java.io.OutputStream;
20  
21  /**
22   * To be replace by commons compress once released
23   * 
24   * @author Torsten Curdt <tcurdt@vafer.org>
25   */
26  public class ArOutputStream extends OutputStream implements ArConstants {
27  
28  	private final OutputStream out;
29  	private long archiveOffset = 0;
30  	private long entryOffset = 0;
31  	private ArEntry prevEntry;
32  
33  	public ArOutputStream( final OutputStream pOut ) {
34  		out = pOut;
35  	}
36  
37  	private long writeArchiveHeader() throws IOException {		
38  		out.write(HEADER);
39  		return HEADER.length;
40  	}
41  
42  	private void closeEntry() throws IOException {
43  		if ((entryOffset % 2) != 0) {
44          	write('\n');
45          	archiveOffset++;
46          }		
47  	}
48  	
49  	public void putNextEntry( final ArEntry pEntry ) throws IOException {
50  		
51  		if (prevEntry == null) {
52  			archiveOffset += writeArchiveHeader();			
53  		} else {
54  			if (prevEntry.getLength() != entryOffset) {
55  				throw new IOException("length does not match entry (" + prevEntry.getLength() + " != " + entryOffset);
56  			}
57  			
58  			closeEntry();
59  		}
60  		
61  		prevEntry = pEntry;
62  		
63  		archiveOffset += writeEntryHeader(pEntry);
64  
65  		entryOffset = 0;
66  	}
67  
68  	/**
69  	 * Write the data to the stream and pad the output
70  	 * with white spaces up to the specified size.
71  	 *
72  	 * @param data	  the value to be written
73  	 * @param size	  the total size of the output
74  	 * @param fieldname the name of the field
75  	 */
76  	private void write(String data, int size, String fieldname) throws IOException {
77  		if (data.length() > size) {
78  			throw new IOException(fieldname + " too long");
79  		}
80  
81  		long length = size - write(data);
82  		for (int i = 0; i < length; i++) {
83  			write(' ');
84  		}
85  	}
86  
87  	private long write( final String data ) throws IOException {
88  		final byte[] bytes = data.getBytes("ascii");
89  		write(bytes);
90  		return bytes.length;
91  	}
92  	
93  	private long writeEntryHeader( final ArEntry entry ) throws IOException {
94  
95  		String n = entry.getName();
96  		write(n, FIELD_SIZE_NAME, "filename");
97  
98  		String m = "" + (entry.getLastModified() / 1000);
99  		write(m, FIELD_SIZE_LASTMODIFIED, "lastmodified");
100 
101 		String u = "" + entry.getUserId();
102 		write(u, FIELD_SIZE_UID, "userid");
103 
104 		String g = "" + entry.getGroupId();
105 		write(g, FIELD_SIZE_GID, "groupid");
106 
107 		String fm = Integer.toString(entry.getMode(), 8);
108 		write(fm, FIELD_SIZE_MODE, "filemode");
109 
110 		String s = "" + entry.getLength();
111 		write(s, FIELD_SIZE_LENGTH, "size");
112 
113 		write(ENTRY_TERMINATOR);
114 		
115 		return HEADER_SIZE;
116 	}		
117 	
118 	public void write(int b) throws IOException {
119 		out.write(b);
120 		entryOffset++;
121 	}
122 
123 	public void write(byte[] b, int off, int len) throws IOException {
124 		out.write(b, off, len);
125 		entryOffset += len;
126 	}
127 
128 	public void write(byte[] b) throws IOException {
129 		out.write(b);
130 		entryOffset += b.length;
131 	}
132 
133 	public void close() throws IOException {
134 		closeEntry();
135 		out.close();
136 		prevEntry = null;
137 	}
138 	
139 }