//默认库源代码
namespace zlib;

ZLIB_VERSION = "1.2.3"; 
var dll = ..raw.loadDll( $"/.res/zlib1.dll","zlib1.dll" ); 

/*普通压缩解压{{*/
var z_compress2 = dll.api("compress2","int(pointer dest, INT& destLen, string src, INT srcLen,int level)","cdecl");
var z_compressBound = dll.api("compressBound","INT(INT srcLen)","cdecl");
var z_uncompress = dll.api("uncompress","int(string& dest, INT& destLen, string src, INT srcLen)","cdecl");

compressBound = z_compressBound;
compress = function ( src,raw,level =  -1/*_Z_DEFAULT_COMPRESSION*/ ) {
	if ( !#src  ) {
		error("参数一必须是非空字符串!", 2);
	}
	if(!raw){ 
		return gzCompress(src,level,false);
	}
	var srcLen = #src;
	var dstLen = compressBound(srcLen);
	var buf = ..raw.malloc(dstLen);
	var re,dstLen = z_compress2(buf, dstLen, src, srcLen,level);
	if(re==0/*_Z_OK*/) return ..raw.tostring(buf,1,dstLen),srcLen; 
} 
uncompress = function (src,dstLen) {
	if ( !#src  ) {
		error("参数一必须是非空字符串!", 2);
	}
	var srcLen = #src;
	if (!dstLen) {
		return gzUncompress(src,false);
	}
	var re, dest = z_uncompress(dstLen, dstLen, src, srcLen);
	if(re==0/*_Z_OK*/)return dest;
};
/*}}*/
	
/*压缩解压内存流{{*/
var z_inflate = dll.api("inflate","int(struct &strm, int flush)","cdecl");
var z_deflate = dll.api("deflate","int(struct &strm, int flush)","cdecl"); 
var z_inflateEnd = dll.api("inflateEnd","int(struct &strm)","cdecl");
var z_deflateEnd = dll.api("deflateEnd","int(struct &strm)","cdecl");
var z_deflateInit = dll.api("deflateInit_","int(struct &strm, int level, string version, int stream_size)","cdecl");
var z_inflateInit = dll.api("inflateInit_","int(struct &strm, string version, int stream_size)","cdecl");
var z_deflateInit2 = dll.api("deflateInit2_","int(struct &strm, int  level, int  method,int windowBits, int memLevel,int strategy,string version,int stream_size)","cdecl");
var z_inflateInit2 = dll.api("inflateInit2_","int(struct &strm, int  windowBits, string version, int stream_size)","cdecl");
	
deflateInit = function(strm, level=-1/*_Z_DEFAULT_COMPRESSION*/){
	return z_deflateInit(strm, level,ZLIB_VERSION,z_stream.sizeof)
}
inflateInit = function(strm){
	return z_inflateInit(strm,ZLIB_VERSION,z_stream.sizeof)
}
deflateInit2 = function(strm, level, method, windowBits, memLevel=-1/*_Z_DEFAULT_COMPRESSION*/, strategy=0/*_Z_DEFAULT_STRATEGY*/){
	return z_deflateInit2(strm, level, method, windowBits, memLevel, strategy,ZLIB_VERSION,z_stream.sizeof);
}
inflateInit2 = function(strm,windowBits){
	return z_inflateInit2(strm,windowBits,ZLIB_VERSION,z_stream.sizeof);
};
	
z_stream = class{
	ctor(bufferSize=1024){
		this.buffer =  ..raw.malloc(bufferSize)
		this.bufferSize = bufferSize ;
		this.next_out = this.buffer ; 
		this.avail_out = bufferSize
		this.total_in = 0; 	
	}
    pointer next_in;
    INT avail_in; 
    INT total_in;  
    pointer next_out;
    INT avail_out;
    INT total_out;
    pointer msg;
    pointer state;
    pointer zalloc;
    pointer zfree;
    pointer opaque;
    int data_type;
    INT adler;
    INT reserved;
}
z_stream.sizeof = 56; //..raw.sizeof( z_stream() ); 
	
class streamReader{
	ctor( gzip = true,bufferSize = 0x4000/*16KB*/ ){
		this = ..zlib.z_stream(bufferSize); 
		
		var ret;
		if( gzip ){
			//If you would like to use zlib to inflate data with gzip header,
			//you should use inflateInit2 instead of inflate Init, and add 16 or 32 to your usual windowBits parameters. Let's say your usual windowBits is 15, then you should use 31 instead.
			ret = ..zlib.inflateInit2( this, 47/*32 + 15*/)
		}
		else {
			ret = ..zlib.inflateInit( this )
		} 
		if( ret != 0/*_Z_OK*/) return; 
	}
	read = function(zdata){ 
		var nzdata = #zdata
		this.next_in  = zdata; 
		this.avail_in = nzdata; 
		
		var tab = {}; 
		var limit = this.total_in + nzdata
		var flush = (!nzdata) ? 4/*_Z_FINISH*/ : 0/*_Z_NO_FLUSH*/ ;
		while ( (this.total_in < limit) || (!nzdata) ) {
			ret = z_inflate( this, flush )   
			if( ret == 1/*_Z_STREAM_END*/ ){
				..table.push( tab, ..raw.tostring( this.buffer,1,this.bufferSize - this.avail_out ) )
			 	break;
			}
			if( ret != 0/*_Z_OK*/ ) { 
				return;
			} 
			if( !this.avail_out ){
				..table.push( tab, ..raw.tostring( this.buffer,1,this.bufferSize ) );
				this.avail_out = this.bufferSize;
				this.next_out = this.buffer;
			} 
		} 
		if(#tab) return  ..string.join(tab) 
	}
	close = function(){
		if(!this.next_out)return;
		var data = this.read(null);
		if( z_inflateEnd(this) != 0/*_Z_OK*/) return;
		this.next_out = null ; 
		this.avail_out = 0;
		return data;
	} 
};
gzUncompress = function(zdata,gzip,bufferSize) { 
 	gzStream =	streamReader(gzip,bufferSize);  
	return ..string.concat( gzStream.read( zdata ),gzStream.close() ); 
};

class streamWriter{
	ctor( level =  -1/*_Z_DEFAULT_COMPRESSION*/,gzip=true,bufferSize = 0x4000/*16KB*/ ){
		this = ..zlib.z_stream(bufferSize);  
		
		var ret;
		if( gzip ){
			ret = ..zlib.deflateInit2( this, level, 8/*_Z_DEFLATED*/,  31/*16 + 15 */, 8 ) 
			//If you would like to use zlib to inflate raw data without either zlib or gzip header, 
			//you should use inflateInit2 instead of inflate Init, and use -1 to multiply your usual windowBits parameters
		}
		else {
			//when you using deflateInit function - which actually is deflateInit2 with windowBits=15 
			ret = ..zlib.deflateInit( this, level)  
		} 
		if( ret != 0/*_Z_OK*/) return; 
	};
	write = function(zdata){ 
		var nzdata = #zdata
		this.next_in  = zdata; 
		this.avail_in = nzdata; 
		
		var tab = {}; 
		var limit = this.total_in + nzdata
		var flush = (!nzdata) ? 4/*_Z_FINISH*/ : 0/*_Z_NO_FLUSH*/ ;
		while ( (this.total_in < limit) || (!nzdata) ) { 
			ret = z_deflate( this,flush ); 
			if( ret == 1/*_Z_STREAM_END*/ ){
				..table.push( tab, ..raw.tostring( this.buffer,1,this.bufferSize - this.avail_out ) )
			 	break;
			}
			if( ret != 0/*_Z_OK*/ ) {
				return  ..string.join(tab) 
				return;
			} 
			if( !this.avail_out ){
				..table.push( tab, ..raw.tostring( this.buffer,1,this.bufferSize ) );
				this.avail_out = this.bufferSize;
				this.next_out = this.buffer;  
			} 
		} 
		if(#tab) return  ..string.join(tab) 
	}
	close = function(){
		if(!this.next_out)return;
		var data = this.write(null);
		if( z_deflateEnd(this) != 0/*_Z_OK*/) return; 
		this.next_out = null ; 
		this.avail_out = 0;
		return data;
	} 
}   
gzCompress = function(data,level =  -1/*_Z_DEFAULT_COMPRESSION*/,gzip=true) {
	var gzStream = streamWriter(level,gzip)  
	return ..string.concat( gzStream.write(data),gzStream.close() ); 
};
/*}}*/

/*压缩解压文件{{*/
var gzopen = dll.api("gzopen","pointer(string name,string mode)","cdecl");
var gzclose = dll.api("gzclose","int(POINTER gzFile)","cdecl");
var gzwrite = dll.api("gzwrite","int(POINTER gzFile,string data,INT length)","cdecl");
var gzwriteByStruct = dll.api("gzwrite","int(POINTER gzFile,struct data,INT length)","cdecl");
var gzread = dll.api("gzread","int(POINTER gzFile,string &data,INT length)","cdecl"); 
var gzreadByStruct = dll.api("gzread","int(POINTER gzFile,struct &data,INT length)","cdecl"); 
var gzeof = dll.api("gzeof","bool(POINTER gzFile)","cdecl");  

class gzFile{
	ctor( name,mode,buferSize=0x10000){
		name = ..io.fullpath(name);
		this.handle = gzopen(name,mode);
		if(!this.handle)return;
		
		..table.add_gc(this,"close");
	};
	read = function(len){ 
		if( len[["_struct"]] ){ 
			var got = gzreadByStruct(this.handle,len,..raw.sizeof(len) ); 
			if(got>0)return len;
			
			return;
		}
		if( len <= 0 ){
			if(!len){
				return gzeof(this.handle); 
			}
			else {
				var tab = {}
				do{
					var got,s = gzread(this.handle,buferSize,buferSize);
					..table.push(tab,..string.left(s,got) )
				}while(!gzeof(this.handle))
				return ..string.join(tab);
			} 
		}
		var got,s = gzread(this.handle,len,len);
		if(got>0)return ..string.left(s,got);
	}; 
	write = function(s){
		if( s[["_struct"]] ){ 
			return gzwriteByStruct(this.handle,s,..raw.sizeof(s) );  
		}
		return gzwrite(this.handle,s,#s);
	};
	close = function(){
		if( this.handle ){
			gzclose(this.handle);
			this.handle = null;
		}
	};
}; 
/*}}*/

/**intellisense()
zlib = zlib库
zlib.ZLIB_VERSION = zlib版本
zlib.z_stream(缓冲区大小) = z_stream 结构体
zlib.compressBound(.(源数据大小) = 提供源数据大小，计算压缩需要的缓冲区长度
zlib.compress(.(源数据,添加zlib头,压缩级别) = 源数据：需要压缩的数据(字符串类型)\n可选参数2如果设为false,则不会添加zlib头,解压时则必须指定原始大小\n压缩级别最快为1,最大压缩为9,默认值为8\n返回压缩后的数据,第二个返回值为压缩前数据长度
zlib.uncompress(.(源数据,解压后大小) = 源数据：需要解压缩的数据(字符串类型)\n解压后大小：若压缩数据记录了原始文件长度,则不需要指定此参数
zlib.gzUncompress(.(源数据,是否gzip格式) = 解压缩数据\n参数2为可选参数,默认为true
zlib.gzCompress(.(源数据,压缩级别,是否gzip格式) = 压缩gzip数据\n参数2指定压缩级别,最快速度为1,最大压缩率为9,默认为8\n参数3为可选参数,默认为true\n返回压缩后的数据,第二个返回值为压缩前数据长度
zlib.streamReader(.(是否gzip格式,缓冲区大小) = 创建解压内存流对象\n所有参数可选
zlib.streamWriter(.(压缩级别,是否gzip格式,缓冲区大小) = 创建压缩内存流对象,所有参数可选,\n压缩级别,最快速度为1,最大压缩率为9,默认为8
zlib.streamReader() = !zlib_streamReader.
!zlib_streamReader.read(字符串) = 解压并返回字符串
!zlib_streamReader.colse() = 完成压缩,返回剩余解压数据 
!zlib_streamReader.total_in = 总输入大小\n不可修改该值
!zlib_streamReader.total_out = 总输出大小\n不可修改该值
!zlib_streamReader.data_type = 二进制文件为0\n文本文件为1\n不可修改该值
zlib.streamWriter() = !zlib_streamWriter.
!zlib_streamWriter.write(字符串) = 压缩并返回压缩后的字符串\n有可能返回空字符串
!zlib_streamWriter.colse() = 完成压缩,并返回剩余压缩数据 
!zlib_streamWriter.total_in = 总输入大小\n不可修改该值
!zlib_streamWriter.total_out = 总输出大小\n不可修改该值
!zlib_streamWriter.data_type = 二进制文件为0\n文本文件为1\n不可修改该值 
zlib.gzFile("/路径->gz","wb") = 创建只写gzip压缩文件
zlib.gzFile("/路径->gz","rb") = 打开只读gzip压缩文件 
zlib.gzFile() = !gzFile.
!gzFile.read(0) = 检测是否到文件尾
!gzFile.read(-1) = 读取到文件尾,返回所有解压数据\n也可指定要读取的数据长度
!gzFile.read({int data=1234}) = 参数可以是任意结构体\n解压并填充该结构体
!gzFile.write(字符串) = 压缩并写入到压缩文件
!gzFile.write({int data=1234}) = 压缩结构体并写入到压缩文件
!gzFile.close() = 关闭文件
end intellisense**/

 /**intellisense()
_Z_NO_FLUSH=@0/*_Z_NO_FLUSH*/
_Z_PARTIAL_FLUSH=@1/*_Z_PARTIAL_FLUSH*/
_Z_SYNC_FLUSH=@2/*_Z_SYNC_FLUSH*/
_Z_FULL_FLUSH=@3/*_Z_FULL_FLUSH*/
_Z_FINISH=@4/*_Z_FINISH*/
_Z_OK=@0/*_Z_OK*/
_Z_STREAM_END=@1/*_Z_STREAM_END*/
_Z_NEED_DICT=@2/*_Z_NEED_DICT*/
_Z_ERRNO=@-1/*_Z_ERRNO*/
_Z_STREAM_ERROR=@-2/*_Z_STREAM_ERROR*/
_Z_DATA_ERROR=@-3/*_Z_DATA_ERROR*/
_Z_MEM_ERROR=@-4/*_Z_MEM_ERROR*/
_Z_BUF_ERROR=@-5/*_Z_BUF_ERROR*/
_Z_VERSION_ERROR=@-6/*_Z_VERSION_ERROR*/
_Z_NO_COMPRESSION=@0/*_Z_NO_COMPRESSION*/
_Z_BEST_SPEED=@1/*_Z_BEST_SPEED*/
_Z_BEST_COMPRESSION=@9/*_Z_BEST_COMPRESSION*/
_Z_DEFAULT_COMPRESSION=@-1/*_Z_DEFAULT_COMPRESSION*/
_Z_FILTERED=@1/*_Z_FILTERED*/
_Z_HUFFMAN_ONLY=@2/*_Z_HUFFMAN_ONLY*/
_Z_DEFAULT_STRATEGY=@0/*_Z_DEFAULT_STRATEGY*/
_Z_BINARY=@0/*_Z_BINARY*/
_Z_ASCII=@1/*_Z_ASCII*/
_Z_UNKNOWN=@2/*_Z_UNKNOWN*/
_Z_DEFLATED=@8/*_Z_DEFLATED*/
_Z_NULL=@0/*_Z_NULL*/  
_Z_MAX_WBITS=@15/*_Z_MAX_WBITS*/
end intellisense**/