support for the BSD dialect of AR

git-svn-id: https://svn.apache.org/repos/asf/ant/antlibs/compress/trunk@1154959 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/changes.xml b/changes.xml
index a567c37..2d1abec 100644
--- a/changes.xml
+++ b/changes.xml
@@ -42,6 +42,11 @@
         The Apache Compress Antlib now requires Apache Commons
         Compress 1.3 which in turn requires Java5 at runtime.
       </action>
+      <action type="update">
+        The &lt;ar&gt; task now optionally suppports writing entries
+        with names longer than 16 characters using the BSD variant of
+        AR archives.
+      </action>
       <action type="add">
         The unarchiving tasks and fileset types share a new attribute
         skipUnreadableEntries that can be used to ignore archive
diff --git a/docs/archive.html b/docs/archive.html
index e420537..cd16380 100644
--- a/docs/archive.html
+++ b/docs/archive.html
@@ -222,11 +222,27 @@
   <p>An <a href="#archive">archiving task</a> creating archives of the
     AR format.</p>
 
-  <p>The AR format is pretty limited, it can only store file names up
+  <p>The AR format is pretty limited, by default it can only store file names up
     to 16 characters and not store directories at all.  It is not
     possible to set the <code>filesonly</code> attribute to true for
     the <code>ar</code> task.</p>
 
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">format</td>
+      <td valign="top">Ar format for entries with names longer than
+        16 characters.  Supported values are "ar" which doesn't
+        support entries of that length and results in a build failure
+        and "bsd".</td>
+      <td valign="top" align="center">No, default is "ar"</td>
+    </tr>
+  </table>
+
   <h3><a name="cpio">Cpio</a></h3>
 
   <p>An <a href="#archive">archiving task</a> creating archives of the
diff --git a/src/main/org/apache/ant/compress/taskdefs/Ar.java b/src/main/org/apache/ant/compress/taskdefs/Ar.java
index c8a5b20..cbca87d 100644
--- a/src/main/org/apache/ant/compress/taskdefs/Ar.java
+++ b/src/main/org/apache/ant/compress/taskdefs/Ar.java
@@ -18,12 +18,17 @@
 
 package org.apache.ant.compress.taskdefs;
 
-import org.apache.ant.compress.util.ArStreamFactory;
+import java.io.IOException;
+import java.io.OutputStream;
 import org.apache.ant.compress.resources.ArFileSet;
+import org.apache.ant.compress.util.ArStreamFactory;
 import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveOutputStream;
 import org.apache.commons.compress.archivers.ar.ArArchiveEntry;
+import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream;
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.types.ArchiveFileSet;
+import org.apache.tools.ant.types.EnumeratedAttribute;
 import org.apache.tools.ant.types.Resource;
 
 /**
@@ -34,8 +39,22 @@
     private static final String NO_DIRS_MESSAGE = "ar archives cannot store"
         + " directory entries";
 
+    private Format format = Format.AR;
+
     public Ar() {
-        setFactory(new ArStreamFactory());
+        setFactory(new ArStreamFactory() {
+                public ArchiveOutputStream getArchiveStream(OutputStream stream,
+                                                            String encoding)
+                    throws IOException {
+                    ArArchiveOutputStream o =
+                        (ArArchiveOutputStream) super.getArchiveStream(stream,
+                                                                       encoding);
+                    if (format.equals(Format.BSD)) {
+                        o.setLongFileMode(ArArchiveOutputStream.LONGFILE_BSD);
+                    }
+                    return o;
+                }
+            });
         setEntryBuilder(
               new ArchiveBase.EntryBuilder() {
                 public ArchiveEntry buildEntry(ArchiveBase.ResourceWithFlags r) {
@@ -85,4 +104,43 @@
             throw new BuildException(NO_DIRS_MESSAGE);
         }
     }
+
+    /**
+     * The format for entries with filenames longer than 16 characters
+     * or containign spaces - any other entry will always use "ar".
+     *
+     * @since Apache Compress Antlib 1.1
+     */
+    public void setFormat(Format f) {
+        format = f;
+    }
+
+    /**
+     * The supported tar formats for entries with long file names.
+     */
+    public final static class Format extends EnumeratedAttribute {
+        private static final String AR_NAME = "ar";
+        private static final String BSD_NAME = "bsd";
+
+        public static final Format AR = new Format(AR_NAME);
+        public static final Format BSD = new Format(BSD_NAME);
+
+        public Format(String v) {
+            setValue(v);
+        }
+
+        public Format() {
+            setValue(AR_NAME);
+        }
+
+        public String[] getValues() {
+            return new String[] {AR_NAME, BSD_NAME};
+        }
+
+        public boolean equals(Object other) {
+            return other instanceof Format
+                && ((Format) other).getValue().equals(getValue());
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/src/tests/antunit/ar-test.xml b/src/tests/antunit/ar-test.xml
index 7444c71..c2a291e 100644
--- a/src/tests/antunit/ar-test.xml
+++ b/src/tests/antunit/ar-test.xml
@@ -539,4 +539,26 @@
       </cond:islastmodified>
     </au:assertFalse>
   </target>
+
+  <target name="testLongNameException" depends="setUp">
+    <touch file="${input}/this-is-a-long-name-for-ar.txt"/>
+    <au:expectfailure>
+      <cmp:ar dest="${dest}">
+        <fileset dir="${input}"/>
+      </cmp:ar>
+    </au:expectfailure>
+  </target>
+
+
+  <target name="testLongNameBSD" depends="setUp">
+    <touch file="${input}/this-is-a-long-name-for-ar.txt"/>
+    <cmp:ar dest="${dest}" format="bsd">
+      <fileset dir="${input}"/>
+    </cmp:ar>
+    <assertResourceExists>
+      <cmp:arentry name="this-is-a-long-name-for-ar.txt">
+        <file file="${dest}"/>
+      </cmp:arentry>
+    </assertResourceExists>
+  </target>
 </project>