//file 文件读写
import util.metaProperty
namespace fsys;

class file{
	//构造参数与API函数CreateFile基本一致,请参考API手册
	ctor( path
		,mode = "r" 
		,sharemode = 3/*_FILE_SHARE_READ | _FILE_SHARE_WRITE*/
		,creation = 0
		,attrib = 0x80/*_FILE_ATTRIBUTE_NORMAL*/
		,secAttrib
		,template
		){ 
		if(type(path)==type.pointer){
			this.hfile =  path
		}
		else{
			path = ..io.fullpath(path);  
			var access = 0;
			var seekend;
			if( type(mode) == type.string ){
				var f=mode[1];
				if( f='r'# ) {
					creation |= 0x3/*_OPEN_EXISTING*/  
					access |= 0x80000000/*_GENERIC_READ*/;
				}
				else {  
					access |= 0x40000000/*_GENERIC_WRITE*/
					if( f='w'#  ) 
						creation |= 0x2/*_CREATE_ALWAYS*/
					else{
						creation |= 0x4/*_OPEN_ALWAYS*/
						seekend = true;
					}
				}
				
				if(..string.indexAny(mode,"+") )
					access |= 0x10000000/*_GENERIC_ALL*/ 
			}
			else {
				access = mode; 
			} 
			
			this.hfile = CreateFile(path,access,sharemode,secAttrib : {} ,creation,attrib ) 
			if( this.hfile == INVALID_HANDLE )
				return null,..lasterr()
				
			if(seekend)
			 	llseek( this.hfile,0 ,0x2/*_SEEK_END*/);
		}

		 ..table.add_gc(this,"close");	 
	}; 
	@_metaProperty
}
 
var push = ..table.push;
namespace file{	 
	_metaProperty = ..util.metaProperty(
		close = function(){
			if(owner.hfile)
				..raw.closehandle(owner.hfile)
			owner.hfile = null;
		}
		seteof = function(){
			if(owner.hfile)
				return SetEndOfFile(owner.hfile)
		}
		seek = function(mode,off=0){
			if(owner.hfile){
				return llseek( owner.hfile,off,_seekMode[mode]:0); 
			}
		}
		read = function(len){
			if(owner.hfile){ 
				if( type(len)!=type.number){ 
					var bytes = {} 
					var ok,byte = ReadByte(owner.hfile,0,1,0)
					if(!ok)return; 
					while(ok && byte && (byte!='\n'#) ){  
						if(byte!='\r'#)
							push(bytes,byte);  
						ok,byte = ReadByte(owner.hfile,0,1,0)
					}
					return ..string.pack(bytes)
				}
				 
				if(len<0) 
					len = owner.size -len + 1; 
					
				var ok,str,numBytes = ReadFile( owner.hfile,len,len,0);
				if(ok)
					return ..string.left(str,numBytes); 
				
			}
		}
		write = function(str){
			if(owner.hfile){
				str = tostring(str);
				var ok,str,numBytes = WriteFile( owner.hfile,str,#str,0);
				if(ok)
					return numBytes;
			}
		};
		flush = function(){
			if(owner.hfile){
				return FlushFileBuffers( owner.hfile );
			}
		};
		setFileTimes = function(tm){
			if(! owner.hfile)
				return;
			var creation,access,write = tm.creation,tm.access,tm.write
			if( !(..time.istime(creation) 
				&&  ..time.istime(access)
				&&  ..time.istime(write)
				) ){
				error('参数必须是一个table对象\n并且creation,access,write成员必须是合法的time对象',2)
			}
			var ok;
			ok,creation = SystemTimeToFileTime(creation,0)
			ok,access = SystemTimeToFileTime(access,0)
			ok,write = SystemTimeToFileTime(write,0)
			var ok = SetFileTime( owner.hfile,creation,access,write)
			return ok;
		};
		getFileTimes = function(){
			if(! owner.hfile)
				return;
				
			var ok,creation,access,write = GetFileTime(owner.hfile,0,0,0) 
			ok,,creation = FileTimeToSystemTime(creation,..time( ,"!%c") )
			ok,,access = FileTimeToSystemTime(access,..time( ,"!%c") )
			ok,,write = FileTimeToSystemTime(write,..time( ,"!%c") )
			return  {creation=creation;access=access;write=write};
		};
		size = function(unit,p=2){ 
			if(owner.hfile){ 
				var low,high = GetFileSize(owner.hfile,0)
				return fsys.size.format(low,high); 
			} 
		};
		handle = {
			_get = function(){
				return owner.hfile;
			} 
		} 
	);
	
	import fsys.size;
	
	INVALID_HANDLE = topointer(0xFFFFFFFF)
	CreateFile = ::Kernel32.api("CreateFileA","pointer(string path,int access,int sharemode,
	struct secAttrib,int creationDisposition,int attrib,pointer template)")
	llseek = ::Kernel32.api("_llseek","int(pointer file,int off,int mode)") 
	ReadByte = ::Kernel32.api("ReadFile","int(pointer file,BYTE& buffer,INT bufferSize,INT& numBytes,pointer overlapped)") 
	ReadFile = ::Kernel32.api("ReadFile","int(pointer file,string& buffer,INT bufferSize,INT& numBytes,pointer overlapped)") 
	WriteFile = ::Kernel32.api("WriteFile","int(pointer file,string buffer,INT bufferSize,INT& numBytes,pointer lpOverlapped)")
	GetFileSize = ::Kernel32.api("GetFileSize","INT(pointer file,int& INT)")
	FlushFileBuffers = ::Kernel32.api("FlushFileBuffers","int(pointer file)")
	
	GetFileTime = ::Kernel32.api("GetFileTime","int(pointer file,long& creation,long& access,long& write)")
	SetFileTime = ::Kernel32.api("SetFileTime","int(pointer file,long& creation,long& access,long& write)")
	FileTimeToSystemTime = ::Kernel32.api("FileTimeToSystemTime","int(long &filetime,struct& time)")
	SystemTimeToFileTime = ::Kernel32.api("SystemTimeToFileTime","int(struct time,long& filetime)") 
	SetEndOfFile = ::Kernel32.api("SetEndOfFile","int(pointer file)") 
	 
	_seekMode = {
	 	["cur"] = 0x1/*_FILE_CURRENT*/;
	 	["end"] = 0x2/*_FILE_END*/;
	 	["set"] = 0x0/*_FILE_BEGIN*/;
	} 
}
 
/**intellisense() 
fsys.file = 文件读写函数库
fsys.file(__/*文件句柄*/) = 可以指定文件、管道等句柄
fsys.file("__/*文件路径*/") = 只读模式打开,文件必须存在\n更多参数参考源码
fsys.file("__/*文件路径*/","r+") = 读写模式打开,文件必须存在\n更多参数参考源码
fsys.file("__/*文件路径*/","w") = 只写模式打开,创建新文件清空原文件\n更多参数参考源码
fsys.file("__/*文件路径*/","w+") = 读写模式打开,创建新文件清空原文件\n更多参数参考源码
fsys.file("__/*文件路径*/","a") = 只写追加模式打开,创建新文件保留原文件\n更多参数参考源码
fsys.file("__/*文件路径*/","a+") = 读写追加模式打开,创建新文件保留原文件\n更多参数参考源码
!fsysfile.read(__/*字节数*/) = 读取指定长度的字节 
!fsysfile.read() = 读取一行文本\n返回文本不包含回车换行符
!fsysfile.read(-1) = 读取所有内容到文件尾部
!fsysfile.write(__/*字符串*/) = 写入字符串
!fsysfile.setFileTimes(__) = 修改创建时间、最后修改时间、最后访问时间\n参数必须请使用getFileTimes()函数返回的对象
!fsysfile.getFileTimes() = 返回创建时间、最后修改时间、最后访问时间\n!filetimes.
!fsysfile.seek("end") = 移动指针至结束处\n返回当前位置,返回值大于2GB则为负值,\n获取文件大小推荐使用 size() 函数
!fsysfile.seek("end",__) = 移动至相对结束处的指定偏移量
!fsysfile.seek() = 得到当前位置
!fsysfile.seek("cur",__) = 移动至相对当前位置的指定偏移量
!fsysfile.seek("set") = 移动指针到开始
!fsysfile.seek("set",__) = 移动至相对开始处的指定偏移量
!fsysfile.path = 返回文件路径
!fsysfile.flush() = 刷新缓冲区
!fsysfile.close() = 关闭文件句柄
!fsysfile.seteof() = 设置文件结束 
!fsysfile.size() = 返回文件大小\n可选参数一指定单位大小(默认自动选择),\n可选用参数二指定小数精度(默认为2)\n返回文件大小,单位大小,单位名("bytes","KB","MB","GB"等)
!fsysfile.handle = 返回文件句柄
fsys.file() = !fsysfile.
?fsys.file = !fsysfile.
!filetimes.creation = 文件创建时间\n!time.
!filetimes.access = 文件最后访问时间\n!time.
!filetimes.write = 文件最后修改时间!time.
?.getFileTimes = !filetimes.

_FILEOPENORD=@0x600/*_FILEOPENORD*/
_FILE_ATTRIBUTE_ARCHIVE=@0x20/*_FILE_ATTRIBUTE_ARCHIVE*/
_FILE_ATTRIBUTE_COMPRESSED=@0x800/*_FILE_ATTRIBUTE_COMPRESSED*/
_FILE_ATTRIBUTE_DIRECTORY=@0x10/*_FILE_ATTRIBUTE_DIRECTORY*/
_FILE_ATTRIBUTE_HIDDEN=@0x2/*_FILE_ATTRIBUTE_HIDDEN*/
_FILE_ATTRIBUTE_NORMAL=@0x80/*_FILE_ATTRIBUTE_NORMAL*/
_FILE_ATTRIBUTE_READONLY=@0x1/*_FILE_ATTRIBUTE_READONLY*/
_FILE_ATTRIBUTE_SYSTEM=@0x4/*_FILE_ATTRIBUTE_SYSTEM*/
_FILE_ATTRIBUTE_TEMPORARY=@0x100/*_FILE_ATTRIBUTE_TEMPORARY*/
_FILE_BEGIN=@0x0/*_FILE_BEGIN*/
_FILE_CASE_PRESERVED_NAMES=@0x2/*_FILE_CASE_PRESERVED_NAMES*/
_FILE_CASE_SENSITIVE_SEARCH=@0x1/*_FILE_CASE_SENSITIVE_SEARCH*/
_FILE_CURRENT=@0x1/*_FILE_CURRENT*/
_FILE_END=@0x2/*_FILE_END*/
_FILE_FILE_COMPRESSION=@0x10/*_FILE_FILE_COMPRESSION*/
_FILE_FLAG_BACKUP_SEMANTICS=@0x2000000/*_FILE_FLAG_BACKUP_SEMANTICS*/
_FILE_FLAG_DELETE_ON_CLOSE=@0x4000000/*_FILE_FLAG_DELETE_ON_CLOSE*/
_FILE_FLAG_NO_BUFFERING=@0x20000000/*_FILE_FLAG_NO_BUFFERING*/
_FILE_FLAG_OVERLAPPED=@0x40000000/*_FILE_FLAG_OVERLAPPED*/
_FILE_FLAG_POSIX_SEMANTICS=@0x1000000/*_FILE_FLAG_POSIX_SEMANTICS*/
_FILE_FLAG_RANDOM_ACCESS=@0x10000000/*_FILE_FLAG_RANDOM_ACCESS*/
_FILE_FLAG_SEQUENTIAL_SCAN=@0x8000000/*_FILE_FLAG_SEQUENTIAL_SCAN*/
_FILE_FLAG_WRITE_THROUGH=@0x80000000/*_FILE_FLAG_WRITE_THROUGH*/
_FILE_NOTIFY_CHANGE_ATTRIBUTES=@0x4/*_FILE_NOTIFY_CHANGE_ATTRIBUTES*/
_FILE_NOTIFY_CHANGE_DIR_NAME=@0x2/*_FILE_NOTIFY_CHANGE_DIR_NAME*/
_FILE_NOTIFY_CHANGE_FILE_NAME=@0x1/*_FILE_NOTIFY_CHANGE_FILE_NAME*/
_FILE_NOTIFY_CHANGE_LAST_WRITE=@0x10/*_FILE_NOTIFY_CHANGE_LAST_WRITE*/
_FILE_NOTIFY_CHANGE_SECURITY=@0x100/*_FILE_NOTIFY_CHANGE_SECURITY*/
_FILE_NOTIFY_CHANGE_SIZE=@0x8/*_FILE_NOTIFY_CHANGE_SIZE*/
_FILE_PERSISTENT_ACLS=@0x8/*_FILE_PERSISTENT_ACLS*/
_FILE_SHARE_READ=@0x1/*_FILE_SHARE_READ*/
_FILE_SHARE_WRITE=@0x2/*_FILE_SHARE_WRITE*/
_FILE_SHARE_DELETE=@4/*_FILE_SHARE_DELETE*/
_FILE_TYPE_CHAR=@0x2/*_FILE_TYPE_CHAR*/
_FILE_TYPE_DISK=@0x1/*_FILE_TYPE_DISK*/
_FILE_TYPE_PIPE=@0x3/*_FILE_TYPE_PIPE*/
_FILE_TYPE_REMOTE=@0x8000/*_FILE_TYPE_REMOTE*/
_FILE_TYPE_UNKNOWN=@0x0/*_FILE_TYPE_UNKNOWN*/
_FILE_UNICODE_ON_DISK=@0x4/*_FILE_UNICODE_ON_DISK*/
_FILE_VOLUME_IS_COMPRESSED=@0x8000/*_FILE_VOLUME_IS_COMPRESSED*/
end intellisense**/
