約 954,456 件
https://w.atwiki.jp/rffbl22/pages/44.html
バイナリファイルの入出力 バイナリファイルの入力 バイナリファイルをFortranで読み出すためには、テキストに比べて少し複雑なことをすることになる。 fortranプログラム例 PROGRAM samp IMPLICIT NONE INTEGER i,j,k,siz REAL,DIMENSION(1 5,1 5,1 2) temp siz=5*5*2*4 OPEN(300,FILE="hoge.bin",ACCESS="direct",FORM="unformatted",STATUS="OLD",recl=siz) READ(300,rec=1) (((temp(i,j,k),i=1,5),j=1,5),k=1,2) CLOSE(300) OPEN(310,FILE= hogeout.txt ,STATUS="REPLACE") WRITE(310,*) (((temp(i,j,k),i=1,5),j=1,5),k=1,2) CLOSE(310) STOP END PROGRAM samp OPEN文で、ACESS="direct"つまり直接探査をします。 何も書かなければACCESS="sequential"つまり順番探査になる。 OPEN文やREAD文の中では、数値演算は行えないので、前もってsiz=5*5*2*4と書く。ここで*4かどうかはコンパイラに依存する。 READ文でデータ数が1つなら、rec=1と書く。 hogeout.txtに出力している。 バイナリファイルへの出力 バイナリファイルで出力するためには、入力と逆の方法をする。これでGrADSで読める。 もっとも(x,y,z)のデータなら、GMTでgrdファイルを作った方が簡単。 fortranプログラム例 PROGRAM samp IMPLICIT NONE INTEGER i,j,k,siz REAL,DIMENSION(1 5,1 5,1 2) temp siz=5*5*2*4 temp( , , )=0.0 OPEN(300,FILE="hoge.bin",ACCESS="direct",FORM="unformatted",STATUS="REPLACE",recl=siz) WRITE(300,rec=1) (((temp(i,j,k),i=1,5),j=1,5),k=1,2) CLOSE(300) STOP END PROGRAM samp このプログラムで作成したバイナリファイルを、上のプログラムで読み込むことができる。 バイナリ入力におけるエラー バイナリの入力では、変数の型を適切に指定する必要がある。 もし、バイナリの中身が整数なのに、DOUBLE PRECSIONのように指定してしまうと forrtl severe (67) input statement requires too much data, unit ... のように怒られる。 rec=2以上の場合の入出力 rec(レコード)数が2以上、つまり変数が2つ以上ある場合には、以下のような書き方をする。
https://w.atwiki.jp/asagaolabo/pages/4953.html
[バイナリスター] 【バイナリスター】 [Usual Days-remix] ハイライト発生箇所 他のBEMANIシリーズへの収録 収録作品 ロング版収録 関連リンク ポップンミュージック うさぎと猫と少年の夢で登場した楽曲。 担当キャラクターは東雲心菜(と東雲夏陽)。 メディアミックス企画「ひなビタ♪」を出典とする、ここなつの担当声優が歌う曲で、「超進化」と称した稼働途中からの追加配信曲。 ジャケットデザインはCUTEGが行っている。 バイナリスター / ここなつ BPM 135 新難易度 EASY NORMAL HYPER EXTRA 7 23 37 43 ハイライト EASY NORMAL HYPER EXTRA 4 4 4 4 稼動途中から追加配信された、「ひなビタ♪」のここなつ関連3曲の内の1曲。SOUND VOLTEXに2016年9月に登場したのが初出で、作詞作曲を手がけた IzeMac (アイズマック)は、エレクトロ系を手がける日本発の3人のユニット「NUXX」の1人。無重力の状況下でのここなつの2人を2つの惑星に例えたような未来的な世界観が特徴的で、翌年3月に発売されたここなつCDのタイトルを冠している。 同BPMのアリプロ2 / 暗黒サイケデリックを髣髴させるような縦連打で始まるのが特色。ほとんどが8分刻みの同時押し、左右別フレーズで構成されており、スライドの16分に注意すればパーフェクトも取りやすいだろう。終盤の左手2個同時は裏から入るのを意識しよう。EXは縦連打をしている手で他を拾わせる配置や、サビにおいては左右別フレーズを刻みながら左右に振られる配置・隣接同時も混じる。序盤の32分スライドやサビ途中の16分同時押し地帯が難所といった程度で、フルコンボ難度もそれほど難しくはない。 ハイライト発生箇所 番号 5Buttons / EASY NORMAL HYPER EXTRA 1 2 3 4 他のBEMANIシリーズへの収録 ジャケット この曲から、ここなつ関連曲のジャケットには「ここなつ」ロゴのみ使われるようになった(ソロ歌唱除く)。 SOUND VOLTEX IIIで「週刊ボルテ × ここなつ」と称して2016/09/08に登場。FLOOR採用曲を除き、[ロンロンへ ライライライ!]以来1年2か月ぶりのオリジナル曲となる。 VIVID WAVEでは、ここなつの誕生日に合わせて2019/06/12からVIVIDエフェクトが登場した。 MUSECA 1+1/2で2016/11/22に、[ヒミツダイヤル]と共に登場。 富士見書房での小説・コミック連載も兼ねている作品・声優を起用しているということもあってか、コナミオリジナル曲ではキー音が入っていない楽曲である。 「超進化」で追加配信された、これを含んだ解禁を要しない「ここなつ」(ひなビタ♪)関連曲としては、選曲画面でジャケット表示されているのは初の事例となる。しかし、2人1組での担当曲であるはずにも関わらず、ライバルキャラクターが条件を満たしたときに変化しないため、かつての[水月鏡花のコノテーション]と同じような不具合が起こっている(これは該当する他のここなつの2曲も同様)。 収録作品 AC版 ポップンミュージック うさぎと猫と少年の夢からの全作品 2017/09/28より追加配信により登場。 CS版 ロング版収録 バイナリスター(CD) / ここなつ ここなつBEST / ここなつ 関連リンク ひなビタ♪ ここなつ 東雲夏陽 東雲心菜 楽曲一覧/ポップンミュージック うさぎと猫と少年の夢
https://w.atwiki.jp/fekai2/pages/66.html
バイナリエディタ関連 reshuffleの作者様の資料が十二分に詳しく丁寧に解説されてるのでそちらを参照のこと いや、まてreshuffleの作者とか言われても知らんって!w -- 名無しさん どこにあるんでしょうか? -- 名無しさん 2chやここでリンクされているアプロダには見つからない模様・・・あれ、積んだ? -- 名無しさん wikiの意味 -- 名無しさん 名前 コメント
https://w.atwiki.jp/nopu/pages/216.html
hoge.dat から読み込み #include iostream #include fstream ... fstream fin( hoge.dat , ios open | ios binary); if( !fin ){ /* file open error */ } std ios off_type offset = 10; ← 10 byte 分のオフセット fin.seekg( offset, ios beg ); ← 読み出し位置を指定 char buf; ← バイナリは char 読み出しが基本。 while( fin.read( buf, sizeof(char) ) ){ /* TODO */ } 一気に読み出し char buf[256]; while( fin.read( buf, 256*sizeof(char) ) ){ /* TODO */ } 注. charの符号 gcc では、char は自動的に符号無し8bit整数 unsigned char と解釈される。←されませんでした。 VC++ では、char は自動的に符号有り8bit整数 singed char と解釈される。 したがって 1byte unsigned integer の場合は unsigned char とする。 べきだが、なぜかこうすると read( buf, ... ) のコンパイルが通らなかった。 ← char bufとしておいて,二重キャストで対処。(double) (unsigned char) buf 以下は失敗する! while( fin buf ){ /* tasks with buf */ } すべてが読み込めないのではなく、一部の、同じ箇所のバイトを飛ばす。謎
https://w.atwiki.jp/air-lang/pages/35.html
バイナリファイル入出力 ( Binary File Input Output ) バイナリデータのファイル入出力は、関数 read()/write() を使用すると便利です。 関数 buf,cnt=read(fname,byte) は、指定されたファイル fname より byte バイト分だけデータを読み込み、左辺の第1変数 buf に設定します。また、左辺の第2変数 cnt には、読み込んだバイト数がセットされます。 変数 buf の内容へのアクセスは、(バイナリデータである可能性があるため)関数 peek()/poke() を使用します。(通常の文字列関数は、 \0 文字を文字列末と認識します。) 簡易 dump プログラ ( Simple dump program ) コマンドライン引数で指定されたファイル名(省略時は標準入力)の内容を、標準出力へダンプ表示します。 fname=shift(stdin) # 引数をセットします。(デフォルトは stdin ) do_while(cnt!=0){ # {} 内を実行して、cntが 0 でない限りループを繰り返します。 buf,cnt=read(fname,16) # ファイル fname から16バイト読み込み、データとバイト数をセットします。 for(i=0;i cnt;i++) # 1バイトづつ16進数表示を行います。 printf("%02X ",peek(buf,i)) # 関数 peek() は、バイナリデータ buf 内の i 番目のデータを取り出します。 print("\n") }
https://w.atwiki.jp/rffbl22/pages/94.html
Gribのバイナリ出力 Gribファイルのバイナリ出力には、wgribコマンドを用いる wgrib 入力gribファイル | grep " 入力gribファイルの変数名 " | wgrib -i -bin -nh 入力gribファイル -o 出力バイナリファイル JRA25/JCDAS anl_p出力用シェルスクリプト例(grib_anlp_bin.sh) #!/bin/bash #Intial settings------------------------ var=PRMSL #variable name (PRMSL, TMP, UGRD, VGRD, SPFH, HGT) year=2010 #year start_month=06 #start month end_month=06 #end month start_day=01 #start day end_day=31 #end day #--------------------------------------- for month in $(seq ${start_month} ${end_month}) do for day in $(seq ${start_day} ${end_day}) do for hour in 00 06 12 18 do if [ ${month} -le 09 ] ; then mm=0${month} else mm=${month} fi if [ ${day} -le 09 ] ; then dd=0${day} else dd=${day} fi infile=anl_p.${year}${mm}${dd}${hour} outfile=${var}${year}${mm}${dd}${hour}.bin num=`wgrib ${infile} | grep " ${var} " | wgrib -i -bin -nh ${infile} -o ${outfile} | wc -l` echo "Time="${year}/${mm}/${dd}/${hour}UTC ", Variable="${var} ", Layer num="${num} done done done 複数月に渡って出力する場合に、データがないと"could not open file "とエラー表示されるが、次のファイルに継続されるだけなので問題なし。 例えば5、6、7月というように出力すると6月は31日がないのでエラーが表示される。 NCEP/NCAR FNL
https://w.atwiki.jp/2ndanniver/pages/23.html
第10問から 第10問目の勇者が帰還したころ、公式がうpされた。 問題概要 公式がうp トップページに 「3つのファイルはここにある by 失踪者」 と書かれていた 第10問で見つかった3つのガムテ 【Z0P.jayro】 【Z0G.check】 【Z01.jack】 あんたがたの考え 上の3つのよくわからん文字列を公式URLの末尾に付けてアクセスしたところ http //missingman.yh.land.to/Z0P.jayro http //missingman.yh.land.to/Z0G.check http //missingman.yh.land.to/Z01.jack には、よくわからないファイル(らしきもの)が置かれていた 66 名前:愛のVIP戦士[] 投稿日:2007/02/26(月) 18 41 10.20 ID H/okO+6F0 http //www.vipper.org/vip451901.zip.html とりあえず結合 起動したら.NET framework2.0が必要って出た インスコしてくる このプログラムを実行すると 78 名前:愛のVIP戦士[] 投稿日:2007/02/26(月) 18 45 44.45 ID CiQUyrNr0 http //www.vipper.net/vip187128.jpg.html こんなの起動した ここからCD-ROMの出番。 ところでバイナリ結合の方法 480 名前:愛のVIP戦士[] 投稿日:2007/02/26(月) 20 21 59.75 ID H/okO+6F0 469 44 48 66 http //www.vector.co.jp/soft/win95/util/se043122.html 44 名前:愛のVIP戦士[] 投稿日:2007/02/26(月) 18 34 41.87 ID H/okO+6F0 ぱっと見た感じでは、 jack、check、jayroの順に接合でよさそうな感じだが 48 名前:愛のVIP戦士[] 投稿日:2007/02/26(月) 18 35 42.79 ID H/okO+6F0 実行ファイルの名前はsissou.exeのようだ 66 名前:愛のVIP戦士[] 投稿日:2007/02/26(月) 18 41 10.20 ID H/okO+6F0 http //www.vipper.org/vip451901.zip.html とりあえず結合 起動したら.NET framework2.0が必要って出た インスコしてくる
https://w.atwiki.jp/wadaisenryaku/pages/729.html
目次 目次 バイナリ編集概要 セクタ構造 巨大なデータの差し替えは困難 セクタ構造2 ファイルインデックス 改造におけるインデックス利用 バイナリ編集概要 CDイメージをバイナリエディタで編集することで、ゲームデータの改変が可能。 改造コードでは実現が難しい、セーブデータだけでは保持されないデータの改造はもちろん、 大規模編集によるオリジナルデータの作成なども可能となる。 基本的な考えは改造コードと同じであり、 ファイルの位置、データの位置、値の役割を把握した上で、そこのデータを書き換えれば望みの結果を得られる。 しかし改造範囲が大規模になると、CD-ROM形式の特有のデータの並び方など、いくつか把握しておくべき論点が生じる。 セクタ構造 CDイメージをマウントし、エキスプローラ等で開くと、中の「実データ」を閲覧・抽出することができる。 この時のファイルAのデータ列の状態を以下とする。 ファイルA しかし、CDイメージそのものをバイナリエディタで開き、データAの部分に移動すると、 A1 仕切 A2 仕切 A3 仕切 A4 ・・・ このように、データAが一定単位ごとに別の「仕切りデータ」で分割されていることが分かる。 この時、A1、A2、A3・・・を結合していくとファイルAと一致する。 これがCD-ROM形式におけるセクタの構造である。 仕切りデータのサイズは304(130h)バイト +仕切られた実データの分割単位は2048(800h)バイト =これがセットで1セクタ、計2352(930h)バイトとなる。 以下は304バイトの仕切りデータの見本。実際にはセクタ毎のヘッダー、エラー訂正符号などの役割を担う。 XXにはランダムなデータが入るが、先頭と末尾に特徴的な00とFFの並びが現れるため、慣れれば見分けることができる。 XX XX XX XX 00 00 00 00 00 00 00 00 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX FF FF FF FF FF FF FF FF FF FF XX XX XX XX XX 仕切りデータそのものは全く解析できていないが、する必要も恐らくない。 少なくともこれまでの試行では、仕切りデータを弄ることなく改造データは上手く動いている。 巨大なデータの差し替えは困難 差し替えやデータ移動の量が多くなる場合は面倒な事になる。例えばファイルAを改造したファイルA'をAの位置に組み込む場合、 A'を2048バイトずつのA'1、A'2、A'3・・・に分割しつつ、A1、A2、A3の位置に正確にコピペしていく作業が必要だ。 例えばBGMデータも上記原理で理論上は差し替え可能だが、ファイルサイズが巨大で数千セクタにも及ぶため、 手動で分割コピペしていくのは非現実的だ。よって改造は小~中規模に抑えるのが無難である。 プログラムで上記処理を行うツールが作れるならそれが一番だが、できない人は苦労することになる。 (ちなみに筆者はキーマクロを利用した自動コピペ法を考えたことがある) 仕切りデータの構造を無視してA'の実データ列を丸ごと貼り付けてしまうことも不可能ではない(SSFが読んでくれた事例もある)が、 少なくともCD-ROMセクタ構造は失われ、Windowsエキスプローラではフォルダごと読めなくなるし、 ゲーム内でも不測のエラーが起こる可能性は十分にあり、あまり推奨できる方法ではない。 セクタ構造2 以上のようにファイルの差し替えにあたっては面倒な方式だが、利点もある。 ファイルの先頭データは必ずセクタの先頭に来るという特徴がある。 つまり、仕切りデータに着目するとファイルの開始位置が特定しやすい。 よってセクタで区切られた空間(実ファイルデータに使える空間)は2048バイトの倍数になる。 実際のファイルサイズが2048の倍数に満たない場合、余りの領域は00で満たされる。 よって00の羅列に着目するとファイルの終端位置を見積もれる場合もある。 ・・・ An-1 仕切 An(終端) 余り(0000...) 仕切 B1 仕切 B2 ・・・ 次にCDイメージにおける一番初めのセクタの実データ位置だが、 実はアドレス0(冒頭)ではなく、アドレス10h(17バイト目~)である。 以下に鋼鉄のアドレス0~のデータを載せる。 00 FF FF FF FF FF FF FF FF FF FF 00 00 02 00 01 53 45 47 41 20 53 45 47 41 53 41 54 55 52 4E 20 53 45 47 41 20 45 4E 54 45 52 50 52 49 53 45 53 47 53 39 30 32 35 20 20 20 20 56 31 2E 30 30 30 31 39 39 35 30 38 32 34 43 44 2D 31 2F 31 20 20 4A 54 20 20 20 20 20 20 20 20 20 20 20 20 20 20 4A 4D 20 20 20 20 20 20 20 20 20 20 20 20 20 20 57 4F 52 4C 44 20 41 44 56 41 4E 43 45 44 20 44 41 49 53 45 4E 52 59 41 4B 55 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ~ 2行目(アドレス10h)~8行目「53 45 47 41 20 53 45 47 ~ 53 45 4E 52 59 41 4B 55」は ASCII形式で「SEGA SEGASATURN ~ WORLD ADVANCED DAISENRYAKU」を表すが、 その前の「00 FF FF FF FF FF FF FF FF FF FF 00 00 02 00 01」は先ほどの304バイトの仕切りデータの末尾16バイトに相当する。 つまり304バイトのうち、末尾16バイトは実はセクタのヘッダで、残りの288バイトはフッタということになる。 以上により、ファイルの実データは 10h+n×(2048+304) の位置にあると分かる。 これが次のファイルインデックスの話に繋がる。 ファイルインデックス アドレスB7D0~に移動すると、CDイメージ内のファイル名などが書かれたデータに遭遇する。 22 00 14 00 00 00 00 00 00 14 00 20 00 00 00 00 20 00 5F 08 18 0F 02 22 14 02 00 00 01 00 00 01 01 00 22 00 14 00 00 00 00 00 00 14 00 20 00 00 00 00 20 00 5F 08 18 0F 02 22 14 02 00 00 01 00 00 01 01 01 2E 00 31 00 00 00 00 00 00 31 14 1A 02 00 00 02 1A 14 5F 08 18 0F 02 22 14 00 00 00 01 00 00 01 0C 30 30 30 30 30 30 30 30 2E 42 49 4E 00 2C 00 23 8E 01 00 00 01 8E 23 00 C0 2F 00 00 2F C0 00 5F 08 18 0F 02 22 14 00 00 00 01 00 ~ 上記のうち冒頭のデータ(22 00 14 00~)は解説しづらいため、5行目途中の「2E 00 31 00 ~」から解説する。 結論から言えばこの「2E 00 31 00 ~」は「00000000.bin」を示すインデックスである。 2E: インデックス1件のデータサイズ。この場合は2Eの箇所から数えて46バイトでひとまとまり。 どうやら必ず2の倍数になっているらしい(後述) 00: 不明。多分特に意味のないクッションデータ。 31 00 00 00 00 00 00 31: 実データが格納されているセクタ番号。 リトルエンディアン4バイト(31 00 00 00)と、ビッグエンディアン4バイト(00 00 00 31)、 同じ値が両方の形式で格納されている。(エンディアンについてはWikipediaを参照) セクタ番号は16進で0から数えるため、31h+1=50番目のセクタを表す。先述の計算式により、 このファイルは 10h+31h×(2048+304)=アドレス1C240 以降にあるということになる。 14 1A 02 00 00 02 1A 14: 実データのファイルサイズ。 これもリトルエンディアン4バイトとビッグエンディアン4バイトで格納されている。 つまりこの場合は 21A14=137,748バイト。 5F 08 18 0F 02 22: 1バイトごとに年月日時分秒を表す。 作成日時と更新日時の区別はないため、エクスプローラ上では両方この日付時刻が表示される。 これをそのまま10進にすると(19)95/8/24 15 02 34である。 しかし実際は(日本では)これに+4時間した1995/8/24 19 02 34と表示される。 元データの15 02はUTC(世界標準時)でもないので、なぜこうなのかは良く分かっていない。 ※ なお、+4時間した結果日付が変わるようであれば繰り上げて表示される。 (例:作戦ファイル、FILM0000.CPK、日本時1995/8/16 2 46、元データは8/15 22 46) 14 00 00 00 01 00 00 01: 今のところ不明。ただしファイルでなくフォルダの場合は2バイト目が02に変化することは判明している。 0C:次に続くファイル名の文字数(データサイズ)つまり0C=12文字。 30 30 30 30 30 30 30 30 2E 42 49 4E:「00000000.bin」←ぴったり12文字 ASCII文字コード形式でファイル名を表す。ただしこのファイルは違うが、末尾になぜか「;1」(3B 31)が付く場合が殆どで、 その場合はファイル文字数も「;1」分までカウントされる(エクスプローラ上では「;1」は表示されない)。 00:多分ただのクッションデータ。ここまで46バイト、直後は次のインデックスになる。 なおこの00は無い場合がある。先述の通りインデックス1件のデータは必ず偶数になっている模様だが、 変動要因であるファイル名文字数自体は偶奇どちらもありうる。そこでこの00があるかないかで偶数に調整しているようだ。 改めて冒頭の「22 00 14 00~」を解析すると、 インデックスデータ量22バイト、セクタ番号14h(アドレスB7D0)、ファイルサイズ8,192バイト(4セクタ分)、 時刻(日本時)1995/8/24 19 02 34、続いて14 02 00 00 01 00 00 01(2バイト目が02なのでフォルダ属性を表す)、 ファイル名なし(ファイル名文字数は0ではなく1とされている) ※ 以上がなぜかほぼ2回繰り返されており、その後00000000.binのインデックスへと続く。 アドレスB7D0はこのファイルインデックスの冒頭と一致する。つまりこのCD-ROMの「ルートフォルダ」と推定される。 改造におけるインデックス利用 改造目的でインデックスを使うのであれば、 ・セクタ番号: 実データ格納アドレスを計算、あるいは参照セクタそのものを変えてしまう ・ファイルサイズ: 改造対象のファイルサイズを増やしたいときにここの値を変える などが重要になるだろう。 特にセクタ番号の情報は改造したいファイルの冒頭データをコピー → 検索だけでは限界がある場合に有効だ。 ただしファイルサイズを増やすのには上限がある(2048の倍数を超えると次のファイルのセクタ領域に行ってしまう) ので、より大規模な改造としては、CDイメージ全体の末尾にある大量の空白セクタを利用して、 ここに新たにファイルを書き込み、それをインデックスから参照させるといったこともできるかもしれない。 (あまり大きいファイルだと当面は困難ではあるが)
https://w.atwiki.jp/wadaisenryaku2/pages/598.html
目次 目次 バイナリ編集概要 セクタ構造 巨大なデータの差し替えは困難 セクタ構造2 ファイルインデックス 改造におけるインデックス利用 バイナリ編集概要 CDイメージをバイナリエディタで編集することで、ゲームデータの改変が可能。 改造コードでは実現が難しい、セーブデータだけでは保持されないデータの改造はもちろん、 大規模編集によるオリジナルデータの作成なども可能となる。 基本的な考えは改造コードと同じであり、 ファイルの位置、データの位置、値の役割を把握した上で、そこのデータを書き換えれば望みの結果を得られる。 しかし改造範囲が大規模になると、CD-ROM形式の特有のデータの並び方など、いくつか把握しておくべき論点が生じる。 セクタ構造 CDイメージをマウントし、エキスプローラ等で開くと、中の「実データ」を閲覧・抽出することができる。 この時のファイルAのデータ列の状態を以下とする。 ファイルA しかし、CDイメージそのものをバイナリエディタで開き、データAの部分に移動すると、 A1 仕切 A2 仕切 A3 仕切 A4 ・・・ このように、データAが一定単位ごとに別の「仕切りデータ」で分割されていることが分かる。 この時、A1、A2、A3・・・を結合していくとファイルAと一致する。 これがCD-ROM形式におけるセクタの構造である。 仕切りデータのサイズは304(130h)バイト +仕切られた実データの分割単位は2048(800h)バイト =これがセットで1セクタ、計2352(930h)バイトとなる。 以下は304バイトの仕切りデータの見本。実際にはセクタ毎のヘッダー、エラー訂正符号などの役割を担う。 XXにはランダムなデータが入るが、先頭と末尾に特徴的な00とFFの並びが現れるため、慣れれば見分けることができる。 XX XX XX XX 00 00 00 00 00 00 00 00 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX FF FF FF FF FF FF FF FF FF FF XX XX XX XX XX 仕切りデータそのものは全く解析できていないが、する必要も恐らくない。 少なくともこれまでの試行では、仕切りデータを弄ることなく改造データは上手く動いている。 巨大なデータの差し替えは困難 差し替えやデータ移動の量が多くなる場合は面倒な事になる。例えばファイルAを改造したファイルA'をAの位置に組み込む場合、 A'を2048バイトずつのA'1、A'2、A'3・・・に分割しつつ、A1、A2、A3の位置に正確にコピペしていく作業が必要だ。 例えばBGMデータも上記原理で理論上は差し替え可能だが、ファイルサイズが巨大で数千セクタにも及ぶため、 手動で分割コピペしていくのは非現実的だ。よって改造は小~中規模に抑えるのが無難である。 プログラムで上記処理を行うツールが作れるならそれが一番だが、できない人は苦労することになる。 (ちなみに筆者はキーマクロを利用した自動コピペ法を考えたことがある) 仕切りデータの構造を無視してA'の実データ列を丸ごと貼り付けてしまうことも不可能ではない(SSFが読んでくれた事例もある)が、 少なくともCD-ROMセクタ構造は失われ、Windowsエキスプローラではフォルダごと読めなくなるし、 ゲーム内でも不測のエラーが起こる可能性は十分にあり、あまり推奨できる方法ではない。 セクタ構造2 以上のようにファイルの差し替えにあたっては面倒な方式だが、利点もある。 ファイルの先頭データは必ずセクタの先頭に来るという特徴がある。 つまり、仕切りデータに着目するとファイルの開始位置が特定しやすい。 よってセクタで区切られた空間(実ファイルデータに使える空間)は2048バイトの倍数になる。 実際のファイルサイズが2048の倍数に満たない場合、余りの領域は00で満たされる。 よって00の羅列に着目するとファイルの終端位置を見積もれる場合もある。 ・・・ An-1 仕切 An(終端) 余り(0000...) 仕切 B1 仕切 B2 ・・・ 次にCDイメージにおける一番初めのセクタの実データ位置だが、 実はアドレス0(冒頭)ではなく、アドレス10h(17バイト目~)である。 以下に鋼鉄のアドレス0~のデータを載せる。 00 FF FF FF FF FF FF FF FF FF FF 00 00 02 00 01 53 45 47 41 20 53 45 47 41 53 41 54 55 52 4E 20 53 45 47 41 20 45 4E 54 45 52 50 52 49 53 45 53 47 53 39 30 32 35 20 20 20 20 56 31 2E 30 30 30 31 39 39 35 30 38 32 34 43 44 2D 31 2F 31 20 20 4A 54 20 20 20 20 20 20 20 20 20 20 20 20 20 20 4A 4D 20 20 20 20 20 20 20 20 20 20 20 20 20 20 57 4F 52 4C 44 20 41 44 56 41 4E 43 45 44 20 44 41 49 53 45 4E 52 59 41 4B 55 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ~ 2行目(アドレス10h)~8行目「53 45 47 41 20 53 45 47 ~ 53 45 4E 52 59 41 4B 55」は ASCII形式で「SEGA SEGASATURN ~ WORLD ADVANCED DAISENRYAKU」を表すが、 その前の「00 FF FF FF FF FF FF FF FF FF FF 00 00 02 00 01」は先ほどの304バイトの仕切りデータの末尾16バイトに相当する。 つまり304バイトのうち、末尾16バイトは実はセクタのヘッダで、残りの288バイトはフッタということになる。 以上により、ファイルの実データは 10h+n×(2048+304) の位置にあると分かる。 これが次のファイルインデックスの話に繋がる。 ファイルインデックス アドレスB7D0~に移動すると、CDイメージ内のファイル名などが書かれたデータに遭遇する。 22 00 14 00 00 00 00 00 00 14 00 20 00 00 00 00 20 00 5F 08 18 0F 02 22 14 02 00 00 01 00 00 01 01 00 22 00 14 00 00 00 00 00 00 14 00 20 00 00 00 00 20 00 5F 08 18 0F 02 22 14 02 00 00 01 00 00 01 01 01 2E 00 31 00 00 00 00 00 00 31 14 1A 02 00 00 02 1A 14 5F 08 18 0F 02 22 14 00 00 00 01 00 00 01 0C 30 30 30 30 30 30 30 30 2E 42 49 4E 00 2C 00 23 8E 01 00 00 01 8E 23 00 C0 2F 00 00 2F C0 00 5F 08 18 0F 02 22 14 00 00 00 01 00 ~ 上記のうち冒頭のデータ(22 00 14 00~)は解説しづらいため、5行目途中の「2E 00 31 00 ~」から解説する。 結論から言えばこの「2E 00 31 00 ~」は「00000000.bin」を示すインデックスである。 2E: インデックス1件のデータサイズ。この場合は2Eの箇所から数えて46バイトでひとまとまり。 どうやら必ず2の倍数になっているらしい(後述) 00: 不明。多分特に意味のないクッションデータ。 31 00 00 00 00 00 00 31: 実データが格納されているセクタ番号。 リトルエンディアン4バイト(31 00 00 00)と、ビッグエンディアン4バイト(00 00 00 31)、 同じ値が両方の形式で格納されている。(エンディアンについてはWikipediaを参照) セクタ番号は16進で0から数えるため、31h+1=50番目のセクタを表す。先述の計算式により、 このファイルは 10h+31h×(2048+304)=アドレス1C240 以降にあるということになる。 14 1A 02 00 00 02 1A 14: 実データのファイルサイズ。 これもリトルエンディアン4バイトとビッグエンディアン4バイトで格納されている。 つまりこの場合は 21A14=137,748バイト。 5F 08 18 0F 02 22: 1バイトごとに年月日時分秒を表す。 作成日時と更新日時の区別はないため、エクスプローラ上では両方この日付時刻が表示される。 これをそのまま10進にすると(19)95/8/24 15 02 34である。 しかし実際は(日本では)これに+4時間した1995/8/24 19 02 34と表示される。 元データの15 02はUTC(世界標準時)でもないので、なぜこうなのかは良く分かっていない。 ※ なお、+4時間した結果日付が変わるようであれば繰り上げて表示される。 (例:作戦ファイル、FILM0000.CPK、日本時1995/8/16 2 46、元データは8/15 22 46) 14 00 00 00 01 00 00 01: 今のところ不明。ただしファイルでなくフォルダの場合は2バイト目が02に変化することは判明している。 0C:次に続くファイル名の文字数(データサイズ)つまり0C=12文字。 30 30 30 30 30 30 30 30 2E 42 49 4E:「00000000.bin」←ぴったり12文字 ASCII文字コード形式でファイル名を表す。ただしこのファイルは違うが、末尾になぜか「;1」(3B 31)が付く場合が殆どで、 その場合はファイル文字数も「;1」分までカウントされる(エクスプローラ上では「;1」は表示されない)。 00:多分ただのクッションデータ。ここまで46バイト、直後は次のインデックスになる。 なおこの00は無い場合がある。先述の通りインデックス1件のデータは必ず偶数になっている模様だが、 変動要因であるファイル名文字数自体は偶奇どちらもありうる。そこでこの00があるかないかで偶数に調整しているようだ。 改めて冒頭の「22 00 14 00~」を解析すると、 インデックスデータ量22バイト、セクタ番号14h(アドレスB7D0)、ファイルサイズ8,192バイト(4セクタ分)、 時刻(日本時)1995/8/24 19 02 34、続いて14 02 00 00 01 00 00 01(2バイト目が02なのでフォルダ属性を表す)、 ファイル名なし(ファイル名文字数は0ではなく1とされている) ※ 以上がなぜかほぼ2回繰り返されており、その後00000000.binのインデックスへと続く。 アドレスB7D0はこのファイルインデックスの冒頭と一致する。つまりこのCD-ROMの「ルートフォルダ」と推定される。 改造におけるインデックス利用 改造目的でインデックスを使うのであれば、 ・セクタ番号: 実データ格納アドレスを計算、あるいは参照セクタそのものを変えてしまう ・ファイルサイズ: 改造対象のファイルサイズを増やしたいときにここの値を変える などが重要になるだろう。 特にセクタ番号の情報は改造したいファイルの冒頭データをコピー → 検索だけでは限界がある場合に有効だ。 ただしファイルサイズを増やすのには上限がある(2048の倍数を超えると次のファイルのセクタ領域に行ってしまう) ので、より大規模な改造としては、CDイメージ全体の末尾にある大量の空白セクタを利用して、 ここに新たにファイルを書き込み、それをインデックスから参照させるといったこともできるかもしれない。 (あまり大きいファイルだと当面は困難ではあるが)
https://w.atwiki.jp/javastudy/pages/35.html
第7章 ★バイナリの読み書き ■バイナリファイルの読み込み手順 ①ファイルを開く FileStream(ストリームクラス)のオブジェクトを生成してファイルを読み込む FileInputStream in = new FileInputStream (“file3.dat”); ←ファイル生成 ②データを読み込む readメソッドを使用する。読み込んだ1バイトデータをint型で返す。 読み込むデータがなくなるとー1を返す。 Int c; c = in.read(); ③ファイルを閉じる close()メソッドを使用 in.close(); ■バイナリファイルの書き出し手順 ①ファイルを開く FileOutputStream(ストリームクラス)のオブジェクトを生成してファイルを書き出す FileOutputStream out = new FileOutputStream (“file4.dat”); ←この名前でファイル生成 ②データを書き出す write()メソッドを使用する。引数として与えたデータをファイルに書き出す。 引数にはint型かbyte型の値を指定 out.write(65); ③ファイルを閉じる close()メソッドを使用 out.close(); ■文字ストリームへの変換 InputStreamReader バイナリ入力→文字入力へ変換 バイナリデータを読み込むオブジェクトを引数として受け取る FileInputStream ifile = new FileInputStream(“file5.dat”); InputStreamReader in = new InputStreamReader(ifile); ↑オブジェクト名 ↑InputStreamReaderクラスのオブジェクト OutputStreamReader バイナリ出力→文字出力へ変換 バイナリデータを読み込むオブジェクトを引数として受け取る FileOutputStream ofile = new FileOutputStream(“file5.dat”); OnputStreamReader out = new OutputStreamReader(ofile); ↑オブジェクト名 ↑OutputStreamReaderクラスのオブジェクト ■ サンプルプログラム import java.io.*; class InOut { public static void main(String[] args) { try { String filename = "file.dat"; FileOutputStream out = new FileOutputStream(filename); FileInputStream file = new FileInputStream(filename); InputStreamReader in = new InputStreamReader(file); for(byte i = 1; i = 10; i++) { out.write(i); } int c; while((c = in.read()) != -1) { System.out.print(c + " "); } in.close(); out.close(); } catch (IOException e) { System.out.println("ファイルがありません。"); } } }