blob: 4995655e55c6be667114bb577d60091c68c67a6e [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::Result;
use cxx::{CxxString, CxxVector};
use std::io::{Cursor, Read};
use std::pin::Pin;
#[cxx::bridge(namespace = "rust_zip")]
mod ffi {
#[derive(Debug)]
#[repr(i32)]
enum UnzipResult {
Success = 0,
ErrorOpenArchive = 1,
ErrorReadFile = 2,
}
struct RustFileData {
data: Vec<u8>,
}
extern "Rust" {
fn unzip_archive_in_memory(
zip_archive_bytes: &[u8],
out_file_contents: Pin<&mut CxxVector<RustFileData>>,
out_error_string: Pin<&mut CxxString>,
) -> UnzipResult;
}
}
fn unzip_worker(zip_archive_bytes: &[u8]) -> Result<Vec<ffi::RustFileData>> {
let mut archive = zip::ZipArchive::new(Cursor::new(zip_archive_bytes))?;
let mut all_files = Vec::new();
for i in 0..archive.len() {
let mut file_in_zip = match archive.by_index(i) {
Ok(f) => f,
Err(_) => {
continue;
}
};
if file_in_zip.is_dir() {
continue;
}
let mut file_bytes = Vec::new();
file_in_zip.read_to_end(&mut file_bytes)?;
all_files.push(ffi::RustFileData { data: file_bytes });
}
Ok(all_files)
}
pub fn unzip_archive_in_memory(
zip_archive_bytes: &[u8],
mut out_file_contents: Pin<&mut CxxVector<ffi::RustFileData>>,
mut out_error_string: Pin<&mut CxxString>,
) -> ffi::UnzipResult {
out_error_string.as_mut().clear();
match unzip_worker(zip_archive_bytes) {
Ok(files) => {
for file_data in files {
out_file_contents.as_mut().push(file_data);
}
ffi::UnzipResult::Success
}
Err(e) => {
out_error_string.as_mut().push_str(&e.to_string());
ffi::UnzipResult::ErrorOpenArchive
}
}
}