Board logo

标题: 写了个HD-COPY IMG转普通IMA格式软盘镜像的软件 [打印本页]

作者: rgwan     时间: 2018-3-20 00:22    标题: 写了个HD-COPY IMG转普通IMA格式软盘镜像的软件

废话少说,放源码!

https://github.com/rgwan/hdcopy-tools

编译好的程序下载:

http://rthost.fam.cx/cndos-up/img/2357.zip

另外求UCDOS3.1版的扩充字库!感激不尽!打算做一些压缩和优化,使得它们继续发挥余热!

[ Last edited by rgwan on 2018-3-20 at 00:23 ]
作者: LoggerVick     时间: 2018-3-20 00:31
不过可能你的附件会很少有人下载,我先顶一下。
作者: LoggerVick     时间: 2018-3-20 00:36


  Quote:
Originally posted by rgwan at 2018-3-20 00:22:
废话少说,放源码!

https://github.com/rgwan/hdcopy-tools

编译好的程序下载:

http://rthost.fam.cx/cndos-up/img/2357.zip

另外求UCDOS3.1版的扩 ...

我已经向我加的联盟群询问字库了,有的话应该会提示你去那个群下载。

[ Last edited by LoggerVick on 2018-3-20 at 00:46 ]
作者: rgwan     时间: 2018-3-20 08:46
http://cndos.fam.cx/forum/viewth ... =%E6%B1%87%E9%BE%99

已经找到啦,感谢mys先生!
作者: crshen     时间: 2018-3-20 12:19
程序不错,英文语句稍有点不统一,前面是decompress,后面是Decode,两者有点区别的。
另外提个小建议,这种DOS程序最好使用TC或者BC,DOS文本格式,GCC对很多初入门者有点复杂。C99标准比较晚,而程序中只用了stdint.h中的数据类型,如果改成老标准C89更方便大家学习。
作者: crshen     时间: 2018-3-20 13:25
刚转换到TC2.0,编译后DOS下测试发现严重问题,看来对hd-copy的img格式分析还不全面。确认为hd-copy 2.0a的img居然解压不出,只写出个32k的头。再测试gcc编译版本,完全不支持DOS,cmd下可以运行,但是解压img却出错退出。
作者: crshen     时间: 2018-3-20 13:38
既然源码是牛X的WTFPL开源协议,我就乱改了
DOS版源码请看后面第14楼层,下载地址在15楼。





[ Last edited by crshen on 2018-3-21 at 16:24 ]
作者: rgwan     时间: 2018-3-20 18:59
能否将出错的Image发给我?另外的,这个程序其实并不运行在DOS环境下。设计上是配合Windows/Linux,给虚拟机使用的。

此外,我做了一些修复,不知对于您的Image是否奏效。
CODE:  [Copy to clipboard]
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

int main(int argc, char *argv[])
{
        FILE *fp;
        uint8_t *hdcopy;
        uint8_t *plain;
        uint32_t length;
        uint32_t fit_size = 0;

        int i, j, k, r;

        if(argc != 3 && argc != 4)
        {
                fprintf(stderr, "Usage: %s <HD-COPY Image> <IMA plain floppy image> [size]\n\n", argv[0]);
                fprintf(stderr, "This small tool can decompress HD-COPY image to plain floppy image.\n");
                fprintf(stderr, "It can help you to use old HD-COPY image on modern PC,\nespecially on Virtual Machine to test out old-school softwares.\n\n");
                fprintf(stderr, "Zhiyuan Wan <h@iloli.bid> 2018, License WTFPL.\nAlgorithm analyze from <https://github.com/ciel-yu/devnotes>. Thanks him!\n");
                exit(-1);
        }
        if(argc == 4)
        {
                fit_size = atoi(argv[3]);
        }
        fp = fopen(argv[1], "rb");
        if(!fp)
        {
                fprintf(stderr, "Can't open source HD-COPY image!\n");
                exit(-1);
        }
        fseek(fp, 0, SEEK_END);
        length = ftell(fp);

        hdcopy = malloc(length);
        plain = malloc(0x168000);

        fseek(fp, 0, SEEK_SET);

        fread(hdcopy, length, 1, fp);

        printf("Decompressing HD-COPY Image\nInput size = %d\n", length);
        fclose(fp);

        uint8_t *actualimage;

        uint8_t *payload;

        if(hdcopy[0] == 0xff && hdcopy[1] == 0x18)
        {
                printf("That is an HD-COPY 2.0 Image\n");
                actualimage = hdcopy + 0x0e; /* 跳过标有卷标的文件头 */
                payload = actualimage + 2 + 168; /* 载荷段 */
        }
        else
        {
                printf("That is an HD-COPY 1.7 Image\n");
                actualimage = hdcopy;
                payload = actualimage + 2 + 164;
        }
        /* 开始解码 */
        int maxTrackCount = actualimage[0];
        int secPerTrack = actualimage[1];

        printf("maxTrackCount = %d, secPerTrack = %d\n", maxTrackCount, secPerTrack);
        uint8_t *dataTrack = actualimage + 2; /* 有数据的磁道表 */

        uint8_t *decomp_p = plain;

        memset(plain, 0x00, 0x168000);

        for(i = 0; i < maxTrackCount; i++)
        {
                for(j = 0; j < 2; j++)
                {
                        if(dataTrack[(i * 2) + j] != 0x01)
                        {
                                decomp_p += 512 * secPerTrack;
                                continue;
                        }
                        int dataLen = payload[0] + (payload[1] << 8);
                        payload += 2;
                        uint8_t escByte; /* RLE 压缩 */
                        for(k = 0; k < dataLen; k++)
                        {
                                if(k == 0)
                                {
                                        escByte = payload[0];
                                }
                                else
                                {
                                        if(payload[k] == escByte)
                                        {
                                                k++;
                                                uint8_t repeatByte = payload[k++];
                                                int repeat = payload[k];

                                                for(r = 0; r < repeat; r++)
                                                {
                                                        *(decomp_p++) = repeatByte;
                                                }
                                        }
                                        else
                                        {
                                                *(decomp_p++) = payload[k];
                                        }
                                }
                        }
                        payload += dataLen;
                }
        }
        uint16_t secCount = plain[0x13] + (plain[0x14] << 8);
        printf("Floppy sector count = %d, fitting to %d bytes\n",
                   secCount, fit_size > 0 ? fit_size : secCount * 512);
        printf("Decompress operation completed, write it to file\n");
        fp = fopen(argv[2], "wb+");
        if(!fp)
        {
                fprintf(stderr, "Can't save plain floppy image!\n");
                goto deal;
        }
        fseek(fp, 0, SEEK_SET);
        fwrite(plain, fit_size > 0 ? fit_size : (secCount * 512 > 0 ? secCount * 512 : 0x168000), 1, fp);
        fclose(fp);

deal:
        free(hdcopy);
        free(plain);
        return 0;
}
[ Last edited by rgwan on 2018-3-20 at 19:01 ]
作者: LoggerVick     时间: 2018-3-20 22:11


  Quote:
Originally posted by rgwan at 2018-3-20 18:59:
能否将出错的Image发给我?另外的,这个程序其实并不运行在DOS环境下。设计上是配合Windows/Linux,给虚拟机使用的。

此外,我做了一些修复,不知对 ...

他qq不加好友,你加入群可以搜索一下crshen然后他看到就能给你。
作者: LoggerVick     时间: 2018-3-20 22:38
或者试试新dos时代纪念光盘crshen留的email
作者: LoggerVick     时间: 2018-3-20 23:06
crshen:@[论坛]Willard 知道,我今天单位夜班,没法回他,一晚不睡,明天要睡一天,估计明下午4点后回复他吧。
作者: crshen     时间: 2018-3-21 15:36
回复rgwan:
经测试,程序已基本能解压HD-copy的img,但是源码中存在些瑕疵:
1、i 的 for 循环明显错误,查看img格式文档,byte    tracks; // total tracks - 1,这里是以0起计数的,80道显示为79,故要改for (i = 0; i <= maxTrackCount; i++),否则在一些比较满的磁盘会缺一个磁道数据。
2、对 for(k = 0; k < dataLen; k++) 中k==0的判断,几乎每个磁道将进行上万次,影响效率,可改:
escByte = payload[0];
            for (k = 1; k < dataLen; k++){}
作者: crshen     时间: 2018-3-21 15:44
软件测试环境:
1、Ubuntu 16.04 ,gcc编译,命令行下运行正常;
2、Win7 x64 + CodeBlocks 17.12 mingw,cmd环境运行正常;
3、XP + cfree5.0默认gcc3.45,cmd环境运行正常;
4、DOS 6.22 + Turbo C 2.0,运行正常,拷贝到win98,command下运行正常。

测试方法:
1、磁盘映像,选用mys的起步DOS网站下10个HD-COPY img,包括1.44M和1.2M;
2、单命令行执行;
3、批处理执行:for %i in (dir *.img) do dehd.exe %i dest\%i (将当前目录下所有HD-COPY格式img 转换到 标准格式img,保存至dest目录下同名文件)。
作者: crshen     时间: 2018-3-21 15:51
首先感谢rgwan分享源码,这里是我修改的DOS版本,可用TC2.0或BC3.1编译。

由于DOS内存限制,不可能像保护模式下那样直接申请一个大内存,故数据解码需频繁进行文件读写,磁盘IO速度自然比不上内存,效率较CMD版要差些。
CODE:  [Copy to clipboard]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE *fpin, *fpout;
    unsigned char *buffer, *hdcopy, *plain, *pnDataTrkMap;
    int nTrackCount, nSecPerTrack, nBytesPerTrack, nActualImgAddr, nImgDataAddr, escByte, repeatByte, repeat;
    unsigned int nDataLen;
    unsigned long nFinPos;
    int i, j, k, r;

    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s <HD-COPY Image> <IMA plain floppy image>\n\n", argv[0]);
        fprintf(stderr, "This small tool decompress HD-COPY image to plain floppy image.\n");
        fprintf(stderr, "Therefore, you can use old HD-COPY img on modern PC or Virtual Machine.\n\n");
        fprintf(stderr, "Zhiyuan Wan <h@iloli.bid> 2018, License WTFPL.\nAlgorithm analyze from <https://github.com/ciel-yu/devnotes>. Thanks him!\n");
        fprintf(stderr, "Modified to suit old DOS by crshen <crshen@qq.com>.\n\n");
        exit(-1);
    }
    fpin = fopen(argv[1], "rb");
    if (!fpin)
    {
        fprintf(stderr, "Can't open source HD-COPY image!\n");
        exit(-1);
    }

    fpout = fopen(argv[2], "wb+");
    if (!fpout)
    {
        fprintf(stderr, "Can't save plain floppy image!\n");
        exit(-1);
    }

    buffer = malloc(2);

    fseek(fpin, 0, SEEK_SET);
    fread(buffer, 2, 1, fpin);
    if (buffer[0] == 0xff && buffer[1] == 0x18)
    {
        printf("Source img is an HD-COPY 2.0 Image\n");
        nActualImgAddr = 14; /* 跳过标有卷标的文件头 */
        nImgDataAddr = nActualImgAddr + 2 + 168; /* 磁道数据起始 */
    }
    else
    {
        printf("Source img may be an HD-COPY 1.7 Image\n");
        nActualImgAddr = 0;
        nImgDataAddr = nActualImgAddr + 2 + 164;
    }

    fseek(fpin, nActualImgAddr, SEEK_SET);
    fread(buffer, 2, 1, fpin);
    nTrackCount = buffer[0];   /* total tracks - 1 */
    nSecPerTrack = buffer[1];
    nBytesPerTrack = 512 * nSecPerTrack;
    printf("nTrackCount = %d, nSecPerTrack = %d\n", nTrackCount, nSecPerTrack);

    pnDataTrkMap = malloc(2 * (nTrackCount + 1));
    fseek(fpin, nActualImgAddr + 2, SEEK_SET);  /* tracks_map */
    fread(pnDataTrkMap, 2 * (nTrackCount + 1), 1, fpin);

    plain = malloc(nBytesPerTrack); /* 一个标准磁道容量 */
    hdcopy = malloc(nBytesPerTrack); /* 存放压缩磁道数据 */
    nFinPos = nImgDataAddr;
    printf("Working hard,please wait...\n");
    fseek(fpout, 0, SEEK_SET);
    for (i = 0; i <= nTrackCount; i++)
    {
        for (j = 0; j < 2; j++)
        {
            if (pnDataTrkMap[(i * 2) + j] != 0x01) /* 映射为空磁道 */
            {
                memset(plain, 0x00, nBytesPerTrack);
                fwrite(plain, nBytesPerTrack, 1, fpout);
                continue;
            }
            fseek(fpin, nFinPos, SEEK_SET);
            fread(buffer, 2, 1, fpin);
            nDataLen = buffer[0] + (buffer[1] << 8); /* little endian */
            memset(hdcopy, 0x00, nBytesPerTrack);
            fread(hdcopy, nDataLen, 1, fpin);
            nFinPos = nFinPos + 2 + nDataLen;
            escByte = hdcopy[0];
            for (k = 1; k < nDataLen; k++)  /* RLE压缩的磁道内容解压 */
            {
                if (hdcopy[k] == escByte)
                {
                    k++;
                    repeatByte = hdcopy[k++];
                    repeat = hdcopy[k];
                    for (r = 0; r < repeat; r++)
                    {
                        *(plain++) = repeatByte;
                    }
                }
                else
                {
                    *(plain++) = hdcopy[k];
                }
            }
            plain -= nBytesPerTrack;
            fwrite(plain, nBytesPerTrack, 1, fpout);            
        }
    }

    fclose(fpin);
    fclose(fpout);
    free(hdcopy);
    free(buffer);
    free(pnDataTrkMap);
    free(plain);
    printf("Decompress operation completed.\n");
    return 0;
}
[ Last edited by crshen on 2018-3-21 at 16:27 ]
作者: crshen     时间: 2018-3-21 16:08
源码文件和已经预编译的程序可到百度网盘下载:
DOS软件共享\解压HD-COPY映像到标准img.rar

pan.baidu.com/s/1toVeHvm1PHUL1d-dstROmA
密码:b5n5


或者加 QQ群:中華DOS聯盟(8393170),到群文件中下载。

[ Last edited by crshen on 2018-3-21 at 16:25 ]
作者: rgwan     时间: 2018-3-22 09:56


  Quote:
Originally posted by crshen at 2018-3-21 15:36:
回复rgwan:
经测试,程序已基本能解压HD-copy的img,但是源码中存在些瑕疵:
1、i 的 for 循环明显错误,查看img格式文档,byte    tracks; // total tracks - 1 ...

感谢指出错误.已改并重新发布到GitHub....因为我手上的镜像较少,加上这东西一直属于临时工具的状态,因此便没有过多在意代码效率和无法复现的错误问题。

另外对于比较新的GCC,escByte的判断其实会被优化展开到外部。没有细想就写下了这样的代码。

向大家表示抱歉。
作者: rgwan     时间: 2018-3-22 10:11


  Quote:
Originally posted by crshen at 2018-3-21 15:51:
首先感谢rgwan分享源码,这里是我修改的DOS版本,可用TC2.0或BC3.1编译。

由于DOS内存限制,不可能像保护模式下那样直接申请一个大内存,故 ...

另外我也将您修改后的代码发上GitHub分享啦。
作者: zhiguo7908     时间: 2018-12-23 10:15
不能这么说
作者: TurboY     时间: 2020-3-26 20:28
真不错!
最近正好遇到个HD-COPY的映像文件,没有找到undisk,结果找到了这个。
作者: kmcc123     时间: 2020-4-16 14:33
if not exist "dest" (md "dest")

for /f "tokens=*" %%i in ('dir/s/b/a-d *.img') do dehd-cmd.exe "dest\%%i"

写任意目批处理,新建一个bat,与dehd-cmd同一目录
期待出个支持64位、支持IMG内置目录(有些老软件解出没有原目录),能批处理

[ Last edited by kmcc123 on 2020-4-16 at 14:35 ]




欢迎光临 中国DOS联盟论坛 (http://cndos.fam.cx/forum/) Powered by Discuz! 2.5