flutter_minizip_ffi_bindings 0.3.0 copy "flutter_minizip_ffi_bindings: ^0.3.0" to clipboard
flutter_minizip_ffi_bindings: ^0.3.0 copied to clipboard

FFI bindings for [zlib-ng/minizip-ng](https://github.com/zlib-ng/minizip-ng) made using [dart-lang/ffigen](https://github.com/dart-lang/ffigen) and trivial trick.

example/lib/main.dart

import 'dart:convert';
import 'dart:ffi' as ffi;
import 'dart:io';

import 'package:ffi/ffi.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter_minizip_ffi_bindings/flutter_minizip_ffi_bindings.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';

const _sampleDataName = 'minizip-ng-master.zip';

Future<void> _copySampleData() async {
  final sampleData = await rootBundle.load('assets/$_sampleDataName');
  final filesDir = await getApplicationSupportDirectory();
  final dstPath = p.join(filesDir.path, _sampleDataName);
  final dst = File(dstPath);
  await dst.writeAsBytes(sampleData.buffer.asUint8List());
}

final _minizip = () {
  final lib = Platform.isIOS
      ? ffi.DynamicLibrary.process()
      : ffi.DynamicLibrary.open('libminizip.so');
  return Minizip(lib);
}();

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await _copySampleData();
  runApp(const _App());
}

@immutable
class _App extends StatelessWidget {
  const _App({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('flutter_minizip_ffi_bindings_example'),
        ),
        body: const _Body(),
      ),
    );
  }
}

@immutable
class _Body extends StatefulWidget {
  const _Body({
    Key? key,
  }) : super(key: key);

  @override
  _BodyState createState() => _BodyState();
}

class _BodyState extends State<_Body> {
  List<String>? _paths;

  Future<void> _listFilesInZip() async {
    final filesDir = await getApplicationSupportDirectory();
    final path = p.join(filesDir.path, _sampleDataName);

    final handle = calloc<ffi.Pointer<ffi.Void>>();
    _minizip.mz_zip_reader_create(handle);
    _minizip.mz_zip_reader_open_file(handle.value, path.toNativeUtf8().cast());

    final paths = <String>[];
    _minizip.mz_zip_reader_goto_first_entry(handle.value);
    do {
      if (_minizip.mz_zip_reader_entry_is_dir(handle.value) == MZ_OK) {
        continue;
      }

      final info = calloc<ffi.Pointer<mz_zip_file_s>>();
      _minizip.mz_zip_reader_entry_get_info(handle.value, info);
      paths.add(info.value.ref.filename.cast<Utf8>().toDartString());
    } while (_minizip.mz_zip_reader_goto_next_entry(handle.value) == MZ_OK);

    _minizip.mz_zip_reader_close(handle.value);
    _minizip.mz_zip_reader_delete(handle);

    setState(() => _paths = paths);
  }

  @override
  void initState() {
    super.initState();
    _listFilesInZip();
  }

  @override
  Widget build(BuildContext context) {
    final _paths = this._paths;
    if (_paths == null) {
      return const Center(
        child: CircularProgressIndicator(),
      );
    }

    return Scrollbar(
      child: ListView.builder(
        itemCount: _paths.length,
        itemBuilder: (context, index) {
          return _ListTile(path: _paths[index]);
        },
      ),
    );
  }
}

@immutable
class _ListTile extends StatelessWidget {
  const _ListTile({
    required this.path,
    Key? key,
  }) : super(key: key);

  final String path;

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(
        border: Border(
          bottom: BorderSide(
            color: Theme.of(context).dividerColor,
          ),
        ),
      ),
      child: ListTile(
        title: Text(path),
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) {
                return _Detail(path: path);
              },
            ),
          );
        },
      ),
    );
  }
}

@immutable
class _Detail extends StatelessWidget {
  const _Detail({
    required this.path,
    Key? key,
  }) : super(key: key);

  final String path;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(path),
      ),
      body: _Content(path: path),
    );
  }
}

@immutable
class _Content extends StatelessWidget {
  const _Content({
    required this.path,
    Key? key,
  }) : super(key: key);

  final String path;

  Future<List<String>> _readFileInZip(String filePath) async {
    final filesDir = await getApplicationSupportDirectory();
    final path = p.join(filesDir.path, _sampleDataName);

    final handle = calloc<ffi.Pointer<ffi.Void>>();
    _minizip.mz_zip_reader_create(handle);
    _minizip.mz_zip_reader_open_file(handle.value, path.toNativeUtf8().cast());

    _minizip.mz_zip_reader_locate_entry(
      handle.value,
      filePath.toNativeUtf8().cast(),
      0,
    );

    final info = calloc<ffi.Pointer<mz_zip_file_s>>();
    _minizip.mz_zip_reader_entry_get_info(handle.value, info);

    final len = info.value.ref.uncompressed_size;
    final buf = calloc<ffi.Uint8>(len);

    _minizip.mz_zip_reader_entry_open(handle.value);
    _minizip.mz_zip_reader_entry_read(handle.value, buf.cast(), len);

    final bytes = List<int>.from(buf.asTypedList(len));

    _minizip.mz_zip_reader_entry_close(handle.value);
    _minizip.mz_zip_reader_close(handle.value);
    _minizip.mz_zip_reader_delete(handle);

    final lines = () {
      try {
        return const Utf8Decoder().convert(bytes);
      } catch (e) {
        return 'Error: Invalid UTF-8 Strings';
      }
    }();

    return const LineSplitter().convert(lines);
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<String>>(
      future: _readFileInZip(path),
      builder: (context, snapshot) {
        final lines = snapshot.data;
        if (snapshot.connectionState != ConnectionState.done || lines == null) {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }

        return Scrollbar(
          child: SafeArea(
            child: ListView.builder(
              padding: const EdgeInsets.all(8),
              itemCount: lines.length,
              itemBuilder: (context, index) {
                return Text(lines[index]);
              },
            ),
          ),
        );
      },
    );
  }
}
3
likes
110
pub points
0%
popularity

Publisher

unverified uploader

FFI bindings for [zlib-ng/minizip-ng](https://github.com/zlib-ng/minizip-ng) made using [dart-lang/ffigen](https://github.com/dart-lang/ffigen) and trivial trick.

Repository (GitLab)
View/report issues

Documentation

API reference

License

BSD-3-Clause (LICENSE)

Dependencies

ffi, flutter

More

Packages that depend on flutter_minizip_ffi_bindings