〜 ソフトウェア 〜
圧縮されたZipファイルのファイルリストを取得 (要UNZIP32.DLL)

WindowsXPからは標準機能でZip書庫への追加や展開ができるようになりましたが、
ココでは昔ながらのアーカイバーで利用されていたZip書庫解凍用のUnZip32.dllを用いて
HSPでZipファイルを展開してみるサンプルを紹介します。
このUnZip32.dllがない場合は当モジュールを使用して正常に書庫を解凍できませんので、
統合アーカイバプロジェクト等から事前にダウンロードしておいてください。

今回は主にZip書庫ファイルを操作する為に必要な初期化処理の説明と、
Zip書庫ファイルに含まれているファイル一覧取得について説明します。
Zip書庫ファイルに含まれているファイル一覧を取得する際、
HSP3ではdup命令でクローン変数を作成していますが、
HSP2ではモジュール命令に渡した変数とモジュール内のdup命令で作成した変数とが
一致しない為にパラメータで渡したはずの変数に代入することができませんので、
直接代入する方法で回避しています。

モジュール命令の使い方を軽く説明しておきます。
まずは初期化としてzip_initを一度だけ呼び出しましょう。
当モジュールで使用しているUnZip32.dllがシステムに入ってない場合は、
statに0が、使える場合は百の位をメジャー・十と一の位をマイナーとしたバージョンが返ります。

次にzip_selで解凍の対象とするZipファイルパスを指定します。
命令内部ではファイルリストを取得するzip_findfileが使用されており、
解凍できるZipファイルを指定していたならファイルリストのバイト数がstatに返ります。
尚、ファイルリストとは、Zipファイル内に入っているファイル名情報を格納した一覧のことです。

このファイルリストを表示するには、
リスト用変数「filelist@m0」を直接呼び出しても良いのですが、
グローバル領域からモジュール領域の変数に直接アクセスすることは好ましくないので、
用意したzip_getlistでファイルリスト情報格納先変数を指定して受け取りましょう。

zip_selで対象となるZipファイルを指定すると、
内部で自動的にzip_findfileを呼び出してファイリストの取得まで行う処理を内部で行っていますが、
ファイルリストに格納するファイルの拡張子またはファイル名を指定したい時は、
zip_findfileのパラメータに拡張子やファイル名の一部とワイルドカードを指定して再度実行してください。
複数の拡張子を指定する際は半角スペースで区切ってください。
複数のファイルパスを指定する際にパスの一部を含んでいるなら、
ファイルパスをダブルクォーテーションで囲んで指定すると良いでしょう。
尚、zip_selから呼び出す際は全ての拡張子を示す「*」を指定してます。

zip_findfileの内部ではzip_waitzip_getcountが使われています。
zip_waitはその他のアプリケーション等でUnZip32.dllが使われていると
同時に使用することができませんので、ソチラの処理が終わるまで当モジュールの取得処理を中断します。
何らかの都合で実行終了が通知されない場合に備えて無限で待機することはありません。
6,553,500ミリ秒(約109分)待っても実行中と判断された場合は、
フリーズしてしまうことを防ぐ為にエラーとして処理を中断するようにしています。

zip_getcountはアイテム数を取得するもので、
アイテムは「Zipファイルの格納ファイル」または「取得したファイルリスト」のどちらかを選択できます。
Zipファイル内にフォルダが含まれていたり、ファイル名や拡張子を限定して取得している場合は、
Zipファイルの格納ファイル数=ファイルリスト数とはなりません。

具体的な使い方は下記のサンプルを参照してください。
	

zip_init
[パラメータなし]バージョンを取得するだけである為、パラメータは必要ない。
プログラム起動後に一度だけ実行する必要がある。

zip_wait
[パラメータなし]処理待ちするだけである為、パラメータは必要ない。
尚、処理可能状態になれば0が、処理できないままなら−1がstatに返る。

zip_getcount 受取先変数, 取得タイプ
受取先変数取得したカウント値(失敗:-1, 成功:アイテム数)の受取先とする数値型変数を指定する。
取得タイプ取得するタイプ(0:格納ファイル数, 1:ファイルリスト行数)を指定する。

zip_findfile 絞込条件
絞込条件ファイルリストに格納するファイル名の一部または拡張子とワイルドカードを指定する。
半角スペースを含むと複数の条件を指定したことになるので、
ファイル名の一部に半角スペースを含んでいるものを指定する時はダブルクォーテーションで囲む。
正常に指定したなら0が、失敗なら−1がstatに返る。

zip_sel zipファイル
zipファイル解凍対象となるzip書庫ファイルパスを指定する。
尚、内部でzip_findfileを使用している為、zip_selより前にzip_findfileを定義すること。
その際のファイルリスト絞込条件は「*」全ファイルである。
正常に指定したならファイルリストのバイト数が、失敗なら−1がstatに返る。

zip_getlist 受取先変数
受取先変数ファイルリストの受取先となる文字列型変数を指定する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
	ll_libload unzip32, "UnZip32.dll"
	ll_getproc UnZipCloseArchive, "UnZipCloseArchive", unzip32
	ll_getproc UnZipFindFirst, "UnZipFindFirst", unzip32
	ll_getproc UnZipFindNext, "UnZipFindNext", unzip32
	ll_getproc UnZipGetFileCount, "UnZipGetFileCount", unzip32
	ll_getproc UnZipGetFileName, "UnZipGetFileName", unzip32
	ll_getproc UnZipGetOriginalSize, "UnZipGetOriginalSize", unzip32
	ll_getproc UnZipGetRunning, "UnZipGetRunning", unzip32
	ll_getproc UnZipGetVersion, "UnZipGetVersion", unzip32
	ll_getproc UnZipOpenArchive, "UnZipOpenArchive", unzip32

#module
#deffunc zip_init
	mref stt, 64
	zipver = 0
	if UnZipGetVersion@ {
		// バージョン取得[百の位がメジャー][一・十の位がマイナー]
		ll_callfnv UnZipGetVersion@ : ll_ret zipver
		poke zipver, 2
		stt = zipver ! 0
	}
	return

#deffunc zip_wait
	mref stt, 64
	repeat 0xFFFF
		ll_callfnv UnZipGetRunning@ : ll_ret prm // UnZip32.DLLの稼働状況取得
		if prm = 0 : stt = 1 : break
		wait 10
	loop
	stt = (stt ! 1) * -1
	return

#deffunc zip_getcount val, int
	mref count, 16 : mref type, 1
	mref stt, 64
	if zipver = 0 : stt = -1 : return : else : stt = 0
	if type {
		notesel filelist
		notemax count
	} else {
		ll_getptr zipfile : ll_ret prm
		ll_callfunc prm, 1, UnZipGetFileCount@ : ll_ret count // 格納ファイル総数を取得
	}
	return

#deffunc zip_findfile str
	mref extension, 32
	mref stt, 64
	if zipver = 0 : stt = -1 : return
	zip_wait
	if stat : stt = -1 : return
	sdim s, 256
	zip_getcount prm
	if prm > 0 {
		sdim filelist, prm * 256
		dim sizelist, prm
	} else : stt = -1 : return
	prm = 0
	ll_getptr zipfile : ll_ret prm.1
	prm.2 = 0x02800000 // 2000000:M_BAR_WINDOW_OFF, 800000:M_ERROR_MESSAGE_OFF
	ll_callfunc prm, 2, UnZipOpenArchive@ : ll_ret harc // Zipファイルにアクセスできるようオープン
	notesel filelist
	j = 0
	repeat
		if cnt {
			ll_callfunc, harc, 1, UnZipFindNext@ // 次の格納ファイルを返す
		} else {
			prm = harc
			ll_getptr extension : ll_ret prm.1
			ll_callfunc, prm, 2, UnZipFindFirst@ // 最初の格納ファイルを返す
		}
		ll_ret prm.3
		if prm.3 = -1 : break
		ll_getptr s : ll_ret prm.1
		prm.2 = 256
		ll_callfunc, prm, 3, UnZipGetFileName@ // 格納ファイル名を取得
		ll_callfunc, prm, 1, UnZipGetOriginalSize@ : ll_ret prm.3 // 格納ファイルの元のサイズを取得
		if prm.3 > 0 : sizelist.j = prm.3 : noteadd s // フォルダは無視
	loop
	ll_callfunc, harc, 1, UnZipCloseArchive@ // Zipファイルをクローズ
	notemax prm
	stt = ((prm ! 0) = 0) * -1
	return

#deffunc zip_sel str
	mref file, 32
	mref stt, 64
	if zipver = 0 : stt = -1 : return
	zipfile = file
	zip_findfile "*"
	if stat ! -1 : strlen stt, filelist
	return

#deffunc zip_getlist val
	mref list, 24
	list = filelist // 参照変数が変わるので dup だとうまく行かない
	return
#global

	dialog "zip", 16, "zipファイル"
	if stat = 0 : end
	zip_init
	zip_sel refstr
	if stat = -1 : dialog "取得に失敗しました" : end
	sdim data, stat + 1
	zip_getlist data
	mesbox data, winx, winy
	stop

zip_init
[パラメータなし]バージョンを取得するだけである為、パラメータは必要ない。
プログラム起動後に一度だけ実行する必要がある。

zip_wait
[パラメータなし]処理待ちするだけである為、パラメータは必要ない。
尚、処理可能状態になれば0が、処理できないままなら−1がstatに返る。

アイテム数 = zip_getcount(取得タイプ)
アイテム数カウント値(失敗:-1, 成功:アイテム数)の受取先を指定する。
取得タイプ取得するタイプ(0:格納ファイル数, 1:ファイルリスト行数)を指定する。

zip_findfile 絞込条件
絞込条件ファイルリストに格納するファイル名の一部または拡張子とワイルドカードを指定する。
半角スペースを含むと複数の条件を指定したことになるので、
ファイル名の一部に半角スペースを含んでいるものを指定する時はダブルクォーテーションで囲む。
正常に指定したなら0が、失敗なら−1がstatに返る。

zip_sel zipファイル
zipファイル解凍対象となるzip書庫ファイルパスを指定する。
尚、内部でzip_findfileを使用している為、zip_selより前にzip_findfileを定義すること。
その際のファイルリスト絞込条件は「*」全ファイルである。
正常に指定したならファイルリストのバイト数が、失敗なら−1がstatに返る。

zip_getlist 受取先変数
受取先変数ファイルリストの受取先となる文字列型変数を指定する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#uselib "unzip32"
#func  global UnZipCloseArchive "UnZipCloseArchive" int
#func  global UnZipFindFirst "UnZipFindFirst" int, str, int
#func  global UnZipFindNext "UnZipFindNext" int, int
#cfunc global UnZipGetFileCount "UnZipGetFileCount" str
#func  global UnZipGetFileName "UnZipGetFileName" int, var, int
#cfunc global UnZipGetOriginalSize "UnZipGetOriginalSize" int
#func  global UnZipGetRunning "UnZipGetRunning"
#cfunc global UnZipGetVersion "UnZipGetVersion"
#cfunc global UnZipOpenArchive "UnZipOpenArchive" nullptr, str, int

#module
#deffunc zip_init
	zipver = 0
	// バージョン取得[百の位がメジャー][一・十の位がマイナー]
	if varptr(UnZipGetVersion) : zipver = UnZipGetVersion()
	poke zipver, 2
	return zipver ! 0

#deffunc zip_wait local i
	repeat 0xFFFF
		UnZipGetRunning // UnZip32.DLLの稼働状況取得
		if stat = 0 : i = 1 : break
		wait 10
	loop
	return (i = 0) * -1

#defcfunc zip_getcount int type, local i
	if zipver = 0 : return -1
	if type {
		notesel filelist
		i = notemax
		noteunsel
	} else : i = UnZipGetFileCount(zipfile) // 格納ファイル総数を取得
	return i

#deffunc zip_findfile str extension, local i, local s
	if zipver = 0 : return -1
	zip_wait
	if stat : return -1
	sdim s, 256
	dim i, 3
	i = zip_getcount()
	if i <= 0 : return -1
	sdim filelist, i * 256
	dim sizelist, i
	// Zipファイルにアクセスできるようオープン 2000000:M_BAR_WINDOW_OFF, 800000:M_ERROR_MESSAGE_OFF
	i = UnZipOpenArchive(zipfile, 0x02800000)
	notesel filelist
	repeat
		if cnt = 0 : UnZipFindFirst i, extension : else : UnZipFindNext i
		if stat = -1 : break
		UnZipGetFileName i, s, 256 // 格納ファイル名を取得
		sizelist(i.1) = UnZipGetOriginalSize(i) // 格納ファイルの元のサイズを取得
		if stat > 0 : noteadd s : i.1++ // フォルダは無視
	loop
	UnZipCloseArchive i // Zipファイルをクローズ
	noteunsel
	return 0

#deffunc zip_sel str file, local i
	if zipver = 0 : return -1
	zipfile = file
	zip_findfile "*"
	if stat = -1 : i = -1 : else : i = strlen(filelist)
	return i

#deffunc zip_getlist var list
	dup list, filelist
	return
#global

	dialog "zip", 16, "zipファイル"
	if stat = 0 : end
	zip_init
	zip_sel refstr
	if stat = -1 : dialog "取得に失敗しました" : end
	sdim data, stat + 1
	zip_getlist data
	mesbox data, ginfo_winx, ginfo_winy