COMPRESS-179 TarUtils.formatLongOctalOrBinaryBytes() assumes the field will be 12 bytes long

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/compress/trunk@1292596 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index f29ce0b..1eca3da 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -46,6 +46,9 @@
   <body>
     <release version="1.4" date="unreleased"
              description="Release 1.4">
+      <action issue="COMPRESS-179" type="fix" date="2012-02-23">
+        TarUtils.formatLongOctalOrBinaryBytes() assumes the field will be 12 bytes long
+      </action> 
       <action issue="COMPRESS-175" type="fix" date="2012-02-22">
         GNU Tar sometimes uses binary encoding for UID and GID
       </action> 
diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
index e77ce97..ad84490 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
@@ -58,6 +58,13 @@
     int    GIDLEN = 8;
 
     /**
+     * The maximum value of gid/uid in a tar archive which can
+     * be expressed in octal char notation (that's 7 sevens, octal).
+     * @since 1.4
+     */
+    long    MAXID = 07777777L;
+ 
+    /**
      * The length of the checksum field in a header buffer.
      */
     int    CHKSUMLEN = 8;
@@ -69,7 +76,8 @@
     int    SIZELEN = 12;
 
     /**
-     * The maximum size of a file in a tar archive (That's 11 sevens, octal).
+     * The maximum size of a file in a tar archive 
+     * which can be expressed in octal char notation (that's 11 sevens, octal).
      */
     long   MAXSIZE = 077777777777L;
 
diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
index 674fd22..7afe0d3 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
@@ -324,7 +324,10 @@
     public static int formatLongOctalOrBinaryBytes(
         final long value, byte[] buf, final int offset, final int length) {
 
-        if (value < TarConstants.MAXSIZE + 1) {
+        // Check whether we are dealing with UID/GID or SIZE field
+        final long maxAsOctalChar = length == TarConstants.UIDLEN ? TarConstants.MAXID : TarConstants.MAXSIZE;
+
+        if (value <= maxAsOctalChar) { // OK to store as octal chars
             return formatLongOctalBytes(value, buf, offset, length);
         }
 
diff --git a/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java b/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
index 9e48128..9397767 100644
--- a/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
@@ -110,20 +110,43 @@
         }
     }
 
-    private void checkRoundTripOctal(final long value) {
-        byte [] buffer = new byte[12];
+    private void checkRoundTripOctal(final long value, final int bufsize) {
+        byte [] buffer = new byte[bufsize];
         long parseValue;
         TarUtils.formatLongOctalBytes(value, buffer, 0, buffer.length);
         parseValue = TarUtils.parseOctal(buffer,0, buffer.length);
         assertEquals(value,parseValue);
     }
     
+    private void checkRoundTripOctal(final long value) {
+        checkRoundTripOctal(value, TarConstants.SIZELEN);
+    }
+
     public void testRoundTripOctal() {
         checkRoundTripOctal(0);
         checkRoundTripOctal(1);
 //        checkRoundTripOctal(-1); // TODO What should this do?
-        checkRoundTripOctal(077777777777L);
+        checkRoundTripOctal(TarConstants.MAXSIZE);
 //        checkRoundTripOctal(0100000000000L); // TODO What should this do?
+
+        checkRoundTripOctal(0, TarConstants.UIDLEN);
+        checkRoundTripOctal(1, TarConstants.UIDLEN);
+        checkRoundTripOctal(TarConstants.MAXID, 8);
+    }
+
+    private void checkRoundTripOctalOrBinary(final long value, final int bufsize) {
+        byte [] buffer = new byte[bufsize];
+        long parseValue;
+        TarUtils.formatLongOctalOrBinaryBytes(value, buffer, 0, buffer.length);
+        parseValue = TarUtils.parseOctalOrBinary(buffer,0, buffer.length);
+        assertEquals(value,parseValue);
+    }
+
+    public void testRoundTripOctalOrBinary() {
+        checkRoundTripOctalOrBinary(0, 8);
+        checkRoundTripOctalOrBinary(1, 8);
+        checkRoundTripOctalOrBinary(Long.MAX_VALUE, 8); // [0x7f ff ff ff ff ff ff ff
+        checkRoundTripOctalOrBinary(TarConstants.MAXSIZE, 8); // will need binary format
     }
     
     // Check correct trailing bytes are generated