|
|
|
2011/4/21(Thu) 15:30:09|NO.38593
HTTPで受信したgzipで圧縮されたデータを解凍したいと思っているのですが、うまくいきません。
この掲示板の過去ログ
http://hsp.tv/play/pforum.php?mode=pastwch&num=35548
や、2chの過去ログ
http://logsoku.com/thread/pc8.2ch.net/tech/1142529119/350-385
などを参考に、やってみたのですが、
http://www.csdinc.co.jp/archiver/dev/main.html
こちらのLHSPプラグインを使用した場合、HSP2専用なのか、
「互換性のない拡張命令タイプを使用しています」とエラーが出て利用出来ず、
zlib 汎用データ圧縮
http://taillove.jp/mia/plugin/arc/z.txt
http://taillove.jp/mia/plugin/arc/z.lzh
こちらのプラグインのzUncompress命令を使用した場合、gzip圧縮の形式?が違うのか、HTTPから送られてきたデータはうまく解凍されませんでした。
(同プラグインのzCompress命令で圧縮した文字列の場合は、解凍できました。)
zlibについて調べたところ、
http://blogs.itmedia.co.jp/komata/2011/04/httpgzipzlib-b764.html
こちらのブログに、uncompress命令ではなく、inflateInit2命令を使えばうまくいく、というような事が書いてあり、
じゃあ上のhsp用zlibプラグインでは、inflateInit2命令は無いようなので利用できないのかな、と思い
それじゃあ、zlib本家のライブラリを使えばいいのかな?と思い、
http://zlib.net/
とりあえずこちらのzlibの本家?から、zlibのライブラリを落として、zlib1.dllをスクリプトファイルと同じディレクトリに置き、
#uselib "zlib1.dll"
と書いてみたところで、どうやれば使えるのか(使えないのかも)分かりません。(-_-;
ここでつまってしまいました。
hspで上のzlibライブラリか、もしくは別の方法で、HTTPのgzipデータを解凍するにはどのようにすれば良いでしょうか?なにか方法は無いでしょうか?
以下2ch.netでgzip圧縮のHTTPデータ受信の例です。
#include "hspsock.as"
screen 0, 640,480
HLog=""
mesbox hLog,640,480,0
hLogId=stat
//接続
sockopen 0,"2ch.net",80
//ヘッダ
header="GET http://2ch.net/ HTTP/1.1\n"
header+="Host: 2ch.net\n"
header+="Cache-Control: max-age=0\n"
header+="Accept-Encoding: gzip,deflate\n\n"
hLog+=header:objprm hLogId,hLog;mesbox更新
//ヘッダを投げる
sockput header
//受信
buf="":a=""
b=0:sz=0
*wloop
await 0
sockget a,64
if stat : dialog "socket error" : end
b=peek(a,0):if b=0 : goto *sdok
buf+=a
sz+=64
if sz>30000 : dialog "受信サイズがオーバーしました。" : goto *sdok
goto *wloop
*sdok
hLog+=buf+"\n\n":objprm hLogId,hLog;mesbox更新
//データから応答ヘッダを取り除く
httpMessageBody=buf
notesel httpMessageBody
repeat
noteget hogea,0
if hogea="" { notedel 0 : break }else{ notedel 0 }
loop
/*ここでhttpMessageBodyをgzip解凍したい*/
hLog+="httpMessageBody ***この文字列をgzip解凍したい***\n"
hLog+=""+httpMessageBody+"\n\n"
objprm hLogId,hLog;mesbox更新
stop
| |
|
2011/4/21(Thu) 18:38:42|NO.38597
gzipのことは詳しくないですが、とりあえずhspsockの使い方が間違ってます。
sockgetはテキストデータの受信にしか使えないのでこれでは受信データ自体が壊れていると思います。
sockgetbで受信してください。
|
|
2011/4/21(Thu) 18:40:32|NO.38598
>#uselib "zlib1.dll"
>
>と書いてみたところで、どうやれば使えるのか(使えないのかも)分かりません。(-_-;
>ここでつまってしまいました。
何らかの方法で登録されている関数を知った後、
エディターで命令や関数として登録すれば使えます。(#func,#cfuncなど)
|
|
2011/4/22(Fri) 17:20:06|NO.38609
akokoさん
ご指摘ありがとうございます。sockgetは文字列専用なんですね。
sockgetbで受信するようにしました。
ですが、やはりhsp用zlibプラグインのuncompress命令では解凍出来ませんでした。
skyblueさん
回答ありがとうございます。
登録されている関数は、
http://www.sra.co.jp/people/m-kasahr/zlib/zlib-1.1.4-ja.h
おそらくこちらのサイトに書かれてる事だと思うのですが、
#funcや#cfuncでどのように記述すればいいか分かりません。
たとえば、
ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
int windowBits));
この関数を登録する場合どのように記述すれば良いのでしょうか?
//sockgetbでの取得とzlibプラグインでの解凍(失敗)
#include "hspsock.as"
#include "z.as"
hLog=""
mesbox hLog,640,480,0
hLogId=stat
//先にファイルサイズ取得
sdim buf,4096
sockopen 0, "2ch.net", 80
if stat !=0 {dialog"sockopen失敗":goto *exit}
//HEADリクエスト送信
sockput "HEAD / HTTP/1.0\nHost: www.2ch.net\n\n"
if stat !=0 {dialog"sockput失敗":goto *exit}
//レスポンスからファイルサイズを割り出す。
sockget buf,4096,0
s=instr(buf,0,"Content-Length: ")
e=instr(buf,s,"\n")
filesize=int(strmid(buf,s+16,e-16))
sockclose 0
//HTTP取得
sockopen 0, "2ch.net", 80
//GETリクエスト送信
header="GET / HTTP/1.1\n"
header+="Host: www.2ch.net\n"
header+="Accept-Encoding: gzip,deflate\n"
header+="\n"
hLog+=header:objprm hLogId,hLog;mesbox更新
sockput header
if stat !=0 {dialog"sockput失敗":goto *exit}
sdim buf,filesize+4096
revsize=0
repeat
sockcheck 0
if stat=1:wait 5:continue
if stat=2:dialog"ソケットエラー":goto *exit
sockgetb buf,revsize,1024,0
if stat=0:break
revsize+=stat
if cnt\10=0:wait 5:title ""+revsize
loop
//レスポンスヘッダーとバイナリデータを分離
idx=instr(buf,0,"\n\n")
sdim buf2,filesize
sdim returnheader,idx+4
memcpy buf2,buf,filesize,0,idx+4
memcpy returnheader,buf,idx+4,0,0
hLog+=returnheader : objprm hLogId,hLog;mesbox更新
/* 解凍 (エラーになり解凍されません。) */
sdim udata, 30000
zSetDest udata, 30000 ;解凍後のデータをudataに代入
zUncompress buf2, filesize:usize=stat
/* 出力 */
bsave "解凍後出力.html",udata
*exit
sockclose 0
| |
|
2011/4/22(Fri) 21:30:09|NO.38616
2点ほど修正
HEADリクエスト送信時にエンコードを指定してないからサイズが違ってる。
受信データはgzファイルなのでzReadで処理する必要がある。
zUncompressとは扱うデータのフォーマットが異なる。
>こちらのブログに、uncompress命令ではなく、inflateInit2命令を使えばうまくいく、というような事が書いてあり
とおなじですね。
#include "hspsock.as"
#include "z.as"
hLog=""
mesbox hLog,640,480,0
hLogId=stat
//先にファイルサイズ取得
sdim buf,4096
sockopen 0, "2ch.net", 80
if stat !=0 {dialog"sockopen失敗":goto *exit}
//HEADリクエスト送信
sockput "HEAD / HTTP/1.0\nHost: www.2ch.net\nAccept-Encoding: gzip,deflate\n\n"
if stat !=0 {dialog"sockput失敗":goto *exit}
//レスポンスからファイルサイズを割り出す。
sockget buf,4096,0
s=instr(buf,0,"Content-Length: ")
e=instr(buf,s,"\n")
filesize=int(strmid(buf,s+16,e-16))
sockclose 0
//HTTP取得
sockopen 0, "2ch.net", 80
//GETリクエスト送信
header="GET / HTTP/1.1\n"
header+="Host: www.2ch.net\n"
header+="Accept-Encoding: gzip,deflate\n"
header+="\n"
hLog+=header:objprm hLogId,hLog;mesbox更新
sockput header
if stat !=0 {dialog"sockput失敗":goto *exit}
sdim buf,filesize+4096
revsize=0
repeat
sockcheck 0
if stat=1:wait 5:continue
if stat=2:dialog"ソケットエラー":goto *exit
sockgetb buf,revsize,1024,0
if stat=0:break
revsize+=stat
if cnt\10=0:wait 5:title ""+revsize
loop
//レスポンスヘッダーとバイナリデータを分離
idx=instr(buf,0,"\n\n")
sdim buf2,filesize
sdim returnheader,idx+4
memcpy buf2,buf,filesize,0,idx+4
memcpy returnheader,buf,idx+4,0,0
hLog+=returnheader : objprm hLogId,hLog;mesbox更新
/* 解凍 (エラーになり解凍されません。) */
sdim udata, 30000
/* 出力 */
bsave "圧縮ファイル.gz",buf2,filesize
zOpen h, "圧縮ファイル.gz",Z_READ
zRead udata,h,30000
bsave "解凍後出力.html",udata,stat
zClose h
*exit
sockclose 0
| |
|
2011/4/23(Sat) 00:43:30|NO.38617
akokoさん
回答どうもありがとうございます。スクリプト動作しました!
なるほど。。。一度ファイルに保存してzRead命令を使えば解凍出来るのですね。
sockgetbの点、Accept-Encodingが抜けている点、盲点でした。どうもありがとうございました。
この方法で、自分のスクリプトの方は十分解決なのですが、
ファイルに出力して呼び出す手間が若干スマートでない事と、
今後の知識の為にも、zlib1.dllを使う方法に関しても解決したいです。
そこで、zlib1.dllを使う方法に関してもう一人、参考になるレスを下さった方がおられたのですが、
レスを参考にスクリプトを組んでいた途中、ブラウザリロードしたら、消えてしまいました。
削除されたのでしょうか?(x_x;)もし、可能でしたらもう一度レスを頂きたいです。
よろしくお願いします。
|
|
2011/4/24(Sun) 13:09:19|NO.38666
わざわざ書き直していただいて、どうも有り難うございます!m(_ _)m
とても参考になりました。
http://www.mlexp.com/wiki/index.php?zlib%20%A5%E1%A5%E2
頂いたレスとこちらの使用例の伸長のプログラムを参考に昨日からずっと挑戦してみてるんですが、
status = inflate(z_stream, 0)
のところでエラー(-3)が出て、いろいろ変えてみたのですが、どうしてもエラーが出て先に進めません。
何度も質問ですみません。簡単に考えていたのですが、まさかこんなにもうまくいかないとは。。。
下のスクリプト、どうすれば動くようになるでしょうか?分かる方いましたら、回答願いたいです。よろしくお願いします。
※akokoさんのスクリプトで出てきた「圧縮ファイル.gz」を使用しています。
※上の伸長のプログラムを参考のためコメントアウトしています。
#uselib "zlib1.dll"
#func global inflateInit2_ "inflateInit2_" var,int,str,int
#cfunc global inflate "inflate" var,int
#cfunc global inflateEnd "inflateEnd" var
exist "圧縮ファイル.gz" : filesize=strsize
sdim buf,filesize
bload "圧縮ファイル.gz",buf
dim z_stream,14 ;構造体の準備 ;z_stream z;
status=0 ;int status = Z_OK;
// メモリ管理はZLIBに任せる
z_stream(8)=0 ;z.zalloc = Z_NULL;
z_stream(9)=0 ;z.zfree = Z_NULL;
z_stream(10)=0 ;z.opaque = Z_NULL;
z_stream(0)=0 ;z.next_in = Z_NULL;
z_stream(1)=0 ;z.avail_in = 0;
#define MAX_WBITS 15
inflateInit2_ z_stream,MAX_WBITS+32,"1.2.5",56
if status!=0 { mes "ERROR 1 ("+status+")" : stop }else{ mes "1 OK" }
;status = inflateInit2(&z, MAX_WBITS + 32);
;if (status != Z_OK) {
; debugs_format(99, 5, "inflateInit: %s\n", (z.msg) ? z.msg : "???");
; return status;
;}
sdim inBuf,filesize
inBuf=buf
sdim outBuf,30000
// 入力データを設定
z_stream(0)=varptr(inBuf) ;入力ポインタ ;z.next_in = src;
z_stream(1)=filesize ;入力バッファサイズ ;z.avail_in = srcSize;
// 出力先を設定
z_stream(3)=varptr(outBuf) ;出力ポインタ ;z.next_out = dest;
z_stream(4)=30000 ;出力バッファサイズ ;z.avail_out = destMaxSize;
// 伸長(展開)
#define Z_OK 0 ;出力データを供給
#define Z_STREAM_END 1 ;圧縮データの終端に達し、伸長データをすべて供給
#define Z_NEED_DICT 2 ;あらかじめセットされた辞書が必要
#define Z_ERRNO (-1)
#define Z_STREAM_ERROR (-2) ;ストリームの状態がおかしい (たとえば next_in や next_out が NULL になっている) 場合
#define Z_DATA_ERROR (-3) ;入力データが壊れている (入力ストリームが zlib 形式になっていない、または adler32チェックサムが合わない) 場合
#define Z_MEM_ERROR (-4) ;十分なメモリがない
#define Z_BUF_ERROR (-5) ;処理がまったく進行できないか、Z_FINISH が指定されたにもかかわらず、出力バッファに十分な空きがない場合
#define Z_VERSION_ERROR (-6)
status = inflate(z_stream, 0) ;status = inflate(&z, Z_NO_FLUSH);
// 成功ではない、またはデータの最後まで読み取れていない場合は失敗
if status!=0 or status!=1 { mes "ERROR 2 ("+status+")" : stop }else{ mes "2 OK" }
;if (status != Z_OK && status != Z_STREAM_END) {
; debugs_format(99, 5, "inflate: %s\n", (z.msg) ? z.msg : "???");
; return status;
;}
// 出力サイズを設定
destSize=z_stream(5) ;*destSize = z.total_out;
// 終了処理
status=inflateEnd(varptr(z_stream))
if status!=0 { mes "ERROR 3 ("+status+")" : stop }else{ mes "3 OK" }
;status = inflateEnd(&z);
;if (status != Z_OK) {
; debugs_format(99, 5, "inflateEnd: %s\n", (z.msg) ? z.msg : "???");
; return status;
;}
// 出力サイズを設定
destSize=z_stream(5) ;*destSize = z.total_out;
;return status;
;}
stop
| |
|
2011/4/24(Sun) 17:46:18|NO.38678
出来ました!!
提示していただいたスクリプトを参考に、自分のスクリプトも見直してみたところ、
inBuf=buf
↓
repeat filesize
poke inBuf,cnt,peek(buf,cnt)
loop
if status!=0 or status!=1 { mes "ERROR 2 ("+status+")" : stop }else{ mes "2 OK"
↓
if status!=1 { mes "ERROR 2 ("+status+")" : stop }else{ mes "2 OK" }
status=inflateEnd(varptr(z_stream))
↓
status=inflateEnd(z_stream)
のようにすることで、動作させることが出来ました。
(その他に削れる部分が沢山あるみたいですが)
ようやく肩の荷が下りました。(^^;
自分で調べても分からなかったので、
C言語やDLL作成に関しても、もう少し学ぶ必要があるかなと思いました。
詳しく解説していただいて、どうも有難うございました。
解決です。
|
|