|
|
2014/12/28(Sun) 13:10:01|NO.66681
別スレで失礼します。
http://hsp.tv/play/pforum.php?mode=all&num=66673
で回答をいただいたあと、実験してみた結果を報告します。
結論から言うと、ファイルの追加は無理でした。
ファイルチャンクは問題なく追加できて、追加前のファイルたちも読めたのですが、追加したファイルがどうしても読めませんでした。
どうやら、ファイルチャンクに個別に書いてある4バイトの暗号化キーが曲者のようで、おそらくDPMファイル全体で整合性が取れるように、各ファイルについて生成されているんだと思います。このキーの値はDPMを作るたびに変わるようです。
追加したファイルは、この暗号化キーの整合性がとれないみたいで、まったく読めませんでした。
プログラムで作ったファイルを解析して、オフセットとかファイルサイズがバグってないかどうかも確認しましたが、どうやらだめなようです。まさか、その解析の間にバグらせた…ってことはないと信じたいです。
う〜ん、やっぱり独自フォーマットでしょうか?でも、なんにもしなくても勝手に読み込んでくれるDPMの機能は便利だし、自分で暗号化を組むと読み込みが重くなりそうだし…
なにか思いつくこととかありますか?もしよければご意見をお聞かせください。
|
|
2014/12/28(Sun) 13:43:09|NO.66682
なんか、暗号化バイナリを書き込む部分がバグってるような気がしてきたので、スクリプトを張ってみます。
なにかお気づきの点があればご指摘お願いします。
書きかけなのでかなり汚いです。ごめんなさい。
infile="a.dpm"//操作するファイル名
addFile="b.dpm"//追加するアーカイブ名
//ステップ1:ヘッダ情報を解析してみる
//ヘッダを読み込み
header=""
bload infile,header,16
//DPM宣言のチェック
if strmid(header,0,4)!"DPMX"{
dialog "DPMファイルじゃない",,"エラー"
end
}
dataChunkOffset=lpeek(header,4)//データチャンクの開始位置
totalFiles=lpeek(header,8)//中身の全ファイル数
//最後の4バイトはなにもないので終わり
sdim header,0//読んだのでもういらない
//ステップ2:ファイル情報チャンクを解析してみる
//ファイル情報チャンク全体の読み込み
sdim chunk,32*totalFiles+1
bload infile,chunk,32*totalFiles,16
pointer=0//現在のファイルポインタ
sdim filenames,20,totalFiles//ファイル名
dim filesizes,totalFiles//ファイルサイズ
dim fileoffsets,totalFiles//データチャンクからの位置
dim filekeys,totalfiles
repeat totalFiles
getstr filenames(cnt),chunk,pointer
filekeys(cnt)=lpeek(chunk,pointer+20)
filesizes(cnt)=lpeek(chunk,pointer+28)
fileoffsets(cnt)=lpeek(chunk,pointer+24)
pointer+=32
loop
//次に、追加するDPMファイルの情報を読む
//ヘッダを読み込み
header=""
bload addFile,header,16
//DPM宣言のチェック
if strmid(header,0,4)!"DPMX"{
dialog "DPMファイルじゃない",,"エラー"
end
}
dataChunkOffset2=lpeek(header,4)//データチャンクの開始位置
totalFiles2=lpeek(header,8)//中身の全ファイル数
sdim header,0
//ファイル情報チャンク全体の読み込み
sdim chunk2,32*totalFiles2+1
bload addFile,chunk2,32*totalFiles2,16
pointer=0//現在のファイルポインタ
sdim filenames2,20,totalFiles2//ファイル名
dim filesizes2,totalFiles2//ファイルサイズ
dim fileoffsets2,totalFiles2//データチャンクからの位置
dim filekeys2,totalfiles2
repeat totalFiles2
getstr filenames2(cnt),chunk2,pointer
filekeys2(cnt)=lpeek(chunk2,pointer+20)
filesizes2(cnt)=lpeek(chunk2,pointer+28)
fileoffsets2(cnt)=lpeek(chunk2,pointer+24)
pointer+=32
loop
//これで全データの解析終了
//ここまでは正常動作
//新しいヘッダおよびファイル情報チャンクの作成
finalFiles=totalFiles+totalFiles2//合計のファイル数
sdim header,17+(32*finalFiles)
header="DPMX"//最初のおまじない
offset=16+(32*finalFiles)//最終的なオフセット
lpoke header,4,offset
lpoke header,8,finalFiles
//ヘッダ完成
//続いて、追加するファイルのオフセット値を書き換え
exist inFile
s=strsize
newoffset=s-offset+32//追加する最初のファイルの位置
pointer=24
fileCount=0
repeat totalFiles2//書き換え開始
tmp=newoffset//開始位置をセット
if fileCount:{//開始位置からずらさないとだめな時
repeat fileCount
tmp+=fileoffsets(cnt)
loop
}
lpoke chunk2,pointer,tmp//変更したオフセットを書き込み
pointer+=32
fileCount++
loop
//ファイル情報チャンクを書いていく
//まずは追加前のチャンクを全部展開する
pointer=16
repeat 32*totalFiles
poke header,pointer,peek(chunk,cnt)
pointer++
loop
//次に、追加したチャンクを展開する
repeat 32*totalFiles2
poke header,pointer,peek(chunk2,cnt)
pointer++
loop
//ファイルチャンクができた
//とりあえず保存する
bsave "test.dpm",header
//次は、データをどんどん書いていく
//1MBずつ書く
//まずは追加前のほうから
pointer=dataChunkOffset//読むほうのポインタ
pointer2=offset//書くほうのポインタ
exist inFile//全体のサイズ
size=strsize
repeat//データがなくなるまで繰り返す
remaining_bites=size-pointer
if remaining_bites=0:break
if remaining_bites>1024000:{
read=1024000
}else{
read=remaining_bites
}
sdim tmp,read+1
bload inFile,tmp,read,pointer
bsave "test.dpm",tmp,read,pointer2
pointer+=read
pointer2+=read
loop
//追加した部分
pointer2=newoffset
pointer=dataChunkOffset2
exist addFile//全体のサイズ
size=strsize
repeat//データがなくなるまで繰り返す
remaining_bites=size-pointer
if remaining_bites=0:break
if remaining_bites>1024000:{
read=1024000
}else{
read=size-pointer
}
sdim tmp,read+1
bload inFile,tmp,read,pointer
bsave "test.dpm",tmp,read,pointer2
pointer+=read
pointer2+=read
loop
dialog "done"
end
| |
|
2014/12/28(Sun) 17:39:58|NO.66684
src_dpm = "src.dpm" // 入力
add_dpm = "add.dpm" // 追加
dst_dpm = "dst.dpm" // 出力
// 入力分の情報取得
exist src_dpm
src_size = strsize
if src_size < 0 {
dialog "入力分DPMが読み込めません", 1
end
}
sdim src_data, src_size
bload src_dpm, src_data
// 情報取得
src_hsize = lpeek(src_data, 4) - 16
src_fnum = lpeek(src_data, 8)
src_dsize = src_size - src_hsize - 16
// 追加分の情報取得
exist add_dpm
add_size = strsize
if add_size < 0 {
dialog "追加分DPMが読み込めません", 1
end
}
sdim add_data, add_size
bload add_dpm, add_data
// 情報取得
add_hsize = lpeek(add_data, 4) - 16
add_fnum = lpeek(add_data, 8)
add_dsize = add_size - add_hsize - 16
// 出力ファイル作成
dst_hsize = src_hsize + add_hsize
dst_fnum = src_fnum + add_fnum
dst_dsize = src_dsize + add_dsize
dst_size = 16 + dst_hsize + dst_dsize
// ヘッダ作成
sdim dst_data, dst_size
lpoke dst_data, 0, 0x584D5044
lpoke dst_data, 4, 16 + dst_hsize
lpoke dst_data, 8, dst_fnum
lpoke dst_data, 12, 0x00000000
// チャンク連結
offset = 16
memcpy dst_data, src_data, src_hsize, offset, 16 : offset += src_hsize
memcpy dst_data, add_data, add_hsize, offset, 16 : offset += add_hsize
memcpy dst_data, src_data, src_dsize, offset, 16 + src_hsize : offset += src_dsize
memcpy dst_data, add_data, add_dsize, offset, 16 + add_hsize : offset += add_dsize
// 追加分の各ファイルのデータオフセット修正
repeat add_fnum
offset = 16 + src_hsize + 32 * cnt + 24
lpoke dst_data, offset, lpeek(dst_data, offset) + src_dsize
loop
// 書き出し
bsave dst_dpm, dst_data
こちらで少し書いてみました。
エラーチェックなどは殆どしていませんので実用には耐えないと
思いますが、プログラム作成の参考になれば幸いです。
一応3.22で正常に動作することを確認しました。
| |
|
2014/12/28(Sun) 19:56:18|NO.66688
ほ ほんとだ、動いてますね。どこがいけなかったんだろう…
提示いただいたスクリプトにエラーチェック入れたり、DPMが大きくなったときのためのメモリ節約機能を入れたりして、システムに組み込んでみたいと思います。
バイナリ操作はまだ数度しかやっていなかったので、スクリプトの中身も勉強になりました。ありがとうございます。
|
|
2014/12/28(Sun) 22:00:28|NO.66690
できました。
Flatさんのソースを参考にしながら、自分自身勉強したかったので、全部書き直しました。前のソースは、DPM解析の実験段階から使いまわしてたので、コードもそれなりにスマートに成りました。
とりあえず、使いやすいようにモジュールにしました。それから、アーカイブファイル全体を一気に読み込まなくなったので、使用メモリがものすごく減りました。
報告と、ほかの皆様へのご参考をかねて張っておきます。
#module dpmRebuildor
//DPMリビルドモジュール
#deffunc dpm_rebuild str in, str add, str out
/*
P1:オリジナルアーカイブ
P2:追加アーカイブ
P3:出力先アーカイブ
戻り値
1:成功
-1:パラメータ欠落
-2:オリジナルアーカイブへのアクセス失敗
-3:追加アーカイブへのアクセス失敗
※オリジナルと追加用アーカイブは、必ず同じ暗号化キーで暗号化されていなければなりません。
*/
if in="" or add="" or out="":return -1
//オリジナルアーカイブのヘッダを読み取り
sdim header,17
exist in
in_size=strsize
if in_size<=0:return -2
bload in,header,16
if strmid(header,0,4)!"DPMX":return 0
in_offset=lpeek(header,4)
in_fnum=lpeek(header,8)
in_datasize=in_size-in_offset
//あとで使うので、ファイルチャンクを読み込んでおく
sdim in_chunk,(32*in_fnum)+1
bload in,in_chunk,32*in_fnum,16
//追加アーカイブのヘッダを読み取り
sdim header,17
exist add
add_size=strsize
if add_size<=0:return -3
bload add,header,16
add_offset=lpeek(header,4)
add_fnum=lpeek(header,8)
add_datasize=add_size-add_offset
sdim add_chunk,(32*add_fnum)+1
bload add,add_chunk,32*add_fnum,16
//ファイルオフセットの修正
pointer=24
repeat add_fnum
lpoke add_chunk,pointer,lpeek(add_chunk,pointer)+in_datasize
pointer+=32
loop
//出力ファイル作成
sdim dstb,17+(32*in_fnum)+(32*add_fnum)
dstb="DPMX"
out_offset=16+(32*in_fnum)+(32*add_fnum)
lpoke dstb,4,16+(32*in_fnum)+(32*add_fnum)
lpoke dstb,8,in_fnum+add_fnum
memcpy dstb,in_chunk,32*in_fnum,16,0
memcpy dstb,add_chunk,32*add_fnum,16+(32*in_fnum),0
bsave out,dstb
sdim dstb,0
//データチャンクのバイナリを、1MBずつ拾って書き込む
rp=in_offset//読み込みポインタ
wp=out_offset//書き込みポインタ
repeat
remaining=in_size-rp
if remaining=0:break
if remaining>1024000:{
read=1024000
}else{
read=remaining
}
sdim d,read+1
bload in,d,read,rp
bsave out,d,read,wp
rp+=read:wp+=read
loop
sdim d,0
rp=add_offset
wp=out_offset+in_datasize
repeat
remaining=add_size-rp
if remaining=0:break
if remaining>1024000:{
read=1024000
}else{
read=remaining
}
sdim d,read+1
bload add,d,read,rp
bsave out,d,read,wp
rp+=read:wp+=read
loop
sdim d,0
//リビルド終了
return 1
#global
| |
|