package org.apache.commons.compress.archivers.ar;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.utils.ArchiveUtils;
public class ArArchiveOutputStream extends ArchiveOutputStream {
public static final int LONGFILE_ERROR = 0;
public static final int LONGFILE_BSD = 1;
private final OutputStream out;
private long entryOffset = 0;
private ArArchiveEntry prevEntry;
private boolean haveUnclosedEntry = false;
private int longFileMode = LONGFILE_ERROR;
private boolean finished = false;
public ArArchiveOutputStream( final OutputStream pOut ) {
this.out = pOut;
}
public void setLongFileMode(final int longFileMode) {
this.longFileMode = longFileMode;
}
private long () throws IOException {
final byte [] header = ArchiveUtils.toAsciiBytes(ArArchiveEntry.HEADER);
out.write(header);
return header.length;
}
@Override
public void closeArchiveEntry() throws IOException {
if(finished) {
throw new IOException("Stream has already been finished");
}
if (prevEntry == null || !haveUnclosedEntry){
throw new IOException("No current entry to close");
}
if (entryOffset % 2 != 0) {
out.write('\n');
}
haveUnclosedEntry = false;
}
@Override
public void putArchiveEntry( final ArchiveEntry pEntry ) throws IOException {
if(finished) {
throw new IOException("Stream has already been finished");
}
final ArArchiveEntry pArEntry = (ArArchiveEntry)pEntry;
if (prevEntry == null) {
writeArchiveHeader();
} else {
if (prevEntry.getLength() != entryOffset) {
throw new IOException("length does not match entry (" + prevEntry.getLength() + " != " + entryOffset);
}
if (haveUnclosedEntry) {
closeArchiveEntry();
}
}
prevEntry = pArEntry;
writeEntryHeader(pArEntry);
entryOffset = 0;
haveUnclosedEntry = true;
}
private long fill( final long pOffset, final long pNewOffset, final char pFill ) throws IOException {
final long diff = pNewOffset - pOffset;
if (diff > 0) {
for (int i = 0; i < diff; i++) {
write(pFill);
}
}
return pNewOffset;
}
private long write( final String data ) throws IOException {
final byte[] bytes = data.getBytes("ascii");
write(bytes);
return bytes.length;
}
private long ( final ArArchiveEntry pEntry ) throws IOException {
long offset = 0;
boolean mustAppendName = false;
final String n = pEntry.getName();
if (LONGFILE_ERROR == longFileMode && n.length() > 16) {
throw new IOException("filename too long, > 16 chars: "+n);
}
if (LONGFILE_BSD == longFileMode &&
(n.length() > 16 || n.contains(" "))) {
mustAppendName = true;
offset += write(ArArchiveInputStream.BSD_LONGNAME_PREFIX
+ String.valueOf(n.length()));
} else {
offset += write(n);
}
offset = fill(offset, 16, ' ');
final String m = "" + pEntry.getLastModified();
if (m.length() > 12) {
throw new IOException("modified too long");
}
offset += write(m);
offset = fill(offset, 28, ' ');
final String u = "" + pEntry.getUserId();
if (u.length() > 6) {
throw new IOException("userid too long");
}
offset += write(u);
offset = fill(offset, 34, ' ');
final String g = "" + pEntry.getGroupId();
if (g.length() > 6) {
throw new IOException("groupid too long");
}
offset += write(g);
offset = fill(offset, 40, ' ');
final String fm = "" + Integer.toString(pEntry.getMode(), 8);
if (fm.length() > 8) {
throw new IOException("filemode too long");
}
offset += write(fm);
offset = fill(offset, 48, ' ');
final String s =
String.valueOf(pEntry.getLength()
+ (mustAppendName ? n.length() : 0));
if (s.length() > 10) {
throw new IOException("size too long");
}
offset += write(s);
offset = fill(offset, 58, ' ');
offset += write(ArArchiveEntry.TRAILER);
if (mustAppendName) {
offset += write(n);
}
return offset;
}
@Override
public void write(final byte[] b, final int off, final int len) throws IOException {
out.write(b, off, len);
count(len);
entryOffset += len;
}
@Override
public void close() throws IOException {
try {
if (!finished) {
finish();
}
} finally {
out.close();
prevEntry = null;
}
}
@Override
public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName)
throws IOException {
if(finished) {
throw new IOException("Stream has already been finished");
}
return new ArArchiveEntry(inputFile, entryName);
}
@Override
public void finish() throws IOException {
if(haveUnclosedEntry) {
throw new IOException("This archive contains unclosed entries.");
} else if(finished) {
throw new IOException("This archive has already been finished");
}
finished = true;
}
}