#disk-image #c64 #commodore #d64

bin+lib cbm

使用 Commodore Business Machines (CBM) 产品中发现的格式,包括传奇的 Commodore 64 家用电脑

1 个不稳定版本

使用旧的 Rust 2015

0.1.0 2018年6月26日

#1526解析实现


用于 matrix65

MIT/Apache

280KB
6K SLoC

cbm

这是一个用于处理 1980 年代 Commodore Business Machines (CBM) 产品中发现的格式的 Rust 库,包括传奇的 Commodore 64 家用电脑。目前大部分提供的功能集中在磁盘镜像上。

特性

  • 对 1541 (D64)、1571 (D71) 和 1581 (D81) 磁盘镜像执行操作。
  • 格式化磁盘镜像。
  • 迭代目录条目。(包括 GEOS 边界区中的那些。)
  • 读取、写入、删除和重命名文件。
  • 验证磁盘镜像的一致性。
  • 提供对相对 (REL)、GEOS 顺序和 GEOS VLIR 文件的访问。(目前为只读。)
  • 在写入文件时尽可能精确地模拟 1541/1571/1581 CBM DOS 的“下一个可用磁道和扇区”算法。
  • 解析 GEOS 信息块。
  • 一个用于操作 D64/D71/D81 磁盘镜像的示例 cdisk 程序。
  • 在 Petscii 和 Unicode 之间进行转换。
  • 使用 Unicode 块元素将精灵图形(包括 GEOS 图标)渲染成文本。

当前缺点

  • 不支持 1581 分区。
  • 磁盘镜像中嵌入的错误表得到支持,但未用于任何有用之处。
  • 相对、GEOS 顺序和 GEOS VLIR 文件目前为只读。

未来改进的想法可能包括

  • 将 Commodore BASIC 的二进制标记格式(例如 petcat 功能)进行转换。
  • 将 VIC-II 原生位图帧缓冲区进行转换。
  • 使用 GEOS 磁盘头部格式化磁盘镜像。
  • 访问硬盘镜像。

此库的潜在范围包括从 Commodore PET 到 Commodore 128 的 Commodore 8 位电脑,因为这些机器之间有共同之处。范围包括由 Commodore 或第三方组件(例如 GEOS)生产的硬件和软件组件,或者其内部工作原理对于解释某些磁盘格式(例如 PrologicDOS)是必需的。应用程序数据的解析(例如 Word Writer 或 geoPaint)最好在单独的 crate 中处理。

示例

以下示例打开磁盘镜像,读取目录,并打印属于 GEOS 应用程序的目录条目列表及其来自 GEOS 信息块的文本描述

use std::io;
use cbm::disk;
use cbm::disk::directory::Extra;
use cbm::disk::geos::GEOSFileType;

// Open the disk image read-only
let disk = disk::open(disk_image_filename, false)?;

// Print directory entries for GEOS applications
disk.directory()?
    .iter()
    .filter_map(|entry| {
        // Only regard directory entries with extra GEOS metadata
        match entry.extra {
            Extra::GEOS(ref geos_extra) => Some((entry, geos_extra)),
            _ => None,
        }
    })
    .filter(|(_, geos_extra)| {
        // Only regard applications
        geos_extra.geos_file_type == GEOSFileType::Application
    })
    .map(|(entry, geos_extra)| {
        // Read the info block and obtain the description string
        let description = match disk
            .open_file_from_entry(entry)
            .and_then(|f| f.geos_info())
        {
            Ok(Some(info)) => info.description.to_escaped_string(),
            Ok(None) => "No info block".to_string(),
            Err(e) => format!("error: {}", e),
        };
        (entry, description)
    })
    .for_each(|(entry, description)| {
        println!("{} {}", entry, description);
    });

在特定的 1581 GEOS 磁盘镜像上,生成以下输出

18   "paint drivers"    usr  Creates drivers that print to geoPaint files, a file for each PAGE, or OVERLAID.
141  "geowrite"         usr  geoWrite (64 version) is a WYSIWYG word processor.
152  "geopaint"         usr  geoPaint is a full-featured graphics editor.
67   "text grabber"     usr  Converts files created by other word processors into data files for geoWrite.
60   "geolaser"         usr     GEOLASER prints geoWrite files on the LaserWriter printer.
67   "geomerge"         usr     Use geoMerge to print- merge your geoWrite files.
111  "geospell"         usr  Use geoSpell to correct your spelling in geoWrite documents.
20   "convert"          usr  This version allows you to select multiple files!

更多示例,请参阅附带的 cdisk 程序,它允许从命令行对磁盘镜像执行各种操作。例如,扩展目录列表

cdisk GEOS64.D81 dir -vv
...
13   "ALARM CLOCK"      usr  GEOS(Sequential, Desk Accessory, 1986-09-03-12:00)
GEOS info block:
▛▀▀▀▀▀▀▀▀▀▀▜ Type: Desk Accessory (Sequential)
▌ ▄▀▖▛▜▗▀▄ ▐ Program addresses: load=0x5400 end=0x5fd8 start=0x5400
▌▗▘▟▞▀▀▚▙▝▖▐ Class: Alarm clock V1.0
▌▝▟▘▗ ▌▗▝▙▘▐ Author: David Durran
▌ ▞▗ ▐  ▖▚ ▐ Application:  Mgr V1.0
▌ ▌▄ ▐▄▄▄▐ ▐ Description: Set the alarm clock to keep yourself time-conscious.
▌ ▌▗    ▖▐ ▐
▌ ▐ ▗ ▖▗ ▌ ▐
▌ ▐▙▖▝ ▗▟▌ ▐
▌ ▀▘▝▀▀▘▝▀ ▐
▀▀▀▀▀▀▀▀▀▀▀▀
...

磁盘镜像访问设计

使用分层方案构建了对磁盘镜像的支持

  1. Image 提供了对包含磁盘映像的底层存储的访问,无论是磁盘映像文件还是内存数组。
  2. BlockDevice 根据一个 Geometry 将映像划分为磁道和扇区。
  3. DiskFormat 描述了特定磁盘格式如何使用磁道和扇区来存储和检索常见的 CBM DOS 结构,如磁盘头、块可用性图(BAM)和目录。
  4. Disk 特性暴露了高级功能,如打开文件、格式化磁盘、验证等。
  5. 打开文件会产生一个 File 对象,该对象根据实现其底层结构的方案(线性文件、相对文件、GEOS VLIR 等)以不同的方式访问。

设计缺陷

CBM DOS 的磁道从 1 开始而不是 0,这导致了无数的实现混淆。此 crate 提供的 API 反映了这种基于 1 的索引,但并没有在内部一致性使用。特别是,Geometry.track_layouts 使用基于 1 的磁道索引(零号磁道未使用),而 BAM 条目的数组使用基于 0 的索引。

为了向调用者提供一个简单且灵活的 API,许多组件存储了自己的 Rc<RefCell<BlockDevice>> 引用到磁盘的块存储。这允许同时使用多个 File 对象、读取器和写入器,并减少了调用者可能需要解决的寿命难题。然而,这意味着磁盘映像可能在 Disk 实现被丢弃后仍然保持打开状态(例如,如果 File 仍然存在),并且某些步骤的组合可能会导致损坏或不一致的磁盘映像。(例如,如果你开始向文件写入,然后格式化磁盘,然后继续向文件写入会发生什么?)更好的运行时检查可能有助于解决这个问题。

可以构建一个纯读取实现,以便将映射磁盘映像的切片引用传递到用户层,而无需(或最小化)额外的复制。然而,支持写入访问和多个活动读取器/写入器需要通过一个 Rc<RefCell<_>> 访问映射扇区,这限制了返回引用的能力。因此,在读取扇区链时需要复制。(也许可以设计一种奇怪的数据访问方案来避免这种情况,但我不愿意为此付出太多努力来避免复制 256 字节。)

许可证

Cbm 根据 MIT 许可证和 Apache 许可证(版本 2.0)的条款进行分发。

有关详细信息,请参阅 LICENSE-APACHE 和 LICENSE-MIT。

许可证:MIT/Apache-2.0

依赖关系

~0.7–1MB