关于unix:如何将xml文件编码为xfdl(base64-gzip)?

关于unix:如何将xml文件编码为xfdl(base64-gzip)?

How can I encode xml files to xfdl (base64-gzip)?

在阅读其他内容之前,请花一些时间阅读原始主题。

概述:.xfdl文件是gzip压缩的.xml文件,然后已将其编码为base64。我希望将.xfdl解编码为xml,然后可以对其进行修改,然后重新编码为.xfdl文件。

xfdl > xml.gz > xml > xml.gz > xfdl

我已经能够获取一个.xfdl文件,并使用uudeview从base64对其进行解码:

1
uudeview -i yourform.xfdl

然后用gunzip解压

1
gunzip -S"" < UNKNOWN.001 > yourform-unpacked.xml

生成的xml具有100%可读性,并且看起来很棒。然后,无需修改xml,我应该能够使用gzip重新压缩它:

1
gzip yourform-unpacked.xml

然后在base-64中重新编码:

1
base64 -e yourform-unpacked.xml.gz yourform_reencoded.xfdl

如果我的想法是正确的,则原始文件和重新编码的文件应该相等。但是,如果我将yourform.xfdl和yourform_reencoded.xfdl放在无法比较的位置,则它们不匹配。另外,可以在http://www.grants.gov/help/download_software.jsp#pureedge">.xfdl查看器中查看原始文件,查看器说重新编码的xfdl不可读。

我也尝试过uuenview在base64中重新编码,它也会产生相同的结果。任何帮助,将不胜感激。


据我所知,您无法找到已压缩文件的压缩级别。压缩文件时,可以使用-#指定压缩级别,其中#为1到9(1是最快的压缩,9是最大的压缩文件)。在实践中,永远不要将压缩文件与已提取并重新压缩的文件进行比较,因为细微的差异很容易出现。在您的情况下,我将比较base64编码版本而不是gzip版本。


我一直在从事类似的工作,这应该适用于php。您必须有一个可写的tmp文件夹,并且php文件名为example.php!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    <?php
    function gzdecode($data) {
        $len = strlen($data);
        if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) {
            echo"FILE NOT GZIP FORMAT";
            return null;  // Not GZIP format (See RFC 1952)
        }
        $method = ord(substr($data,2,1));  // Compression method
        $flags  = ord(substr($data,3,1));  // Flags
        if ($flags & 31 != $flags) {
            // Reserved bits are set -- NOT ALLOWED by RFC 1952
            echo"RESERVED BITS ARE SET. VERY BAD";
            return null;
        }
        // NOTE: $mtime may be negative (PHP integer limitations)
        $mtime = unpack("V", substr($data,4,4));
        $mtime = $mtime[1];
        $xfl   = substr($data,8,1);
        $os    = substr($data,8,1);
        $headerlen = 10;
        $extralen  = 0;
        $extra     ="";
        if ($flags & 4) {
            // 2-byte length prefixed EXTRA data in header
            if ($len - $headerlen - 2 < 8) {
                return false;    // Invalid format
                echo"INVALID FORMAT";
            }
            $extralen = unpack("v",substr($data,8,2));
            $extralen = $extralen[1];
            if ($len - $headerlen - 2 - $extralen < 8) {
                return false;    // Invalid format
                echo"INVALID FORMAT";
            }
            $extra = substr($data,10,$extralen);
            $headerlen += 2 + $extralen;
        }

        $filenamelen = 0;
        $filename ="";
        if ($flags & 8) {
            // C-style string file NAME data in header
            if ($len - $headerlen - 1 < 8) {
                return false;    // Invalid format
                echo"INVALID FORMAT";
            }
            $filenamelen = strpos(substr($data,8+$extralen),chr(0));
            if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
                return false;    // Invalid format
                echo"INVALID FORMAT";
            }
            $filename = substr($data,$headerlen,$filenamelen);
            $headerlen += $filenamelen + 1;
        }

        $commentlen = 0;
        $comment ="";
        if ($flags & 16) {
            // C-style string COMMENT data in header
            if ($len - $headerlen - 1 < 8) {
                return false;    // Invalid format
                echo"INVALID FORMAT";
            }
            $commentlen = strpos(substr($data,8+$extralen+$filenamelen),chr(0));
            if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
                return false;    // Invalid header format
                echo"INVALID FORMAT";
            }
            $comment = substr($data,$headerlen,$commentlen);
            $headerlen += $commentlen + 1;
        }

        $headercrc ="";
        if ($flags & 1) {
            // 2-bytes (lowest order) of CRC32 on header present
            if ($len - $headerlen - 2 < 8) {
                return false;    // Invalid format
                echo"INVALID FORMAT";
            }
            $calccrc = crc32(substr($data,0,$headerlen)) & 0xffff;
            $headercrc = unpack("v", substr($data,$headerlen,2));
            $headercrc = $headercrc[1];
            if ($headercrc != $calccrc) {
                echo"BAD CRC";
                return false;    // Bad header CRC
            }
            $headerlen += 2;
        }

        // GZIP FOOTER - These be negative due to PHP's limitations
        $datacrc = unpack("V",substr($data,-8,4));
        $datacrc = $datacrc[1];
        $isize = unpack("V",substr($data,-4));
        $isize = $isize[1];

        // Perform the decompression:
        $bodylen = $len-$headerlen-8;
        if ($bodylen < 1) {
            // This should never happen - IMPLEMENTATION BUG!
            echo"BIG OOPS";
            return null;
        }
        $body = substr($data,$headerlen,$bodylen);
        $data ="";
        if ($bodylen > 0) {
            switch ($method) {
                case 8:
                    // Currently the only supported compression method:
                    $data = gzinflate($body);
                    break;
                default:
                    // Unknown compression method
                    echo"UNKNOWN COMPRESSION METHOD";
                return false;
            }
        } else {
            // I'm not sure if zero-byte body content is allowed.
            // Allow it for now...  Do nothing...
            echo"ITS EMPTY";
        }

        // Verifiy decompressed size and CRC32:
        // NOTE: This may fail with large data sizes depending on how
        //       PHP's integer limitations affect strlen() since $isize
        //       may be negative for large sizes.
        if ($isize != strlen($data) || crc32($data) != $datacrc) {
            // Bad format!  Length or CRC doesn't match!
            echo"LENGTH OR CRC DO NOT MATCH";
            return false;
        }
        return $data;
    }
    echo"<html><head></head><body>";
    if (empty($_REQUEST['upload'])) {
        echo <<<_END
    <form enctype="multipart/form-data" action="example.php" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="100000" />
    <table>
    <th>
    <input name="uploadedfile" type="file" />
    </th>
    <tr>
    <td><input type="submit" name="upload" value="Convert File" /></td>
    </tr>
    </table>
    </form>
    _END;

    }
    if (!empty($_REQUEST['upload'])) {
        $file           ="tmp/" . $_FILES['uploadedfile']['name'];
        $orgfile        = $_FILES['uploadedfile']['name'];
        $name           = str_replace(".xfdl","", $orgfile);
        $convertedfile  ="tmp/" . $name .".xml";
        $compressedfile ="tmp/" . $name .".gz";
        $finalfile      ="tmp/" . $name ."new.xfdl";
        $target_path    ="tmp/";
        $target_path    = $target_path . basename($_FILES['uploadedfile']['name']);
        if (move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
        } else {
            echo"There was an error uploading the file, please try again!";
        }
        $firstline      ="application/vnd.xfdl; content-encoding="base64-gzip"
";
        $data           = file($file);
        $data           = array_slice($data, 1);
        $raw            = implode($data);
        $decoded        = base64_decode($raw);
        $decompressed   = gzdecode($decoded);
        $compressed     = gzencode($decompressed);
        $encoded        = base64_encode($compressed);
        $decoded2       = base64_decode($encoded);
        $decompressed2  = gzdecode($decoded2);
        $header         = bin2hex(substr($decoded, 0, 10));
        $tail           = bin2hex(substr($decoded, -8));
        $header2        = bin2hex(substr($compressed, 0, 10));
        $tail2          = bin2hex(substr($compressed, -8));
        $header3        = bin2hex(substr($decoded2, 0, 10));
        $tail3          = bin2hex(substr($decoded2, -8));
        $filehandle     = fopen($compressedfile, 'w');
        fwrite($filehandle, $decoded);
        fclose($filehandle);
        $filehandle     = fopen($convertedfile, 'w');
        fwrite($filehandle, $decompressed);
        fclose($filehandle);
        $filehandle     = fopen($finalfile, 'w');
        fwrite($filehandle, $firstline);
        fwrite($filehandle, $encoded);
        fclose($filehandle);
        echo"<center>";
        echo"<table style='text-align:center' >";
        echo"<tr><th>Stage 1</th>";
        echo"<th>Stage 2</th>";
        echo"<th>Stage 3</th></tr>";
        echo"<tr><td>RAW DATA -></td><td>DECODED DATA -></td><td>UNCOMPRESSED DATA -></td></tr>";
        echo"<tr><td>LENGTH:".strlen($raw)."</td>";
        echo"<td>LENGTH:".strlen($decoded)."</td>";
        echo"<td>LENGTH:".strlen($decompressed)."</td></tr>";
        echo"<tr><td>ORIGINAL</td><td>GZIP HEADER:".$header."</td><td>XML CONVERTED</td></tr>";
        echo"<tr><td></td><td>GZIP TAIL:".$tail."</td><td></td></tr>";
        echo"<tr><td><textarea cols='30' rows='20'>" . $raw ."</textarea></td>";
        echo"<td><textarea cols='30' rows='20'>" . $decoded ."</textarea></td>";
        echo"<td><textarea cols='30' rows='20'>" . $decompressed ."</textarea></td></tr>";
        echo"<tr><th>Stage 6</th>";
        echo"<th>Stage 5</th>";
        echo"<th>Stage 4</th></tr>";
        echo"<tr><td>ENCODED DATA <-</td><td>COMPRESSED DATA <-</td><td>UNCOMPRESSED DATA <-</td></tr>";
        echo"<tr><td>LENGTH:".strlen($encoded)."</td>";
        echo"<td>LENGTH:".strlen($compressed)."</td>";
        echo"<td>LENGTH:".strlen($decompressed)."</td></tr>";
        echo"<tr><td></td><td>GZIP HEADER:".$header2."</td><td></td></tr>";
        echo"<tr><td></td><td>GZIP TAIL:".$tail2."</td><td></td></tr>";
        echo"<tr><td>FINAL FILE</td><td>RE-COMPRESSED FILE</td><td></td></tr>";
        echo"<tr><td><textarea cols='30' rows='20'>" . $encoded ."</textarea></td>";
        echo"<td><textarea cols='30' rows='20'>" . $compressed ."</textarea></td>";
        echo"<td><textarea cols='30' rows='20'>" . $decompressed  ."</textarea></td></tr>";
        echo"</table>";
        echo"</center>";
    }
    echo"</body></html>";
    ?>


我在Java中借助http://iharder.net/base64中的Base64类进行了此操作。

我一直在研究在Java中进行表单操作的应用程序。我解码文件,从XML创建DOM文档,然后将其写回到文件中。

我用Java读取文件的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public XFDLDocument(String inputFile)
        throws IOException,
            ParserConfigurationException,
            SAXException

{
    fileLocation = inputFile;

    try{

        //create file object
        File f = new File(inputFile);
        if(!f.exists()) {
            throw new IOException("Specified File could not be found!");
        }

        //open file stream from file
        FileInputStream fis = new FileInputStream(inputFile);

        //Skip past the MIME header
        fis.skip(FILE_HEADER_BLOCK.length());  

        //Decompress from base 64                  
        Base64.InputStream bis = new Base64.InputStream(fis,
                Base64.DECODE);

        //UnZIP the resulting stream
        GZIPInputStream gis = new GZIPInputStream(bis);

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        doc = db.parse(gis);

        gis.close();
        bis.close();
        fis.close();

    }
    catch (ParserConfigurationException pce) {
        throw new ParserConfigurationException("Error parsing XFDL from file.");
    }
    catch (SAXException saxe) {
        throw new SAXException("Error parsing XFDL into XML Document.");
    }
}

我在Java中的代码如下所示,将文件写入磁盘:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    /**
     * Saves the current document to the specified location
     * @param destination Desired destination for the file.
     * @param asXML True if output needs should be as un-encoded XML not Base64/GZIP
     * @throws IOException File cannot be created at specified location
     * @throws TransformerConfigurationExample
     * @throws TransformerException
     */
    public void saveFile(String destination, boolean asXML)
        throws IOException,
            TransformerConfigurationException,
            TransformerException  
        {

        BufferedWriter bf = new BufferedWriter(new FileWriter(destination));
        bf.write(FILE_HEADER_BLOCK);
        bf.newLine();
        bf.flush();
        bf.close();

        OutputStream outStream;
        if(!asXML) {
            outStream = new GZIPOutputStream(
                new Base64.OutputStream(
                        new FileOutputStream(destination, true)));
        } else {
            outStream = new FileOutputStream(destination, true);
        }

        Transformer t = TransformerFactory.newInstance().newTransformer();
        t.transform(new DOMSource(doc), new StreamResult(outStream));

        outStream.flush();
        outStream.close();      
    }

希望能有所帮助。


检查这些:

asc-gzip/.xfd compression

asc-gzip/.xfd decompression

它们使用的是Python,而不是Ruby,但这应该可以使您更加接近。

该算法实际上是针对标头为" application / x-xfdl; content-encoding =" asc-gzip""的文件,而不是针对" application / vnd.xfdl;"的文件。 content-encoding =" base64-gzip"'
但是好消息是PureEdge(又名IBM Lotus Forms)将毫无问题地打开该格式。

然后最重要的是,这是一个base64-gzip解码(在Python中),因此您可以进行完整的往返:

1
2
3
4
5
6
7
8
with open(filename, 'r') as f:
  header = f.readline()
  if header == 'application/vnd.xfdl; content-encoding="base64-gzip"
':
    decoded = b''
    for line in f:
      decoded += base64.b64decode(line.encode("ISO-8859-1"))
    xml = zlib.decompress(decoded, zlib.MAX_WBITS + 16)

您需要将以下行放在XFDL文件的开头:

application/vnd.xfdl; content-encoding="base64-gzip"

生成base64编码的文件后,在文本编辑器中将其打开,并将上面的行粘贴到第一行。确保base64'ed块从第二行的开头开始。

保存并在查看器中尝试!如果仍然不起作用,则可能是由于对XML所做的更改使它在某种程度上不符合标准。在这种情况下,在修改完XML之后,但在将其压缩并进行base64编码之前,请使用.xfdl文件扩展名保存它,然后尝试使用查看器工具将其打开。如果查看器采用有效的XFDL格式,则它应该能够解析和显示未压缩/未编码的文件。


gzip会将文件名放在文件的标题中,以便压缩文件的长度根据未压缩文件的文件名而有所不同。

如果gzip在流上起作用,则文件名将被省略,并且文件会短一些,因此应该可以使用以下命令:

gzip yourform-unpacked.xml.gz

然后在base-64中重新编码:
base64 -e yourform-unpacked.xml.gz yourform_reencoded.xfdl

也许这会产生相同长度的文件


有趣的是,我会试一试。但是变化并不大。新编码的文件更长,并且在比较前后的二进制文件时,数据几乎不匹配。

前(前三行)

1
2
3
H4sIAAAAAAAAC+19eZOiyNb3/34K3r4RT/WEU40ssvTtrhuIuKK44Bo3YoJdFAFZ3D79C6hVVhUq
dsnUVN/qmIkSOLlwlt/JPCfJ/PGf9dwAlorj6pb58wv0LfcFUEzJknVT+/ml2uXuCSJP3kNf/vOQ
+TEsFVkgoDfdn18mnmd/B8HVavWt5TsKI2vKN8magyENiH3Lf9kRfpd817PmF+jpiOhQRFZcXTMV

之后(前三行):

1
2
3
H4sICJ/YnEgAAzEyNDQ2LTExNjk2NzUueGZkbC54bWwA7D1pU+JK19/9FV2+H5wpByEhJMRH
uRUgCMom4DBYt2oqkAZyDQlmQZ1f/3YSNqGzKT3oDH6RdE4vOXuf08vFP88TFcygYSq6dnlM
naWOAdQGuqxoo8vjSruRyGYzfII6/id3dPGjVKwCBK+Zl8djy5qeJ5NPT09nTduAojyCZwN9

如您所见,H4SI匹配,然后是pandemonium。


gzip算法的不同实现将始终生成略有不同但仍正确的文件,并且原始文件的压缩级别可能会与运行该文件时的压缩级别有所不同。


推荐阅读