mirror of
https://gitee.com/Vancouver2017/luban-lite.git
synced 2025-12-29 01:06:56 +00:00
v1.2.2
This commit is contained in:
15
packages/artinchip/zipfs/Kconfig
Normal file
15
packages/artinchip/zipfs/Kconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
# Kconfig file for package zipfs
|
||||
menuconfig LPKG_USING_ZIPFS
|
||||
bool "zipfs: A file system for zip file"
|
||||
select LPKG_USING_MINIZ
|
||||
default n
|
||||
depends on PRJ_KERNEL="rt-thread"
|
||||
|
||||
if LPKG_USING_ZIPFS
|
||||
|
||||
config LPKG_ZIPFS_DEMO
|
||||
bool "Enable zipfs demo"
|
||||
default n
|
||||
|
||||
endif
|
||||
48
packages/artinchip/zipfs/README.md
Normal file
48
packages/artinchip/zipfs/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# ZIP File System Library
|
||||
|
||||
## Overview
|
||||
|
||||
This library provides two approaches to handle ZIP files:
|
||||
|
||||
1. **ZIP File System**: Mount ZIP files or the block device where the ZIP data in as virtual file systems
|
||||
2. **ZIP File Reader**: Directly read ZIP file contents
|
||||
|
||||
## ZIP File System
|
||||
|
||||
### API Functions
|
||||
```c
|
||||
int zipfs_mount(const char *zip_path, const char *mount_point);
|
||||
int zipfs_unmount(const char *mount_point);
|
||||
```
|
||||
|
||||
### Important Notes
|
||||
- Not thread-safe, requires external locking in multi-threaded environments
|
||||
- Mount point must be an empty directory
|
||||
- Read-only access
|
||||
|
||||
## ZIP File Reader
|
||||
|
||||
### API Functions
|
||||
```c
|
||||
struct aic_zip_reader *aic_zip_reader_open(const char *source);
|
||||
int aic_zip_reader_read(struct aic_zip_reader *reader,
|
||||
struct aic_file_info file_info,
|
||||
void *buffer);
|
||||
void aic_zip_reader_close(struct aic_zip_reader *reader);
|
||||
```
|
||||
|
||||
### Important Notes
|
||||
- After opening a ZIP reader, you must manually call aic_zip_reader_close to close it
|
||||
- You can adjust the read buffer size by modifying the READ_BUF_SIZE macro in zip_reader.h
|
||||
- Large files are automatically streamed internally, but note that the provided buffer must be greater than or equal to the file size
|
||||
- Encrypted ZIP and ZIP64 formats are not supported
|
||||
|
||||
## Demo Programs
|
||||
|
||||
The project includes two demonstration programs:
|
||||
- `zip_fs_demo.c`: ZIP file system usage example
|
||||
- `zip_reader_demo.c`: ZIP file reader usage example
|
||||
|
||||
## Dependencies
|
||||
|
||||
- RT-Thread: Real-time operating system
|
||||
48
packages/artinchip/zipfs/README_CN.md
Normal file
48
packages/artinchip/zipfs/README_CN.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# ZIP文件系统库
|
||||
|
||||
## 功能概述
|
||||
|
||||
本库提供两种处理ZIP文件的方式:
|
||||
|
||||
1. **ZIP文件系统**:将ZIP文件或包含zip文件的块设备挂载为虚拟文件系统
|
||||
2. **ZIP文件读取器**:直接读取ZIP文件内容
|
||||
|
||||
## ZIP文件系统
|
||||
|
||||
### 接口函数
|
||||
```c
|
||||
int zipfs_mount(const char *zip_path, const char *mount_point);
|
||||
int zipfs_unmount(const char *mount_point);
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
- 非线程安全,多线程环境需要外部加锁
|
||||
- 挂载点必须是空的目录
|
||||
- 只读访问
|
||||
|
||||
## ZIP文件读取器
|
||||
|
||||
### 接口函数
|
||||
```c
|
||||
struct aic_zip_reader *aic_zip_reader_open(const char *source);
|
||||
int aic_zip_reader_read(struct aic_zip_reader *reader,
|
||||
struct aic_file_info file_info,
|
||||
void *buffer);
|
||||
void aic_zip_reader_close(struct aic_zip_reader *reader);
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
- 在打开ZIP读取器后,必须手动调用aic_zip_reader_close关闭读取器
|
||||
- 可以在zip_reader.h中通过修改宏READ_BUF_SIZE调整读取缓冲区大小
|
||||
- 读取大文件时内部会自动流式,但是要注意提供的buffer要大于或等于文件大小
|
||||
- 不支持加密ZIP和ZIP64格式
|
||||
|
||||
## 示例程序
|
||||
|
||||
项目包含两个演示程序:
|
||||
- `zip_fs_demo.c`: ZIP文件系统使用示例
|
||||
- `zip_reader_demo.c`: ZIP文件读取器使用示例
|
||||
|
||||
## 依赖
|
||||
|
||||
- RT-Thread: 实时操作系统
|
||||
24
packages/artinchip/zipfs/SConscript
Normal file
24
packages/artinchip/zipfs/SConscript
Normal file
@@ -0,0 +1,24 @@
|
||||
from building import *
|
||||
Import('rtconfig')
|
||||
|
||||
src = []
|
||||
cwd = GetCurrentDir()
|
||||
install = []
|
||||
|
||||
if GetDepend('LPKG_USING_ZIPFS'):
|
||||
src += Glob('src/*.c')
|
||||
if GetDepend('LPKG_ZIPFS_DEMO'):
|
||||
src += Glob('zip_reader_demo.c')
|
||||
src += Glob('zip_fs_demo.c')
|
||||
ins_dst = 'rodata/zipfs_test'
|
||||
ins_src = 'test_zip_files/'
|
||||
install = [(ins_src, ins_dst)]
|
||||
|
||||
# add include path.
|
||||
path = [cwd + '/inc']
|
||||
|
||||
# add src and include to group.
|
||||
group = DefineGroup('zipfs', src, depend = ['LPKG_USING_ZIPFS'], CPPPATH = path,
|
||||
INSTALL = install)
|
||||
|
||||
Return('group')
|
||||
40
packages/artinchip/zipfs/inc/zip_fs.h
Normal file
40
packages/artinchip/zipfs/inc/zip_fs.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2025, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Cui Jiawei <jiawei.cui@artinchip.com>
|
||||
*/
|
||||
|
||||
#ifndef __ZIPFS_H_
|
||||
#define __ZIPFS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define FS_NAME "zipfs"
|
||||
|
||||
/**
|
||||
* @brief Mount a specified ZIP archive as a virtual filesystem at the target path.
|
||||
* Creates an in-memory read-only view under `mount_point`, where subsequent
|
||||
* POSIX filesystem operations will transparently access files within the ZIP.
|
||||
*
|
||||
* @param source Full path to ZIP file in RAMDisk, or block name where ZIP data in
|
||||
* example: "/rodata/zipfs_test/much_file.zip", "blk_rodata_r"
|
||||
* @param mount_point Target mount location in the system (e.g., "/zipfs"). Must be an
|
||||
* empty directory not currently mounted by other filesystems.
|
||||
*
|
||||
* @return Returns 0 on success; returns -1 on failure.
|
||||
*/
|
||||
int zipfs_mount(const char *source, const char *mount_point);
|
||||
|
||||
/**
|
||||
* @brief Unmount a previously mounted ZIP filesystem, immediately releasing all resources
|
||||
* associated with the specified mount point.
|
||||
*
|
||||
* @param mount_point The mount point of the ZIP filesystem to unmount.
|
||||
*
|
||||
* @return Returns 0 on success; returns -1 on failure.
|
||||
*/
|
||||
int zipfs_unmount(const char *mount_point);
|
||||
|
||||
#endif // __ZIPFS_H_
|
||||
59
packages/artinchip/zipfs/inc/zip_reader.h
Normal file
59
packages/artinchip/zipfs/inc/zip_reader.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2025, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Cui Jiawei <jiawei.cui@artinchip.com>
|
||||
*/
|
||||
|
||||
#ifndef __ZIP_READER_H_
|
||||
#define __ZIP_READER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include "miniz.h"
|
||||
#include "miniz_zip.h"
|
||||
|
||||
#define READ_BUF_SIZE 4096
|
||||
|
||||
struct aic_file_info {
|
||||
char *name;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct aic_zip_reader {
|
||||
void *zip_buffer; /* Memory buffer containing ZIP file */
|
||||
size_t zip_size; /* Size of ZIP file in bytes */
|
||||
mz_zip_archive archive; /* miniz ZIP archive structure */
|
||||
uint32_t file_count; /* Number of files (including directories) in the ZIP archive */
|
||||
struct aic_file_info *file_info; /* Array of structures containing file information */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Open a ZIP file from RAMDisk
|
||||
*
|
||||
* @param source Full path to ZIP file in RAMDisk, or block name where ZIP data in
|
||||
* example: "/rodata/zipfs_test/much_file.zip", "blk_rodata_r"
|
||||
*
|
||||
* @return aic_zip_reader* Pointer to ZIP reader instance, NULL on failure
|
||||
*/
|
||||
struct aic_zip_reader *aic_zip_reader_open(const char *source);
|
||||
|
||||
/**
|
||||
* @brief Close ZIP reader and release all resources
|
||||
*
|
||||
* @param reader ZIP reader pointer
|
||||
*/
|
||||
void aic_zip_reader_close(struct aic_zip_reader *reader);
|
||||
|
||||
/**
|
||||
* @brief Extract file content directly into provided buffer
|
||||
*
|
||||
* @param reader ZIP reader pointer
|
||||
* @param file_info Struct representing the information of files to be read.
|
||||
* @param buffer Destination buffer, Set the buffer size based on the size field of aic_file_info.
|
||||
* @return int Number 0 on success, -1 on failure
|
||||
*/
|
||||
int aic_zip_reader_read(struct aic_zip_reader *reader, struct aic_file_info file_info,
|
||||
void *buffer);
|
||||
|
||||
#endif // __ZIP_READER_H_
|
||||
265
packages/artinchip/zipfs/src/zip_fs.c
Normal file
265
packages/artinchip/zipfs/src/zip_fs.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (c) 2025, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Cui Jiawei <jiawei.cui@artinchip.com>
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs_posix.h>
|
||||
#include <aic_errno.h>
|
||||
#include "zip_reader.h"
|
||||
#include "stdbool.h"
|
||||
#include "zip_fs.h"
|
||||
|
||||
static const struct dfs_file_ops zipfs_fops;
|
||||
|
||||
static int zipfs_ops_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data)
|
||||
{
|
||||
fs->data = (void *)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zipfs_ops_unmount(struct dfs_filesystem *fs)
|
||||
{
|
||||
struct aic_zip_reader *reader = (struct aic_zip_reader *)fs->data;
|
||||
aic_zip_reader_close(reader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zipfs_ops_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
|
||||
{
|
||||
struct aic_zip_reader *reader = (struct aic_zip_reader *)fs->data;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < reader->file_count; i++) {
|
||||
size_t file_size = reader->file_info[i].size;
|
||||
char *file_name = reader->file_info[i].name;
|
||||
int j = 0;
|
||||
|
||||
for (j = 0; j < strlen(path) && path[j] == file_name[j]; j++) {
|
||||
}
|
||||
|
||||
if (j == strlen(path)) {
|
||||
if (file_name[j] == '/') {
|
||||
st->st_mode = S_IFDIR;
|
||||
st->st_size = 0;
|
||||
} else if (file_name[j] == '\0') {
|
||||
st->st_mode = S_IFREG;
|
||||
st->st_size = file_size;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static const struct dfs_filesystem_ops zipfs_ops = {
|
||||
FS_NAME,
|
||||
DFS_FS_FLAG_DEFAULT,
|
||||
&zipfs_fops,
|
||||
zipfs_ops_mount, /* mount */
|
||||
zipfs_ops_unmount, /* unmount */
|
||||
NULL, /* mkfs */
|
||||
NULL, /* statfs */
|
||||
NULL, /* unlink */
|
||||
zipfs_ops_stat, /* stat */
|
||||
NULL, /* rename */
|
||||
};
|
||||
|
||||
static int zipfs_fopen(struct dfs_fd *fd)
|
||||
{
|
||||
struct aic_zip_reader *reader = (struct aic_zip_reader *)fd->fs->data;
|
||||
int i = 0;
|
||||
|
||||
if ((fd->flags & O_ACCMODE) != O_RDONLY)
|
||||
return -EINVAL;
|
||||
|
||||
if (strcmp(fd->path, "/") == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < reader->file_count; i++) {
|
||||
char *file_name = reader->file_info[i].name;
|
||||
int j = 0;
|
||||
|
||||
for (j = 0; j < strlen(fd->path) && fd->path[j] == file_name[j]; j++) {
|
||||
}
|
||||
|
||||
if (j == strlen(fd->path)) {
|
||||
if (file_name[j] == '/' && fd->flags == O_DIRECTORY) {
|
||||
return 0;
|
||||
} else if (file_name[j] == '\0' && fd->flags != O_DIRECTORY) {
|
||||
fd->size = reader->file_info[i].size;
|
||||
fd->data = mz_zip_reader_extract_file_iter_new(&reader->archive, file_name + 1, 0);
|
||||
return 0;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int zipfs_fread(struct dfs_fd *fd, void *buf, size_t count)
|
||||
{
|
||||
struct aic_zip_reader *reader = (struct aic_zip_reader *)fd->fs->data;
|
||||
rt_size_t length;
|
||||
size_t read_size = 0;
|
||||
|
||||
length = count > (fd->size - fd->pos) ? (fd->size - fd->pos) : count;
|
||||
|
||||
if (length > 0) {
|
||||
for (int i = 0; i < reader->file_count; i++) {
|
||||
char *file_name = reader->file_info[i].name;
|
||||
if (!strcmp(fd->path, file_name)) {
|
||||
mz_zip_reader_extract_iter_state *iter =
|
||||
(mz_zip_reader_extract_iter_state *)fd->data;
|
||||
|
||||
read_size = mz_zip_reader_extract_iter_read(iter, buf, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fd->pos += read_size;
|
||||
|
||||
return read_size;
|
||||
}
|
||||
|
||||
static int zipfs_fclose(struct dfs_fd *fd)
|
||||
{
|
||||
if (fd->data != NULL) {
|
||||
mz_zip_reader_extract_iter_free(fd->data);
|
||||
fd->data = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zipfs_lseek(struct dfs_fd *fd, off_t offset)
|
||||
{
|
||||
mz_zip_reader_extract_iter_state *iter = NULL;
|
||||
uint8_t *temp_buf = NULL;
|
||||
|
||||
if (offset < 0 || offset > fd->size)
|
||||
return -EINVAL;
|
||||
|
||||
if (offset == fd->pos)
|
||||
return offset;
|
||||
if (offset < fd->pos) {
|
||||
struct aic_zip_reader *reader = (struct aic_zip_reader *)fd->fs->data;
|
||||
iter = (mz_zip_reader_extract_iter_state *)fd->data;
|
||||
uint32_t file_index = iter->file_stat.m_file_index;
|
||||
|
||||
mz_zip_reader_extract_iter_free(iter);
|
||||
fd->data = mz_zip_reader_extract_iter_new(&reader->archive, file_index, 0);
|
||||
fd->pos = 0;
|
||||
}
|
||||
|
||||
temp_buf = malloc(offset);
|
||||
iter = (mz_zip_reader_extract_iter_state *)fd->data;
|
||||
mz_zip_reader_extract_iter_read(iter, temp_buf, offset);
|
||||
free(temp_buf);
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int zipfs_getdents(struct dfs_fd *fd, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
struct aic_zip_reader *reader = (struct aic_zip_reader *)fd->fs->data;
|
||||
const char *path = fd->path;
|
||||
int index = 0;
|
||||
uint32_t i = 0;
|
||||
uint32_t entries_processed = fd->pos;
|
||||
|
||||
const uint32_t max_entries = count / sizeof(struct dirent);
|
||||
if (max_entries == 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = entries_processed; i < reader->file_count && index < max_entries; i++) {
|
||||
const char *file_name = reader->file_info[i].name;
|
||||
uint32_t l = 0, r = 0;
|
||||
for (l = 0; l < strlen(path) && path[l] == file_name[l]; l++) {
|
||||
}
|
||||
|
||||
if (l == 1)
|
||||
l = 0;
|
||||
else if (l == 0 || (file_name[l] != '\0' && file_name[l] != '/'))
|
||||
continue;
|
||||
|
||||
for (r = l + 1; r < strlen(file_name) && file_name[r] != '\0' && file_name[r] != '/'; r++) {
|
||||
}
|
||||
|
||||
if (r == (l + 1))
|
||||
continue;
|
||||
|
||||
bool duplicate = false;
|
||||
for (int k = 0; k < entries_processed; k++) {
|
||||
if (strncmp(dirp[k].d_name, file_name + l + 1, r - l - 1) == 0) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate)
|
||||
continue;
|
||||
|
||||
dirp[index].d_type = (file_name[r] == '/') ? DT_DIR : DT_REG;
|
||||
dirp[index].d_namlen = r - l;
|
||||
dirp[index].d_reclen = (uint16_t)sizeof(struct dirent);
|
||||
strncpy(dirp[index].d_name, file_name + l + 1, r - l - 1);
|
||||
dirp[index].d_name[r - l] = '\0';
|
||||
index++;
|
||||
}
|
||||
|
||||
fd->pos = i;
|
||||
return index * sizeof(struct dirent);
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops zipfs_fops = {
|
||||
zipfs_fopen, /* open */
|
||||
zipfs_fclose, /* close */
|
||||
NULL, /* ioctl */
|
||||
zipfs_fread, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* flush */
|
||||
zipfs_lseek, /* lseek */
|
||||
zipfs_getdents, /* getdents */
|
||||
NULL, /* poll */
|
||||
};
|
||||
|
||||
int zipfs_register()
|
||||
{
|
||||
if (dfs_register(&zipfs_ops) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zipfs_mount(const char *source, const char *mount_point)
|
||||
{
|
||||
struct aic_zip_reader *reader = aic_zip_reader_open(source);
|
||||
if (reader == NULL)
|
||||
return -1;
|
||||
|
||||
if (dfs_mount(RT_NULL, mount_point, FS_NAME, 0, reader) != 0) {
|
||||
aic_zip_reader_close(reader);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("ZIP mounted at %s\n", mount_point);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zipfs_unmount(const char *mount_point)
|
||||
{
|
||||
if (dfs_unmount(mount_point) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
INIT_COMPONENT_EXPORT(zipfs_register);
|
||||
256
packages/artinchip/zipfs/src/zip_reader.c
Normal file
256
packages/artinchip/zipfs/src/zip_reader.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2025, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Cui Jiawei <jiawei.cui@artinchip.com>
|
||||
*/
|
||||
|
||||
#include "zip_reader.h"
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <dfs_posix.h>
|
||||
#include <aic_utils.h>
|
||||
#include <aic_core.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ZIP_FILE_HEADER 0x04034B50
|
||||
#define ZIP_FILE_EOCD_SIGN 0x06054B50
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct zip_eocd {
|
||||
rt_uint32_t signature;
|
||||
rt_uint16_t disk_number;
|
||||
rt_uint16_t cd_disk;
|
||||
rt_uint16_t cd_records;
|
||||
rt_uint16_t total_cd_records;
|
||||
rt_uint32_t cd_size;
|
||||
rt_uint32_t cd_offset;
|
||||
rt_uint16_t comment_len;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static size_t get_zip_size_from_blk(const char *blk_name)
|
||||
{
|
||||
rt_device_t flash_dev;
|
||||
struct rt_device_blk_geometry flash_geo;
|
||||
struct zip_eocd *eocd = NULL;
|
||||
size_t len = 0, i;
|
||||
uint32_t blk_count = 0;
|
||||
uint8_t *blk_data = NULL;
|
||||
|
||||
flash_dev = rt_device_find(blk_name);
|
||||
if (!flash_dev)
|
||||
return 0;
|
||||
|
||||
if (rt_device_open(flash_dev, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
|
||||
return 0;
|
||||
|
||||
rt_device_control(flash_dev, RT_DEVICE_CTRL_BLK_GETGEOME, &flash_geo);
|
||||
|
||||
blk_data = (uint8_t *)malloc(flash_geo.block_size);
|
||||
|
||||
rt_device_read(flash_dev, 0, blk_data, 1);
|
||||
hexdump(blk_data, flash_geo.block_size, 16);
|
||||
|
||||
if (*(uint32_t *)blk_data != ZIP_FILE_HEADER) {
|
||||
rt_kprintf("head:%d\n", *(uint32_t *)blk_data);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 4; i < flash_geo.block_size - sizeof(struct zip_eocd); i++) {
|
||||
eocd = (struct zip_eocd *)(blk_data + i);
|
||||
if (eocd->signature == ZIP_FILE_EOCD_SIGN) {
|
||||
len = i + sizeof(struct zip_eocd) + eocd->comment_len;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
blk_count = flash_geo.bytes_per_sector * flash_geo.sector_count / flash_geo.block_size;
|
||||
|
||||
for (i = 1; i < blk_count; i++) {
|
||||
rt_device_read(flash_dev, i, blk_data, 1);
|
||||
for (int j = 0; j < flash_geo.block_size - sizeof(struct zip_eocd); j++) {
|
||||
eocd = (struct zip_eocd *)(blk_data + j);
|
||||
if (eocd->signature == ZIP_FILE_EOCD_SIGN) {
|
||||
len = j + sizeof(struct zip_eocd) + eocd->comment_len + i * flash_geo.block_size;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
rt_device_close(flash_dev);
|
||||
if (blk_data)
|
||||
free(blk_data);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int get_zip_data_from_blk(const char *blk_name, void *buffer, size_t len)
|
||||
{
|
||||
rt_device_t flash_dev;
|
||||
struct rt_device_blk_geometry flash_geo;
|
||||
size_t read_size = 0;
|
||||
uint8_t *blk_data = NULL;
|
||||
|
||||
flash_dev = rt_device_find(blk_name);
|
||||
if (!flash_dev)
|
||||
return -1;
|
||||
|
||||
if (rt_device_open(flash_dev, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
|
||||
return -1;
|
||||
|
||||
rt_device_control(flash_dev, RT_DEVICE_CTRL_BLK_GETGEOME, &flash_geo);
|
||||
|
||||
read_size = RT_ALIGN(len, flash_geo.block_size);
|
||||
blk_data = (uint8_t *)malloc(read_size);
|
||||
|
||||
rt_device_read(flash_dev, 0, blk_data, read_size / flash_geo.block_size);
|
||||
|
||||
memcpy(buffer, blk_data, len);
|
||||
|
||||
rt_device_close(flash_dev);
|
||||
if (blk_data)
|
||||
free(blk_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct aic_zip_reader *aic_zip_reader_open(const char *source)
|
||||
{
|
||||
int fd = -1;
|
||||
struct aic_zip_reader *reader = NULL;
|
||||
void *buffer = NULL;
|
||||
size_t zip_size = 0;
|
||||
struct stat st;
|
||||
bool is_file = false;
|
||||
|
||||
fd = open(source, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
zip_size = get_zip_size_from_blk(source);
|
||||
if (zip_size == 0) {
|
||||
pr_err("zip file data get failed\n");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
is_file = true;
|
||||
if (fstat(fd, &st) == -1) {
|
||||
close(fd);
|
||||
pr_err("Stat file failed\n");
|
||||
return NULL;
|
||||
}
|
||||
zip_size = st.st_size;
|
||||
}
|
||||
|
||||
buffer = (char *)malloc(zip_size);
|
||||
if (!buffer) {
|
||||
if (is_file)
|
||||
close(fd);
|
||||
pr_err("Memory allocation failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is_file) {
|
||||
if (read(fd, buffer, zip_size) != zip_size) {
|
||||
free(buffer);
|
||||
close(fd);
|
||||
pr_err("File read failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (close(fd) == -1) {
|
||||
free(buffer);
|
||||
pr_err("File close failed\n");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (get_zip_data_from_blk(source, buffer, zip_size) == -1) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Create reader instance
|
||||
reader = (struct aic_zip_reader *)malloc(sizeof(struct aic_zip_reader));
|
||||
if (!reader) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
memset(reader, 0, sizeof(struct aic_zip_reader));
|
||||
|
||||
// Initialize miniz ZIP archive
|
||||
memset(&reader->archive, 0, sizeof(mz_zip_archive));
|
||||
if (!mz_zip_reader_init_mem(&reader->archive, buffer, zip_size, 0)) {
|
||||
pr_err("Failed to init ZIP archive: %s\n",
|
||||
mz_zip_get_error_string(mz_zip_get_last_error(&reader->archive)));
|
||||
aic_zip_reader_close(reader);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reader->zip_buffer = buffer;
|
||||
reader->zip_size = zip_size;
|
||||
reader->file_count = mz_zip_reader_get_num_files(&reader->archive);
|
||||
reader->file_info = malloc(sizeof(struct aic_file_info) * reader->file_count);
|
||||
memset(reader->file_info, 0, sizeof(struct aic_file_info) * reader->file_count);
|
||||
|
||||
for (int i = 0; i < reader->file_count; i++) {
|
||||
mz_zip_archive_file_stat stat;
|
||||
if (!mz_zip_reader_file_stat(&reader->archive, i, &stat)) {
|
||||
aic_zip_reader_close(reader);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reader->file_info[i].name = malloc(strlen(stat.m_filename) + 2);
|
||||
if (!reader->file_info[i].name) {
|
||||
aic_zip_reader_close(reader);
|
||||
return NULL;
|
||||
}
|
||||
reader->file_info[i].name[0] = '/';
|
||||
memcpy(reader->file_info[i].name + 1, stat.m_filename, strlen(stat.m_filename) + 1);
|
||||
reader->file_info[i].size = stat.m_uncomp_size;
|
||||
}
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
void aic_zip_reader_close(struct aic_zip_reader *reader)
|
||||
{
|
||||
if (reader) {
|
||||
if (reader->file_info) {
|
||||
for (int i = 0; i < reader->file_count; i++)
|
||||
if (reader->file_info[i].name)
|
||||
free(reader->file_info[i].name);
|
||||
free(reader->file_info);
|
||||
}
|
||||
|
||||
if (reader->zip_buffer)
|
||||
free(reader->zip_buffer);
|
||||
|
||||
mz_zip_reader_end(&reader->archive);
|
||||
|
||||
free(reader);
|
||||
}
|
||||
}
|
||||
|
||||
int aic_zip_reader_read(struct aic_zip_reader *reader, struct aic_file_info file_info, void *buffer)
|
||||
{
|
||||
if (!reader || !buffer) {
|
||||
return -1;
|
||||
}
|
||||
const char *file_name = file_info.name + 1;
|
||||
size_t buffer_size = file_info.size;
|
||||
size_t extacted_size = 0;
|
||||
mz_zip_reader_extract_iter_state *iter =
|
||||
mz_zip_reader_extract_file_iter_new(&reader->archive, file_name, 0);
|
||||
|
||||
while (extacted_size < buffer_size) {
|
||||
size_t byte_read =
|
||||
mz_zip_reader_extract_iter_read(iter, buffer + extacted_size, READ_BUF_SIZE);
|
||||
if (byte_read == 0)
|
||||
break;
|
||||
extacted_size += byte_read;
|
||||
}
|
||||
|
||||
mz_zip_reader_extract_iter_free(iter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
packages/artinchip/zipfs/test_zip_files/big_file.zip
Normal file
BIN
packages/artinchip/zipfs/test_zip_files/big_file.zip
Normal file
Binary file not shown.
BIN
packages/artinchip/zipfs/test_zip_files/much_file.zip
Normal file
BIN
packages/artinchip/zipfs/test_zip_files/much_file.zip
Normal file
Binary file not shown.
137
packages/artinchip/zipfs/zip_fs_demo.c
Normal file
137
packages/artinchip/zipfs/zip_fs_demo.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2025, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Cui Jiawei <jiawei.cui@artinchip.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <finsh.h>
|
||||
#include <aic_core.h>
|
||||
#include <rtthread.h>
|
||||
#include <dfs_posix.h>
|
||||
#include <aic_common.h>
|
||||
#include <aic_utils.h>
|
||||
#include "zip_fs.h"
|
||||
|
||||
/**
|
||||
* Note: An empty directory must be prepared as the mount point. It is recommended
|
||||
* to add {ROMFS_DIRENT_DIR, "zipfs", RT_NULL, 0} in _mountpoint_root within
|
||||
* ./target/xxx/demoxx-xxx/board.c.
|
||||
*/
|
||||
#define MOUNT_PATH "/zipfs"
|
||||
#define SOURCE_FILE "/rodata/zipfs_test/big_file.zip"
|
||||
#define SOURCE_BLK "blk_rodata_r"
|
||||
|
||||
static const char *g_file_name = MOUNT_PATH "/large_file.txt";
|
||||
|
||||
/**
|
||||
* Reads and displays the entire contents of a file
|
||||
*
|
||||
* @param fd File descriptor to read from
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
static int read_file(int fd)
|
||||
{
|
||||
off_t size = -1;
|
||||
ssize_t bytes_read = -1;
|
||||
char *buffer = NULL;
|
||||
|
||||
/* Get file size by seeking from start to end */
|
||||
if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
|
||||
pr_err("Seek to start failed\n");
|
||||
return -1;
|
||||
}
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
if (size == (off_t)-1) {
|
||||
pr_err("Seek to end failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return to beginning of file */
|
||||
if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
|
||||
pr_err("Seek to start failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate buffer for file contents */
|
||||
buffer = (char *)aicos_malloc(MEM_CMA, size + 1);
|
||||
if (!buffer) {
|
||||
pr_err("Memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
uint64_t start_us = aic_get_time_us();
|
||||
/* Read entire file */
|
||||
bytes_read = read(fd, buffer, size);
|
||||
show_speed("zip file read speed", bytes_read, aic_get_time_us() - start_us);
|
||||
|
||||
if (bytes_read == -1) {
|
||||
aicos_free(MEM_CMA, buffer);
|
||||
pr_err("File read failed\n");
|
||||
return -1;
|
||||
}
|
||||
buffer[bytes_read] = '\0';
|
||||
|
||||
/* Display contents */
|
||||
rt_kprintf("Read %lu bytes:\n", (unsigned long)bytes_read);
|
||||
for (int i = 0; i < bytes_read; i++)
|
||||
putchar(buffer[i]);
|
||||
putchar('\n');
|
||||
|
||||
aicos_free(MEM_CMA, buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zip File Operations Demonstration
|
||||
*
|
||||
* Demonstrates:
|
||||
* - Opening files using open()
|
||||
* - Closing files using close()
|
||||
* - Reading files (wrapped function)
|
||||
*/
|
||||
static int zip_fs_demo(int argc, char **argv)
|
||||
{
|
||||
int fd = -1, err = 0;
|
||||
|
||||
rt_kprintf("zip file system usage example start\n");
|
||||
|
||||
/* Mount zip file system */
|
||||
err = zipfs_mount(SOURCE_FILE, MOUNT_PATH);
|
||||
/* Or you can mount zip file system by zip blk */
|
||||
// err = zipfs_mount(SOURCE_BLK, MOUNT_PATH);
|
||||
if (err) {
|
||||
pr_err("zipfs mount failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Open file */
|
||||
rt_kprintf("Open file (open) :%s\n", g_file_name);
|
||||
fd = open(g_file_name, O_RDONLY, 0644);
|
||||
if (fd == -1) {
|
||||
pr_err("File open failed\n");
|
||||
err = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Read file content */
|
||||
rt_kprintf("Read File Content\n");
|
||||
err = read_file(fd);
|
||||
if (err)
|
||||
pr_err("Read file failed\n");
|
||||
|
||||
exit:
|
||||
/* Close file using close() */
|
||||
rt_kprintf("Close File (close)\n");
|
||||
if (close(fd) == -1)
|
||||
pr_err("Final close failed");
|
||||
|
||||
/* Unmount zip file system */
|
||||
zipfs_unmount(MOUNT_PATH);
|
||||
rt_kprintf("zip file system example end\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
MSH_CMD_EXPORT(zip_fs_demo, Zip file system example);
|
||||
69
packages/artinchip/zipfs/zip_reader_demo.c
Normal file
69
packages/artinchip/zipfs/zip_reader_demo.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2025, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Cui Jiawei <jiawei.cui@artinchip.com>
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <aic_common.h>
|
||||
#include <aic_core.h>
|
||||
#include <aic_utils.h>
|
||||
#include "zip_reader.h"
|
||||
|
||||
#define SOURCE_FILE "/rodata/zipfs_test/much_file.zip"
|
||||
#define SOURCE_BLK "blk_rodata_r"
|
||||
|
||||
/**
|
||||
* Demonstrates how to process a ZIP archive by extracting and
|
||||
* printing contents of each entry.
|
||||
*/
|
||||
static int zip_reader_demo()
|
||||
{
|
||||
/* Open zip reader by zip file */
|
||||
struct aic_zip_reader *reader = aic_zip_reader_open(SOURCE_FILE);
|
||||
|
||||
/* Or you can open zip reader by zip blk */
|
||||
// struct aic_zip_reader *reader = aic_zip_reader_open(SOURCE_BLK);
|
||||
if (!reader) {
|
||||
pr_err("Failed to open zip reader by file: %s\n", SOURCE_FILE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Process each file */
|
||||
for (int i = 0; i < reader->file_count; i++) {
|
||||
size_t file_size = reader->file_info[i].size;
|
||||
char *file_name = reader->file_info[i].name;
|
||||
|
||||
rt_kprintf("Processing %d: %s, size:%zu\n", i + 1, file_name, file_size);
|
||||
|
||||
if (file_name[strlen(file_name) - 1] == '/') {
|
||||
rt_kprintf(" Skipping directory\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
void *content = malloc(file_size);
|
||||
if (!content) {
|
||||
perror("Memory allocation failed");
|
||||
aic_zip_reader_close(reader);
|
||||
return -1;
|
||||
}
|
||||
uint64_t start_us = aic_get_time_us();
|
||||
/* Read the file specified by index file_info. */
|
||||
aic_zip_reader_read(reader, reader->file_info[i], content);
|
||||
show_speed("zip file read speed", file_size, aic_get_time_us() - start_us);
|
||||
for (size_t j = 0; j < file_size; j++) {
|
||||
putchar(((char *)content)[j]);
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
free(content);
|
||||
}
|
||||
|
||||
/* Close zip reader */
|
||||
aic_zip_reader_close(reader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MSH_CMD_EXPORT(zip_reader_demo, zip reader demo);
|
||||
Reference in New Issue
Block a user