<p>Before reading anything else, please take time to read the <a href="https://stackoverflow.com/questions/1615/how-can-i-modify-xfdl-files-update-1">original thread</a>.</p>

<p>Overview:  a .xfdl file is a gzipped .xml file which has then been encoded in base64.  I wish to de-encode the .xfdl into xml which I can then modify and then re-encode back into a .xfdl file.</p>

<blockquote>
  <p>xfdl > xml.gz > xml > xml.gz > xfdl</p>
</blockquote>

<p>I have been able to take a .xfdl file and de-encode it from base64 using uudeview:</p>

<pre><code>uudeview -i yourform.xfdl
</code></pre>

<p>Then decommpressed it using gunzip</p>

<pre><code>gunzip -S "" &lt; UNKNOWN.001 &gt; yourform-unpacked.xml
</code></pre>

<p>The xml produced is 100% readable and looks wonderful.  Without modifying the xml then, i should be able to re-compress it using gzip:</p>

<pre><code>gzip yourform-unpacked.xml
</code></pre>

<p>Then re-encoded in base-64:</p>

<pre><code>base64 -e yourform-unpacked.xml.gz yourform_reencoded.xfdl
</code></pre>

<p>If my thinking is correct, the original file and the re-encoded file should be equal.  If I put yourform.xfdl and yourform_reencoded.xfdl into beyond compare, however, they do not match up.  Also, the original file can be viewed in an http://www.grants.gov/help/download_software.jsp#pureedge">.xfdl viewer.  The viewer says that the re-encoded xfdl is unreadable.  </p>

<p>I have also tried uuenview to re-encode in base64, it also produces the same results. Any help would be appreciated.</p>

[{'answer_id': 6825, 'author': 'John Downey', 'author_id': 200, 'author_profile': 'https://Stackoverflow.com/users/200', 'pm_score': 0, 'selected': False, 'text': '<p>Different implementations of the gzip algorithm will always produce slightly different but still correct files, also the compression level of the original file may be different then what you are running it at.</p>\n'}, {'answer_id': 6845, 'author': 'John Downey', 'author_id': 200, 'author_profile': 'https://Stackoverflow.com/users/200', 'pm_score': 2, 'selected': False, 'text': "<p>As far as I know you cannot find the compression level of an already compressed file. When you are compressing the file you can specify the compression level with -# where the # is from 1 to 9 (1 being the fastest compression and 9 being the most compressed file). In practice you should never compare a compressed file with one that has been extracted and recompressed, slight variations can easily crop up. In your case I would compare the base64 encoded versions instead of the gzip'd versions.</p>\n"}, {'answer_id': 6852, 'author': 'CodingWithoutComments', 'author_id': 25, 'author_profile': 'https://Stackoverflow.com/users/25', 'pm_score': 0, 'selected': False, 'text': "<p>Interesting, I'll give it a shot.  The variations aren't slight, however.  The newly encoded file is longer and when comparing the binary of the before and after, the data hardly matches up at all.</p>\n\n<p>Before (the first three lines)</p>\n\n<pre><code>H4sIAAAAAAAAC+19eZOiyNb3/34K3r4RT/WEU40ssvTtrhuIuKK44Bo3YoJdFAFZ3D79C6hVVhUq\ndsnUVN/qmIkSOLlwlt/JPCfJ/PGf9dwAlorj6pb58wv0LfcFUEzJknVT+/ml2uXuCSJP3kNf/vOQ\n+TEsFVkgoDfdn18mnmd/B8HVavWt5TsKI2vKN8magyENiH3Lf9kRfpd817PmF+jpiOhQRFZcXTMV\n</code></pre>\n\n<p>After (the first three lines):</p>\n\n<pre><code>H4sICJ/YnEgAAzEyNDQ2LTExNjk2NzUueGZkbC54bWwA7D1pU+JK19/9FV2+H5wpByEhJMRH\nuRUgCMom4DBYt2oqkAZyDQlmQZ1f/3YSNqGzKT3oDH6RdE4vOXuf08vFP88TFcygYSq6dnlM\nnaWOAdQGuqxoo8vjSruRyGYzfII6/id3dPGjVKwCBK+Zl8djy5qeJ5NPT09nTduAojyCZwN9\n</code></pre>\n\n<p>As you can see <code>H4SI</code> match up, then after that it's pandemonium.</p>\n"}, {'answer_id': 1414463, 'author': 'Paradigm', 'author_id': 172404, 'author_profile': 'https://Stackoverflow.com/users/172404', 'pm_score': 1, 'selected': False, 'text': '<p>You\'ll need to put the following line at the beginning of the XFDL file:</p>\n\n<p><code>application/vnd.xfdl; content-encoding="base64-gzip"</code></p>\n\n<p>After you\'ve generated the base64-encoded file, open it in a text editor and paste the line above on the first line. Ensure that the base64\'ed block starts at the beginning of the second line.</p>\n\n<p>Save it and try it in the Viewer! If it still does not work, it may be that the changes that were made to the XML made it non-compliant in some manner. In this case, after the XML has been modified, but before it has been gzipped and base64 encoded, save it with an .xfdl file extension and try opening it with the Viewer tool. The viewer should be able to parse and display the uncompressed / unencoded file if it is in a valid XFDL format.</p>\n'}, {'answer_id': 1539927, 'author': 'Alex Lehmann', 'author_id': 27069, 'author_profile': 'https://Stackoverflow.com/users/27069', 'pm_score': 0, 'selected': False, 'text': '<p>gzip will put the filename in the header of file, so that a gzipped file vary in length depending on the filename of the uncompressed file.</p>\n\n<p>If gzip acts on a stream, the filename is omitted and the file is a bit shorter, so the following should work:</p>\n\n<p>gzip yourform-unpacked.xml.gz</p>\n\n<p>Then re-encoded in base-64:\nbase64 -e yourform-unpacked.xml.gz yourform_reencoded.xfdl</p>\n\n<p>maybe this will produce a file of the same length</p>\n'}, {'answer_id': 5021875, 'author': 'CrazyPyro', 'author_id': 268066, 'author_profile': 'https://Stackoverflow.com/users/268066', 'pm_score': 1, 'selected': False, 'text': '<p>Check these out:</p>\n\n<p><a href="http://www.ourada.org/blog/archives/375" rel="nofollow">http://www.ourada.org/blog/archives/375</a></p>\n\n<p><a href="http://www.ourada.org/blog/archives/390" rel="nofollow">http://www.ourada.org/blog/archives/390</a></p>\n\n<p>They are in Python, not Ruby, but that should get you pretty close.</p>\n\n<p>And the algorithm is actually for files with header \'application/x-xfdl;content-encoding="asc-gzip"\' rather than \'application/vnd.xfdl; content-encoding="base64-gzip"\'\nBut the good news is that PureEdge (aka IBM Lotus Forms) will open that format with no problem.</p>\n\n<p>Then to top it off, here\'s a base64-gzip decode (in Python) so you can make the full round-trip:</p>\n\n<pre><code>with open(filename, \'r\') as f:\n  header = f.readline()\n  if header == \'application/vnd.xfdl; content-encoding="base64-gzip"\\n\':\n    decoded = b\'\'\n    for line in f:\n      decoded += base64.b64decode(line.encode("ISO-8859-1"))\n    xml = zlib.decompress(decoded, zlib.MAX_WBITS + 16)\n</code></pre>\n'}, {'answer_id': 5465913, 'author': 'MrWizard54', 'author_id': 193827, 'author_profile': 'https://Stackoverflow.com/users/193827', 'pm_score': 1, 'selected': False, 'text': '<p>I did this in Java with the help of the Base64 class from <a href="http://iharder.net/base64" rel="nofollow">http://iharder.net/base64</a>.</p>\n\n<p>I\'ve been working on an application to do form manipulation in Java.  I decode the file, create an DOM document from the XML then write it back to file.  </p>\n\n<p>My code in Java to read the file looks like this:</p>\n\n<pre><code>public XFDLDocument(String inputFile) \n        throws IOException, \n            ParserConfigurationException,\n            SAXException\n\n{\n    fileLocation = inputFile;\n\n    try{\n\n        //create file object\n        File f = new File(inputFile);\n        if(!f.exists()) {\n            throw new IOException("Specified File could not be found!");\n        }\n\n        //open file stream from file\n        FileInputStream fis = new FileInputStream(inputFile);\n\n        //Skip past the MIME header\n        fis.skip(FILE_HEADER_BLOCK.length());   \n\n        //Decompress from base 64                   \n        Base64.InputStream bis = new Base64.InputStream(fis, \n                Base64.DECODE);\n\n        //UnZIP the resulting stream\n        GZIPInputStream gis = new GZIPInputStream(bis);\n\n        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n        DocumentBuilder db = dbf.newDocumentBuilder();\n        doc = db.parse(gis);\n\n        gis.close();\n        bis.close();\n        fis.close();\n\n    }\n    catch (ParserConfigurationException pce) {\n        throw new ParserConfigurationException("Error parsing XFDL from file.");\n    }\n    catch (SAXException saxe) {\n        throw new SAXException("Error parsing XFDL into XML Document.");\n    }\n}\n</code></pre>\n\n<p>My code in java looks like this to write the file to disk:</p>\n\n<pre><code>    /**\n     * Saves the current document to the specified location\n     * @param destination Desired destination for the file.\n     * @param asXML True if output needs should be as un-encoded XML not Base64/GZIP\n     * @throws IOException File cannot be created at specified location\n     * @throws TransformerConfigurationExample\n     * @throws TransformerException \n     */\n    public void saveFile(String destination, boolean asXML) \n        throws IOException, \n            TransformerConfigurationException, \n            TransformerException  \n        {\n\n        BufferedWriter bf = new BufferedWriter(new FileWriter(destination));\n        bf.write(FILE_HEADER_BLOCK);\n        bf.newLine();\n        bf.flush();\n        bf.close();\n\n        OutputStream outStream;\n        if(!asXML) {\n            outStream = new GZIPOutputStream(\n                new Base64.OutputStream(\n                        new FileOutputStream(destination, true)));\n        } else {\n            outStream = new FileOutputStream(destination, true);\n        }\n\n        Transformer t = TransformerFactory.newInstance().newTransformer();\n        t.transform(new DOMSource(doc), new StreamResult(outStream));\n\n        outStream.flush();\n        outStream.close();      \n    }\n</code></pre>\n\n<p>Hope that helps.</p>\n'}, {'answer_id': 8902867, 'author': 'Ross Bielski', 'author_id': 958195, 'author_profile': 'https://Stackoverflow.com/users/958195', 'pm_score': 1, 'selected': False, 'text': '<p>I\'ve been working on something like that and this should work for php. You must have a writable tmp folder and the php file be named example.php!</p>\n\n<pre><code>    &lt;?php\n    function gzdecode($data) {\n        $len = strlen($data);\n        if ($len &lt; 18 || strcmp(substr($data,0,2),"\\x1f\\x8b")) {\n            echo "FILE NOT GZIP FORMAT";\n            return null;  // Not GZIP format (See RFC 1952)\n        }\n        $method = ord(substr($data,2,1));  // Compression method\n        $flags  = ord(substr($data,3,1));  // Flags\n        if ($flags &amp; 31 != $flags) {\n            // Reserved bits are set -- NOT ALLOWED by RFC 1952\n            echo "RESERVED BITS ARE SET. VERY BAD";\n            return null;\n        }\n        // NOTE: $mtime may be negative (PHP integer limitations)\n        $mtime = unpack("V", substr($data,4,4));\n        $mtime = $mtime[1];\n        $xfl   = substr($data,8,1);\n        $os    = substr($data,8,1);\n        $headerlen = 10;\n        $extralen  = 0;\n        $extra     = "";\n        if ($flags &amp; 4) {\n            // 2-byte length prefixed EXTRA data in header\n            if ($len - $headerlen - 2 &lt; 8) {\n                return false;    // Invalid format\n                echo "INVALID FORMAT";\n            }\n            $extralen = unpack("v",substr($data,8,2));\n            $extralen = $extralen[1];\n            if ($len - $headerlen - 2 - $extralen &lt; 8) {\n                return false;    // Invalid format\n                echo "INVALID FORMAT";\n            }\n            $extra = substr($data,10,$extralen);\n            $headerlen += 2 + $extralen;\n        }\n\n        $filenamelen = 0;\n        $filename = "";\n        if ($flags &amp; 8) {\n            // C-style string file NAME data in header\n            if ($len - $headerlen - 1 &lt; 8) {\n                return false;    // Invalid format\n                echo "INVALID FORMAT";\n            }\n            $filenamelen = strpos(substr($data,8+$extralen),chr(0));\n            if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 &lt; 8) {\n                return false;    // Invalid format\n                echo "INVALID FORMAT";\n            }\n            $filename = substr($data,$headerlen,$filenamelen);\n            $headerlen += $filenamelen + 1;\n        }\n\n        $commentlen = 0;\n        $comment = "";\n        if ($flags &amp; 16) {\n            // C-style string COMMENT data in header\n            if ($len - $headerlen - 1 &lt; 8) {\n                return false;    // Invalid format\n                echo "INVALID FORMAT";\n            }\n            $commentlen = strpos(substr($data,8+$extralen+$filenamelen),chr(0));\n            if ($commentlen === false || $len - $headerlen - $commentlen - 1 &lt; 8) {\n                return false;    // Invalid header format\n                echo "INVALID FORMAT";\n            }\n            $comment = substr($data,$headerlen,$commentlen);\n            $headerlen += $commentlen + 1;\n        }\n\n        $headercrc = "";\n        if ($flags &amp; 1) {\n            // 2-bytes (lowest order) of CRC32 on header present\n            if ($len - $headerlen - 2 &lt; 8) {\n                return false;    // Invalid format\n                echo "INVALID FORMAT";\n            }\n            $calccrc = crc32(substr($data,0,$headerlen)) &amp; 0xffff;\n            $headercrc = unpack("v", substr($data,$headerlen,2));\n            $headercrc = $headercrc[1];\n            if ($headercrc != $calccrc) {\n                echo "BAD CRC";\n                return false;    // Bad header CRC\n            }\n            $headerlen += 2;\n        }\n\n        // GZIP FOOTER - These be negative due to PHP\'s limitations\n        $datacrc = unpack("V",substr($data,-8,4));\n        $datacrc = $datacrc[1];\n        $isize = unpack("V",substr($data,-4));\n        $isize = $isize[1];\n\n        // Perform the decompression:\n        $bodylen = $len-$headerlen-8;\n        if ($bodylen &lt; 1) {\n            // This should never happen - IMPLEMENTATION BUG!\n            echo "BIG OOPS";\n            return null;\n        }\n        $body = substr($data,$headerlen,$bodylen);\n        $data = "";\n        if ($bodylen &gt; 0) {\n            switch ($method) {\n                case 8:\n                    // Currently the only supported compression method:\n                    $data = gzinflate($body);\n                    break;\n                default:\n                    // Unknown compression method\n                    echo "UNKNOWN COMPRESSION METHOD";\n                return false;\n            }\n        } else {\n            // I\'m not sure if zero-byte body content is allowed.\n            // Allow it for now...  Do nothing...\n            echo "ITS EMPTY";\n        }\n\n        // Verifiy decompressed size and CRC32:\n        // NOTE: This may fail with large data sizes depending on how\n        //       PHP\'s integer limitations affect strlen() since $isize\n        //       may be negative for large sizes.\n        if ($isize != strlen($data) || crc32($data) != $datacrc) {\n            // Bad format!  Length or CRC doesn\'t match!\n            echo "LENGTH OR CRC DO NOT MATCH";\n            return false;\n        }\n        return $data;\n    }\n    echo "&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;";\n    if (empty($_REQUEST[\'upload\'])) {\n        echo &lt;&lt;&lt;_END\n    &lt;form enctype="multipart/form-data" action="example.php" method="POST"&gt;\n    &lt;input type="hidden" name="MAX_FILE_SIZE" value="100000" /&gt;\n    &lt;table&gt;\n    &lt;th&gt;\n    &lt;input name="uploadedfile" type="file" /&gt;\n    &lt;/th&gt;\n    &lt;tr&gt;\n    &lt;td&gt;&lt;input type="submit" name="upload" value="Convert File" /&gt;&lt;/td&gt;\n    &lt;/tr&gt;\n    &lt;/table&gt;\n    &lt;/form&gt;\n    _END;\n\n    }\n    if (!empty($_REQUEST[\'upload\'])) {\n        $file           = "tmp/" . $_FILES[\'uploadedfile\'][\'name\'];\n        $orgfile        = $_FILES[\'uploadedfile\'][\'name\'];\n        $name           = str_replace(".xfdl", "", $orgfile);\n        $convertedfile  = "tmp/" . $name . ".xml";\n        $compressedfile = "tmp/" . $name . ".gz";\n        $finalfile      = "tmp/" . $name . "new.xfdl";\n        $target_path    = "tmp/";\n        $target_path    = $target_path . basename($_FILES[\'uploadedfile\'][\'name\']);\n        if (move_uploaded_file($_FILES[\'uploadedfile\'][\'tmp_name\'], $target_path)) {\n        } else {\n            echo "There was an error uploading the file, please try again!";\n        }\n        $firstline      = "application/vnd.xfdl; content-encoding=\\"base64-gzip\\"\\n";\n        $data           = file($file);\n        $data           = array_slice($data, 1);\n        $raw            = implode($data);\n        $decoded        = base64_decode($raw);\n        $decompressed   = gzdecode($decoded);\n        $compressed     = gzencode($decompressed);\n        $encoded        = base64_encode($compressed);\n        $decoded2       = base64_decode($encoded);\n        $decompressed2  = gzdecode($decoded2);\n        $header         = bin2hex(substr($decoded, 0, 10));\n        $tail           = bin2hex(substr($decoded, -8));\n        $header2        = bin2hex(substr($compressed, 0, 10));\n        $tail2          = bin2hex(substr($compressed, -8));\n        $header3        = bin2hex(substr($decoded2, 0, 10));\n        $tail3          = bin2hex(substr($decoded2, -8));\n        $filehandle     = fopen($compressedfile, \'w\');\n        fwrite($filehandle, $decoded);\n        fclose($filehandle);\n        $filehandle     = fopen($convertedfile, \'w\');\n        fwrite($filehandle, $decompressed);\n        fclose($filehandle);\n        $filehandle     = fopen($finalfile, \'w\');\n        fwrite($filehandle, $firstline);\n        fwrite($filehandle, $encoded);\n        fclose($filehandle);\n        echo "&lt;center&gt;";\n        echo "&lt;table style=\'text-align:center\' &gt;";\n        echo "&lt;tr&gt;&lt;th&gt;Stage 1&lt;/th&gt;";\n        echo "&lt;th&gt;Stage 2&lt;/th&gt;";\n        echo "&lt;th&gt;Stage 3&lt;/th&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;RAW DATA -&gt;&lt;/td&gt;&lt;td&gt;DECODED DATA -&gt;&lt;/td&gt;&lt;td&gt;UNCOMPRESSED DATA -&gt;&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;LENGTH: ".strlen($raw)."&lt;/td&gt;";\n        echo "&lt;td&gt;LENGTH: ".strlen($decoded)."&lt;/td&gt;";\n        echo "&lt;td&gt;LENGTH: ".strlen($decompressed)."&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;&lt;a href=\'tmp/".$orgfile."\'/&gt;ORIGINAL&lt;/a&gt;&lt;/td&gt;&lt;td&gt;GZIP HEADER:".$header."&lt;/td&gt;&lt;td&gt;&lt;a href=\'".$convertedfile."\'/&gt;XML CONVERTED&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;GZIP TAIL:".$tail."&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;&lt;textarea cols=\'30\' rows=\'20\'&gt;" . $raw . "&lt;/textarea&gt;&lt;/td&gt;";\n        echo "&lt;td&gt;&lt;textarea cols=\'30\' rows=\'20\'&gt;" . $decoded . "&lt;/textarea&gt;&lt;/td&gt;";\n        echo "&lt;td&gt;&lt;textarea cols=\'30\' rows=\'20\'&gt;" . $decompressed . "&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;th&gt;Stage 6&lt;/th&gt;";\n        echo "&lt;th&gt;Stage 5&lt;/th&gt;";\n        echo "&lt;th&gt;Stage 4&lt;/th&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;ENCODED DATA &lt;-&lt;/td&gt;&lt;td&gt;COMPRESSED DATA &lt;-&lt;/td&gt;&lt;td&gt;UNCOMPRESSED DATA &lt;-&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;LENGTH: ".strlen($encoded)."&lt;/td&gt;";\n        echo "&lt;td&gt;LENGTH: ".strlen($compressed)."&lt;/td&gt;";\n        echo "&lt;td&gt;LENGTH: ".strlen($decompressed)."&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;GZIP HEADER:".$header2."&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;GZIP TAIL:".$tail2."&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;&lt;a href=\'".$finalfile."\'/&gt;FINAL FILE&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=\'".$compressedfile."\'/&gt;RE-COMPRESSED FILE&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;tr&gt;&lt;td&gt;&lt;textarea cols=\'30\' rows=\'20\'&gt;" . $encoded . "&lt;/textarea&gt;&lt;/td&gt;";\n        echo "&lt;td&gt;&lt;textarea cols=\'30\' rows=\'20\'&gt;" . $compressed . "&lt;/textarea&gt;&lt;/td&gt;";\n        echo "&lt;td&gt;&lt;textarea cols=\'30\' rows=\'20\'&gt;" . $decompressed  . "&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;";\n        echo "&lt;/table&gt;";\n        echo "&lt;/center&gt;";\n    }\n    echo "&lt;/body&gt;&lt;/html&gt;";\n    ?&gt;\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/6811', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/25/']