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    }