001 /*
002 * Copyright 2005 The Apache Software Foundation.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.vafer.jdeb.ar;
017
018 import java.io.IOException;
019 import java.io.OutputStream;
020
021 /**
022 * To be replace by commons compress once released
023 *
024 * @author Torsten Curdt <tcurdt@vafer.org>
025 */
026 public class ArOutputStream extends OutputStream implements ArConstants {
027
028 private final OutputStream out;
029 private long archiveOffset = 0;
030 private long entryOffset = 0;
031 private ArEntry prevEntry;
032
033 public ArOutputStream( final OutputStream pOut ) {
034 out = pOut;
035 }
036
037 private long writeArchiveHeader() throws IOException {
038 out.write(HEADER);
039 return HEADER.length;
040 }
041
042 private void closeEntry() throws IOException {
043 if ((entryOffset % 2) != 0) {
044 write('\n');
045 archiveOffset++;
046 }
047 }
048
049 public void putNextEntry( final ArEntry pEntry ) throws IOException {
050
051 if (prevEntry == null) {
052 archiveOffset += writeArchiveHeader();
053 } else {
054 if (prevEntry.getLength() != entryOffset) {
055 throw new IOException("length does not match entry (" + prevEntry.getLength() + " != " + entryOffset);
056 }
057
058 closeEntry();
059 }
060
061 prevEntry = pEntry;
062
063 archiveOffset += writeEntryHeader(pEntry);
064
065 entryOffset = 0;
066 }
067
068 /**
069 * Write the data to the stream and pad the output
070 * with white spaces up to the specified size.
071 *
072 * @param data the value to be written
073 * @param size the total size of the output
074 * @param fieldname the name of the field
075 */
076 private void write(String data, int size, String fieldname) throws IOException {
077 if (data.length() > size) {
078 throw new IOException(fieldname + " too long");
079 }
080
081 long length = size - write(data);
082 for (int i = 0; i < length; i++) {
083 write(' ');
084 }
085 }
086
087 private long write( final String data ) throws IOException {
088 final byte[] bytes = data.getBytes("ascii");
089 write(bytes);
090 return bytes.length;
091 }
092
093 private long writeEntryHeader( final ArEntry entry ) throws IOException {
094
095 String n = entry.getName();
096 write(n, FIELD_SIZE_NAME, "filename");
097
098 String m = "" + (entry.getLastModified() / 1000);
099 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 }