Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion fitimage/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
[package]
name = "fitimage"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
authors = ["周睿 <zrufo747@outlook.com>"]
description = "A Rust library for creating U-Boot compatible FIT images"
documentation = "https://docs.rs/fitimage"
license = "MIT OR Apache-2.0"
readme = "README.md"
categories = ["embedded", "development-tools", "os"]
keywords = ["u-boot", "boot", "fit-image", "embedded"]
repository = "https://github.com/ZR233/ostool"
Expand Down
56 changes: 32 additions & 24 deletions fitimage/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# mkimage - FIT Image Library
# fitimage - FIT Image Library

一个用于创建U-Boot兼容FIT (Flattened Image Tree) 镜像的Rust库
一个用于创建 U-Boot 兼容 FIT (Flattened Image Tree) 镜像的 Rust 库

## 特性

Expand All @@ -18,26 +18,27 @@

```toml
[dependencies]
mkimage = "0.1.0"
fitimage = "0.1.0"
```

### 基本用法

```rust
use mkimage::{FitImageBuilder, FitImageConfig, ComponentConfig};
use fitimage::{ComponentConfig, FitImageBuilder, FitImageConfig};

// 创建FIT镜像配置
let config = FitImageConfig::new("My FIT Image")
.with_kernel(
ComponentConfig::new("kernel", kernel_data)
.with_load_address(0x80080000)
.with_entry_point(0x80080000)
.with_compression(true)
)
.with_fdt(
ComponentConfig::new("fdt", fdt_data)
.with_load_address(0x82000000)
)
.with_kernel_compression(true);
;

// 构建FIT镜像
let mut builder = FitImageBuilder::new();
Expand All @@ -59,10 +60,13 @@ pub struct FitImageConfig {
pub kernel: Option<ComponentConfig>,
pub fdt: Option<ComponentConfig>,
pub ramdisk: Option<ComponentConfig>,
pub compress_kernel: bool,
pub default_config: Option<String>,
pub configurations: std::collections::HashMap<String, FitConfiguration>,
}
```

> `configurations` 用于生成多个启动配置;当未设置时会自动生成默认配置。

### ComponentConfig

单个组件的配置:
Expand All @@ -84,27 +88,23 @@ pub struct ComponentConfig {
impl FitImageBuilder {
pub fn new() -> Self;
pub fn build(&mut self, config: FitImageConfig) -> Result<Vec<u8>>;
pub fn build_with_compressor(
&mut self,
config: FitImageConfig,
compressor: Box<dyn CompressionInterface>
) -> Result<Vec<u8>>;
}
```

## 示例

### 完整FIT镜像
### 完整 FIT 镜像

```rust
use mkimage::{FitImageBuilder, FitImageConfig, ComponentConfig};
use fitimage::{ComponentConfig, FitImageBuilder, FitImageConfig};

fn create_complete_fit() -> Result<(), Box<dyn std::error::Error>> {
let config = FitImageConfig::new("Complete FIT Image")
.with_kernel(
ComponentConfig::new("linux", kernel_data)
.with_load_address(0x80080000)
.with_entry_point(0x80080000)
.with_compression(true)
)
.with_fdt(
ComponentConfig::new("devicetree", fdt_data)
Expand All @@ -114,7 +114,7 @@ fn create_complete_fit() -> Result<(), Box<dyn std::error::Error>> {
ComponentConfig::new("initramfs", ramdisk_data)
.with_load_address(0x84000000)
)
.with_kernel_compression(true);
;

let mut builder = FitImageBuilder::new();
let fit_data = builder.build(config)?;
Expand All @@ -131,33 +131,41 @@ fn create_complete_fit() -> Result<(), Box<dyn std::error::Error>> {

```rust
let config = FitImageConfig::new("Compressed FIT")
.with_kernel(kernel_component)
.with_kernel_compression(true); // 启用gzip压缩
.with_kernel(kernel_component.with_compression(true)); // 启用gzip压缩
```

## 兼容性

- ✅ U-Boot FIT格式兼容
- ✅ U-Boot FIT 格式兼容
- ✅ 标准设备树结构
- ✅ ARM64架构支持
- ✅ Linux OS支持

## TODO

- [ ] 增加 bzip2 压缩支持
- [ ] 增加 lzma 压缩支持

## 构建和测试

```bash
# 构建库
cargo build --lib

# 运行测试
cargo test --lib
# 运行测试(含单元测试与集成测试)
cargo test

# 运行示例
cargo run --example basic_usage
cargo run --example compression_test
cargo run --example full_fit_test
# 仅运行文档测试
cargo test --doc
```

## API文档
## 测试建议

- 单元测试:覆盖哈希/CRC 计算、FDT 字符串表对齐、配置构建边界值。
- 功能测试:使用 `mkimage`/`dumpimage` 对照验证结构与字段一致性。
- 文档测试:为关键公开 API 添加可运行示例,保证 doctest 通过。

## API 文档

运行以下命令生成API文档:

Expand Down
31 changes: 17 additions & 14 deletions fitimage/src/compression/gzip.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,49 @@
//! Gzip压缩实现
//! Gzip compression implementation.
//!
//! 使用flate2库提供gzip压缩和解压缩功能
//! Provides gzip compression and decompression functionality using the flate2 library.

use std::io::{Read, Write};

use crate::compression::traits::CompressionInterface;
use crate::error::Result;
use flate2::{read::GzDecoder, write::GzEncoder, Compression as GzipLevel};

/// Gzip压缩器
/// 支持可配置的压缩级别
/// Gzip compressor with configurable compression level.
pub struct GzipCompressor {
/// 压缩级别 (0-9, 0表示无压缩)
/// Compression level (0-9, where 0 means no compression).
level: u8,
/// 是否启用压缩(false时直接复制数据)
/// Whether compression is enabled (false means data is copied directly).
enabled: bool,
}

impl Default for GzipCompressor {
fn default() -> Self {
Self::new(6) //
Self::new(6)
}
}

impl GzipCompressor {
/// 创建指定压缩级别的gzip压缩器
/// Creates a new gzip compressor with the specified compression level.
///
/// # Arguments
///
/// * `level` - Compression level from 0 to 9. Level 0 disables compression.
pub fn new(level: u8) -> Self {
Self {
level: level.clamp(0, 9), // 限制在0-9范围内
enabled: level > 0, // 级别0表示不压缩
level: level.clamp(0, 9),
enabled: level > 0,
}
}

/// 创建禁用压缩的实例
/// Creates a disabled compressor instance that passes data through unchanged.
pub fn new_disabled() -> Self {
Self {
level: 0,
enabled: false,
}
}

/// 获取flate2的压缩级别
/// Gets the flate2 compression level.
fn get_compression_level(&self) -> GzipLevel {
if !self.enabled {
GzipLevel::none()
Expand All @@ -58,7 +61,7 @@ impl GzipCompressor {
impl CompressionInterface for GzipCompressor {
fn compress(&self, data: &[u8]) -> Result<Vec<u8>> {
if !self.enabled {
// 如果禁用压缩,直接返回数据副本
// If compression is disabled, return a copy of the data.
return Ok(data.to_vec());
}

Expand All @@ -75,7 +78,7 @@ impl CompressionInterface for GzipCompressor {

fn decompress(&self, compressed_data: &[u8]) -> Result<Vec<u8>> {
if !self.enabled {
// 如果没有压缩,直接返回数据副本
// If compression was not applied, return a copy of the data.
return Ok(compressed_data.to_vec());
}

Expand Down
4 changes: 2 additions & 2 deletions fitimage/src/compression/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! 压缩功能模块
//! Compression module.
//!
//! 提供各种压缩算法的统一接口,支持gzip、bzip2、lzma等格式
//! Provides unified interface for compression algorithms. Currently supports gzip.

pub mod gzip;
pub mod traits;
35 changes: 20 additions & 15 deletions fitimage/src/compression/traits.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
//! 压缩接口定义
//! Compression interface definitions.
//!
//! 定义了所有压缩算法需要实现的标准接口
//! Defines the standard interface that all compression algorithms must implement.

use crate::error::Result;

/// 压缩接口trait
/// 所有压缩算法都需要实现这个接口
/// Compression interface trait.
///
/// All compression algorithms must implement this interface.
pub trait CompressionInterface {
/// 压缩数据
/// Compresses data.
///
/// # 参数
/// - `data`: 要压缩的原始数据
/// # Arguments
///
/// # 返回
/// 压缩后的数据
/// * `data` - The raw data to compress
///
/// # Returns
///
/// The compressed data.
fn compress(&self, data: &[u8]) -> Result<Vec<u8>>;

/// 解压缩数据(主要用于验证)
/// Decompresses data (mainly used for verification).
///
/// # Arguments
///
/// * `compressed_data` - The compressed data
///
/// # 参数
/// - `compressed_data`: 已压缩的数据
/// # Returns
///
/// # 返回
/// 解压缩后的原始数据
/// The decompressed original data.
fn decompress(&self, compressed_data: &[u8]) -> Result<Vec<u8>>;

/// 获取压缩算法名称
/// Returns the name of the compression algorithm.
fn get_name(&self) -> &'static str;
}
6 changes: 3 additions & 3 deletions fitimage/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Error types for mkimage operations
//! Error types for fitimage operations

use thiserror::Error;

/// Result type alias for mkimage operations
/// Result type alias for fitimage operations
pub type Result<T> = std::result::Result<T, MkImageError>;

/// Errors that can occur during mkimage operations
/// Errors that can occur during fitimage operations
#[derive(Error, Debug)]
pub enum MkImageError {
#[error("Invalid image data: {0}")]
Expand Down
Loading