HOME
  Security
   Software
    Hardware
  
FPGA
  CPU
   Android
    Raspberry Pi
  
nLite
  Xcode
   etc.
    ALL
  
LINK
BACK
 

2018/09/23

.QD形式のファイルを .FDS形式に変換してエミュで遊ぶ夢 QD to FDS converter Win macOS .QD形式のファイルを .FDS形式に変換してエミュで遊ぶ夢 QD to FDS converter Win macOS

(.NET C#でバイト配列のバイナリファイルを読み書きする方法、Windowsと macOSの両方で動作)

Tags: [通信販売]




● .QD形式のファイルについて

 .QD形式はディスクシステムの ROMファイルで任天堂の独自形式だそうです。
 Retroarch等のエミュレータで動かすには .FDS形式に変換する必要があります。

 んで、変換ツールとしては MGD1CNVが有名なのですが、現在はダウンロードできない状態で、入手不可になっています。

 仕方が無いので .QD形式を .FDS形式に変換するプログラムを作りました。
 C#で作ったので、Windowsと macOSの両方で動作します。

 .FDS形式 = .QD形式から CRCを除去

形式両面サイズ16進数片面サイズ16進数
.FDS形式1310000x1FFB8655000xFFDC
.QD形式1310720x20000655360x10000
 片面あたり 36バイト違います。

Family_Computer_Disk_System

*NINTENDO-HVC*

● True disc capacity

Even if the FDS disc side image is always 65500 bytes,
 one WILL have to subtract all the bits taken by the gaps and CRCs to find the actual disc capacity.
 In this regard, the way the FDS image is made is not smart because all the bits that were saved by not dumping useless data should be wasted in zeroes at the end of the disc side.
 In addition to this, the programmer should be very careful for not using the whole disc side in FDS format, otherwise, the data might not fit the disc.

The actual disc capacity in bytes is (N = number of files):
65500 - 28300/8 - (2*N + 1)*(16 + 976)/8

For example, if 8 files are present on the disc, there's room for only 59854 bytes instead of the supposed 65500.


● .QD形式を .FDS形式に変換するプログラムを作りました

 C#で作ったので、Windowsと macOSの両方で動作します。

 Windowsは Visual Studio 2013でコンパイルして動作を確認しました。
 macOSは Visual Studio for Mac 7.6.7(build 49)でコンパイルして動作を確認しました。

 QD2FDS.exe の使い方
 QD2FDS.exe [QD file name]
 出力ファイル名は "filename.qd"を "filename.fds"の様に拡張子部分を ".fds"に変更したファイル名で出力します。

 .QDファイルを .FDSファイルに変換して Retroarchで動いた夢を見ました。
 .FDS形式ですが、先頭の 16バイトの FDSヘッダ情報が無い形式になります。

 C#で byte[]のバイト配列でバイナリファイルを読み書きするサンプルにもなります。

 著作権は放棄していません。
 ライセンスは
 ・商用利用の場合は GNU General Public License v3.0
GNU General Public License v3.0
 ・それ以外の場合は Apache License, Version 2.0
APACHE LICENSE, VERSION 2.0
 のデュアルライセンスとしておきます。

Program.cs
 // NES QD to FDS format convert program
 // QD2FDS.exe
 // Copyright (c)2018 FREE WING, Y.Sakamoto

using System.IO;

namespace QD2FDS
{
    class Program
    {
        static void Main(string[] args)
        {
            string filePath = args[0];
            byte[] rbuff = ReadByteFile(filePath);
            byte[] wbuff = new byte[65500 * 2];

            int rpos = 0;
            int wpos = 0;
            int fcnt = 0;
            int cpsize = 0;
            int size04 = 0;
            while (rpos < rbuff.Length)
            {
                byte rb = rbuff[rpos];
                switch (rb)
                {
                    case 0x01:
                        // Disk info block (block 1)
                        // 0x38 + CRC 0x02
                        cpsize = 0x38;
                        break;

                    case 0x02:
                        // File amount block (block 2)
                        // 0x02 + CRC 0x02
                        cpsize = 0x02;
                        fcnt = rbuff[rpos + 1];
                        break;

                    case 0x03:
                        // File header block (block 3)
                        // 0x10 + CRC 0x02
                        cpsize = 0x10;
                        size04 = (rbuff[rpos + 14] << 8) + rbuff[rpos + 13];
                        break;

                    case 0x04:
                        // File data block (block 4)
                        // (size04 + 1) + CRC 0x02
                        cpsize = size04 + 1;
                        if (fcnt > 0)
                        {
                            --fcnt;
                        }
                        else
                        {
                            // Error
                        }
                        break;

                    case 0x00:
                        if (fcnt == 0)
                        {
                            cpsize = 0x10000 - (rpos & 0xFFFF);
                        }
                        else
                        {
                            // Error
                        }
                        break;
                }

                while ((cpsize-- > 0) && (wpos < wbuff.Length))
                {
                    wbuff[wpos++] = rbuff[rpos++];
                }

                if (rb == 0x00)
                {
                    if (wpos < 0x10000)
                    {
                        // .FDS Side B
                        wpos = 0xFFDC;
                    }
                }
                else
                {
                    // Skip CRC
                    rpos += 2;
                }
            }

            WriteByteFile(filePath.Replace(".qd", ".fds"), wbuff);
        }

        static byte[] ReadByteFile(string filePath)
        {
            using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                var buffer = new byte[fs.Length];
                fs.Read(buffer, 0, buffer.Length);
                return buffer;
            }
        }

        static void WriteByteFile(string filePath, byte[] buff)
        {
            using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
            {
                fs.Write(buff, 0, buff.Length);
            }
        }
    }
}


●上記のソースリストをビルドして Windowsの実行ファイルを作成する方法

 Visual Studioをインストールしないで .csの C#のソースファイルをビルドする方法。

 上記の内容を Program.csのファイル名で保存する。
 Program.csを csc.exeでコンパイルする。
 実行ファイルの Program.exeが作成される。

検証環境: Windows 10 1903 18362.387

● v3.5でビルド可能
> C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe Program.cs

● v4.0.30319でビルド可能
> C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe Program.cs

● v2.0.50727ではビルド不可、コンパイルエラー
> C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe Program.cs

Microsoft(R) Visual C# 2005 Compiler version 8.00.50727.9136
for Microsoft(R) Windows(R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

Program.cs(98,20): error CS0246: 型または名前空間名 'var'
        が見つかりませんでした。using
        ディレクティブまたはアセンブリ参照が不足しています。
Program.cs(100,17): error CS0246: 型または名前空間名 'var'
        が見つかりませんでした。using
        ディレクティブまたはアセンブリ参照が不足しています。
Program.cs(102,24): error CS0029: 型 'var' を型 'byte[]'
        に暗黙的に変換できません。
Program.cs(108,20): error CS0246: 型または名前空間名 'var'
        が見つかりませんでした。using
        ディレクティブまたはアセンブリ参照が不足しています。


●追記:引数無しで実行するとアプリが例外エラーを発生します

 Visual Studio上で引数無しで直接実行すると、下記の所でアプリが例外エラーを発生します。

            string filePath = args[0];

・引数無しで実行するとアプリが例外エラーを発生します
引数無しで実行するとアプリが例外エラーを発生します


・引数無しで実行するとアプリが例外エラーを発生します
引数無しで実行するとアプリが例外エラーを発生します




●例外エラーを回避する方法、その1

 「デバッグ」、「QD2FDS のプロパティ」を選択する。
 「コマンドライン引数」欄に QD形式に変換したいファイルの場所を入力する。

・例外エラーを回避する方法、その1
例外エラーを回避する方法、その1
 「デバッグ」、「QD2FDS のプロパティ」を選択する。

・例外エラーを回避する方法、その1
例外エラーを回避する方法、その1
 「コマンドライン引数」欄に QD形式に変換したいファイルの場所を入力する。
 画面の例では C:¥hoge¥fuga.qdを C:¥hoge¥fuga.fdsに変換します。


●例外エラーを回避する方法、その2-A

 string filePath = の行にファイルの場所を記述する。
            string filePath = @"C:\hoge\fuga.qd";
 ※ C#の文法規則で文字列の先頭に@を付けると¥マークを1個で書けます。
・例外エラーを回避する方法、その2-A
例外エラーを回避する方法、その2-A




●例外エラーを回避する方法、その2-B

 string filePath = の行にファイルの場所を記述する。
            string filePath = "C:\\hoge\\fuga.qd";
 ※ C#の文法規則で文字列の先頭に@が無い場合は¥マークを2個ダブって書く必要が有ります。
・例外エラーを回避する方法、その2-B
例外エラーを回避する方法、その2-B




● .QD形式を .FDS形式に変換するプログラムを作りました2

 改良点
 ・ ファイル名無指定時のチェックを追加。
 ・ FDSヘッダの付加機能を追加。
 ・ .NET v2.0系でのビルド対応。

 QD2FDS.exe の使い方
 QD2FDS.exe [QD file name]
 出力ファイル名は "filename.qd"を "filename.fds"の様に拡張子部分を ".fds"に変更したファイル名で出力します。(FDSヘッダ無し)

 QD2FDS.exe [QD file name] 2 (ファイル名の後ろに「半角空白 2」を追加する)
 出力ファイル名は "filename.qd"を "filename.fds"の様に拡張子部分を ".fds"に変更したファイル名で出力します。
 出力ファイルの先頭に 16バイトの FDSヘッダを付加します。
 FDSヘッダは下記固定値です。02なので両面ディスクを想定。
 46 44 53 1A 02 00 00 00 00 00 00 00 00 00 00 00

検証環境: Windows 10 1903 18362.387

● v2.0.50727でビルド可能
> C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe Program.cs

● v3.5でビルド可能
> C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe Program.cs

● v4.0.30319でビルド可能
> C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe Program.cs

Program.cs
 // NES QD to FDS format convert program
 // QD2FDS.exe
 // Copyright (c)2018 FREE WING, Y.Sakamoto

using System;
using System.IO;

namespace QD2FDS
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                // ファイル名を指定してね
                Environment.Exit(1);
            }

            string filePath = args[0];
            byte[] rbuff = ReadByteFile(filePath);
            byte[] wbuff = new byte[65500 * 2];

            int rpos = 0;
            int wpos = 0;
            int fcnt = 0;
            int cpsize = 0;
            int size04 = 0;
            while (rpos < rbuff.Length)
            {
                byte rb = rbuff[rpos];
                switch (rb)
                {
                    case 0x01:
                        // Disk info block (block 1)
                        // 0x38 + CRC 0x02
                        cpsize = 0x38;
                        break;

                    case 0x02:
                        // File amount block (block 2)
                        // 0x02 + CRC 0x02
                        cpsize = 0x02;
                        fcnt = rbuff[rpos + 1];
                        break;

                    case 0x03:
                        // File header block (block 3)
                        // 0x10 + CRC 0x02
                        cpsize = 0x10;
                        size04 = (rbuff[rpos + 14] << 8) + rbuff[rpos + 13];
                        break;

                    case 0x04:
                        // File data block (block 4)
                        // (size04 + 1) + CRC 0x02
                        cpsize = size04 + 1;
                        if (fcnt > 0)
                        {
                            --fcnt;
                        }
                        else
                        {
                            // Error
                        }
                        break;

                    case 0x00:
                        if (fcnt == 0)
                        {
                            cpsize = 0x10000 - (rpos & 0xFFFF);
                        }
                        else
                        {
                            // Error
                        }
                        break;
                }

                while ((cpsize-- > 0) && (wpos < wbuff.Length))
                {
                    wbuff[wpos++] = rbuff[rpos++];
                }

                if (rb == 0x00)
                {
                    if (wpos < 0x10000)
                    {
                        // .FDS Side B
                        wpos = 0xFFDC;
                    }
                }
                else
                {
                    // Skip CRC
                    rpos += 2;
                }
            }

            byte header_param = 0;
            if (args.Length >= 2)
            {
                if (args[1] == "1")
                {
                    // header_param = 1;
                }
                if (args[1] == "2")
                {
                    // FDSヘッダ付加は 2だけ有効
                    header_param = 2;
                }
                if (args[1] == "4")
                {
                    // header_param = 4;
                }
            }

            byte[] header = null;
            if (header_param != 0)
            {
                // "FDS", EOF, Number of disk sides
                // https://wiki.nesdev.com/w/index.php/FDS_file_format
                header = new byte[16]{ 0x46, 0x44, 0x53, 0x1A, header_param, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            }

            WriteByteFile(filePath.Replace(".qd", ".fds"), wbuff, header);
        }

        static byte[] ReadByteFile(string filePath)
        {
            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                byte[] buffer = new byte[fs.Length];
                fs.Read(buffer, 0, buffer.Length);
                return buffer;
            }
        }

        static void WriteByteFile(string filePath, byte[] buff, byte[] header)
        {
            using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
            {
                if (header != null)
                {
                    fs.Write(header, 0, header.Length);
                }
                fs.Write(buff, 0, buff.Length);
            }
        }
    }
}



Tags: [通信販売]

●関連するコンテンツ(この記事を読んだ人は、次の記事も読んでいます)

ニンテンドークラシックミニ ダブルパックを購入、ミニ ファミリーコンピュータとミニ スーパーファミコン
ニンテンドークラシックミニ ダブルパックを購入、ミニ ファミリーコンピュータとミニ スーパーファミコン

  品薄だったミニファミコンがミニスーファミとダブルパックで販売再開したので買ってみた

任天堂 クラシックミニ ミニファミコンとミニスーファミを改造して任意のゲームを追加する
任天堂 クラシックミニ ミニファミコンとミニスーファミを改造して任意のゲームを追加する

  ファミコンミニとスーファミミニをハックして任意のゲームを追加やゲームボーイや PCエンジンを動かす

任天堂 クラシックミニ ミニスーファミに hakchi2アプリを入れて任意のゲームを追加や他機種のゲームで遊ぶ
任天堂 クラシックミニ ミニスーファミに hakchi2アプリを入れて任意のゲームを追加や他機種のゲームで遊ぶ

  ファミコンミニとスーファミミニに hakchi2アプリを入れてゲーム追加や他のゲーム機のゲームで遊ぶ

任天堂 クラシックミニ ファミコンに隠されたハッカー宛てのメッセージをハッカーが発見する!
任天堂 クラシックミニ ファミコンに隠されたハッカー宛てのメッセージをハッカーが発見する!

  ファミコンミニ内の隠された場所に隠されたハッカー宛てウィットなメッセージ、キャプテン花札

インターネットから無料でダウンロードできるゲーム機用のゲームソフトのまとめ
インターネットから無料でダウンロードできるゲーム機用のゲームソフトのまとめ

  スーファミミニをハックしてネットからダウンロードできるゲームを追加してみるテスト

ファミコンの市販ゲームソフトの書き換え改造 AC化 Arcade Conversionの IPSパッチプログラム
ファミコンの市販ゲームソフトの書き換え改造 AC化 Arcade Conversionの IPSパッチプログラム

  .NET C#でバイト配列のバイナリファイルを読み書きする方法、Windowsと macOSの両方で動作

任天堂 クラシックミニ ミニスーファミを改造してスーファミの任意のゲームを追加する方法
任天堂 クラシックミニ ミニスーファミを改造してスーファミの任意のゲームを追加する方法

  スーファミミニをハックして好きなスーファミのゲームを追加してみるテスト

任天堂 クラシックミニ ミニスーファミを改造してファミコンの任意のゲームを追加する方法
任天堂 クラシックミニ ミニスーファミを改造してファミコンの任意のゲームを追加する方法

  スーファミミニをハックして好きなファミコンのゲームを追加してみるテスト

任天堂 クラシックミニ ミニスーファミを改造してゲーム ボーイ アドバンスの任意のゲームを追加する方法
任天堂 クラシックミニ ミニスーファミを改造してゲーム ボーイ アドバンスの任意のゲームを追加する方法

  スーファミミニをハックして好きな GBA ゲームボーイアドバンスのゲームを追加してみるテスト

「ふるさと納税」でファミコンの同人ゲーム「キラキラスターナイト ふるさと納税 ふじみ野版」
「ふるさと納税」でファミコンの同人ゲーム「キラキラスターナイト ふるさと納税 ふじみ野版」

  ふるさと納税の返礼品でファミコンの同人ゲームを実質 2000円でゲットする方法

SONY PlayStation Classicをハックして任意のゲームを追加する方法 BleemSync編
SONY PlayStation Classicをハックして任意のゲームを追加する方法 BleemSync編

  任意のゲームを復刻版プレイステーションミニ クラシック SCPH-1000RJに追加する方法

SONY PlayStation Classicを買ってみた。内箱の正しい開け方
SONY PlayStation Classicを買ってみた。内箱の正しい開け方

  初期型プレイステーションの復刻版プレイステーション クラシック SCPH-1000RJを買った




[HOME] | [BACK]
リンクフリー(連絡不要、ただしトップページ以外は Web構成の変更で移動する場合があります)
Copyright (c) 2018-2019 FREE WING,Y.Sakamoto
Powered by 猫屋敷工房 & HTML Generator

http://www.neko.ne.jp/~freewing/hardware/nintendo_format_converter_qd_to_fds/