HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2011
0421
コタツHTTP受信データのgzip解凍をしたい7解決


コタツ

リンク

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



この記事に返信する


akoko

リンク

2011/4/21(Thu) 18:38:42|NO.38597

gzipのことは詳しくないですが、とりあえずhspsockの使い方が間違ってます。
sockgetはテキストデータの受信にしか使えないのでこれでは受信データ自体が壊れていると思います。
sockgetbで受信してください。



skyblue

リンク

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



akoko

リンク

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作成に関しても、もう少し学ぶ必要があるかなと思いました。
詳しく解説していただいて、どうも有難うございました。
解決です。



ONION software Copyright 1997-2018(c) All rights reserved.