archive icon indicating copy to clipboard operation
archive copied to clipboard

Broken zip archive produced if a file was added from a string containing non-ascii characters.

Open dropik opened this issue 1 year ago • 4 comments

I've encountered this issue with the plugin, which appears to affect version 3.5 and later. Assume this piece of code:

final archive = Archive();
final text = 'Whatever µ whatever';
final file = ArchiveFile.string('example.txt', text);
archive.addFile(file);
final bytes = ZipEncoder().encode(archive);
final zipFile = File('archive.zip');
await zipFile.writeAsBytes(bytes);

In this case the produced archive is broken and can not be unarchived.

I guess the problem is in the ArchiveFile.string constructor. If I use this instead to define the file within the archive, it works:

final file = ArchiveFile('example.txt', -1, text);

Taking a closer look at both constructors, it appears that ArchiveFile.string does not assume that the size of encoded bytes array is not the same as the string length in case the string contains non-ascii chars:

  ArchiveFile.string(this.name, String content,
      [this._compressionType = STORE]) {
    size = content.length;
    _content = utf8.encode(content);
    _rawContent = InputStream(_content);
  }

While the ArchiveFile constructor on the other hand does such consideration:

  ArchiveFile(this.name, this.size, dynamic content,
      [this._compressionType = STORE]) {
//...
  } else if (content is String) {
      _content = utf8.encode(content);
      _rawContent = InputStream(_content);
      if (size <= 0) {
        size = (_content as Uint8List).length + 1;
      }
    }
//...

So I believe that is the issue, and in that case might be quite easily fixed. If you want I can post a pull request for this.

dropik avatar Sep 11 '24 09:09 dropik

I've run into the same issue. FWIW the bug is fixed in the unpublished version:

https://github.com/brendan-duncan/archive/blob/a7a0c007299efa0fc9663f6170389d578f5c1a71/lib/src/archive/archive_file.dart#L79-L84

denniskaselow avatar Sep 11 '24 19:09 denniskaselow

I see. So I guess we'll just wait for the version 4.0. Btw, would be also really nice to have an option to specify encoding in this constructor.

dropik avatar Sep 12 '24 18:09 dropik

I can look into being able to specify the encoding in the constructor soon. It will still be at least a couple weeks before I can get to doing the 4.0 publish, after I get through this really busy season at work. I'm no expert on character encoding, I just know it's way more complex than it aught to be. If you have any suggestions for the API to specify control character encoding, please let me know.

brendan-duncan avatar Sep 14 '24 18:09 brendan-duncan

I think providing an optional Encoding parameter in the constructor would already cover most use cases. Taking the inspiration from the File interface of the flutter itself, which looks like this for writeAsString method:

Future<File> writeAsString(String contents,
      {FileMode mode = FileMode.write,
      Encoding encoding = utf8,
      bool flush = false});

So that the string constructor of ArchiveFile might become something like

ArchiveFile.string(this.name, String content, {Encoding encoding = utf8})  : mode = 0x1a4 {
// handling specified encoding to obtain raw bytes payload.
}

dropik avatar Sep 21 '24 18:09 dropik