//multipartFormData 上传文件数据 namespace fsys; class multipartFormData{ ctor( path,boundary,blockSize){ { var file,err = ..io.file(path,"rb"); if(!file) return null,err; path = path; blockSize = blockSize : 0x100000; this.getPath = function(){ return path; } var current; var multipart = {}; var outBuffer = ..raw.buffer(blockSize); var readSize = file.readBuffer(outBuffer); if(!boundary){ boundary = ..string.match(outBuffer,"^--([^\r]+)"); if(!boundary) return; } var nextboundary = '@\r\n--' + boundary + '\r\n'; var boundarylen = #nextboundary -1; var bound,boundEnd = ..string.find(outBuffer,'@--' + boundary + '\r\n'); while(readSize){ if(! ( bound && ( (bound+boundarylen) <= readSize) ) ){ if(!current) return; if( readSize < blockSize){ if( readSize < boundarylen + 2 ) return; } bound = ..string.find(outBuffer,'@\r\n--' + boundary + '--'); if(( bound && ( (bound+boundarylen-1) <= readSize) ) ){ current.length = ( (file.seek() - readSize) + (bound - 1 )) - current.offset ; if( bound - 1 >= current.length ){ current["contentValue"] = ..string.slice(outBuffer,(bound)-current.length,bound- 1); } break ; } if( ! file.read(0) ){ return; } file.seek("cur",-(boundarylen+2) ); ::Ntdll.RtlZeroMemory(outBuffer,blockSize); readSize = file.readBuffer(outBuffer); bound,boundEnd = ..string.find(outBuffer,nextboundary); continue; } if(current){ current.length = ( (file.seek() - readSize) + (bound - 1 ) ) - current.offset; if( bound - 1 >= current.length ){ current["contentValue"] = ..string.slice(outBuffer,bound-current.length,bound-1); } } current = {} boundEnd++; var offset = ..string.find(outBuffer,'@\r\n\r\n',boundEnd); if(!offset){ var right = ..math.min(4,readSize - boundEnd); if( readSize-right > boundEnd ) current.header = ..string.slice(outBuffer,boundEnd,readSize-right); file.seek("set", -right ); ::Ntdll.RtlZeroMemory(outBuffer,blockSize); readSize = file.readBuffer(outBuffer); if(!readSize) return null; boundEnd = 0; offset = ..string.find(outBuffer,'@\r\n\r\n'); if(!offset) return; } current.header = ..string.concat(current.header,..string.slice(outBuffer,boundEnd,offset-1) ); file.seek("cur",-(readSize -(offset+ 3 )) ); current.offset = file.seek() ; ..table.push(multipart,current); ::Ntdll.RtlZeroMemory(outBuffer,blockSize); readSize = file.readBuffer(outBuffer); bound,boundEnd = ..string.find(outBuffer,nextboundary); } for(k,part in multipart){ var formData = {}; for line in ..string.lines(part.header) { var nv = ..string.split(line,":",2); if(nv[2]){ formData[ ..string.trim(..string.lower(nv[1])) ] = ..string.trim(nv[2]); } } var dp = formData["content-disposition"]; if(!dp) continue; for k,v in ..string.gmatch( dp,`([^=;\s]+)\s*=\s*(<"[^"]+">|<[^;]+>)`) { k = ..string.lower(k); formData[k] = ..string.trim(v,`'"`); } if(!formData.name) continue; formData["contentType"] = formData["content-type"]; formData["contentOffset"] = part.offset; formData["contentLength"] = part.length; formData["contentValue"] = part["contentValue"]; formData.value = function(){ if( !owner["contentValue"] ){ var file,err = ..io.file(this.getPath(),"r+b"); if(!file) return; file.seek("set",owner["contentOffset"]) owner["contentValue"] = file.read(owner["contentLength"] ) file.close(); } return owner["contentValue"]; } formData.save = function(savePath){ if(owner["contentValue"] ){ ..string.save(savePath,owner["contentValue"]); return true; } var fileR,err = ..io.file(this.getPath(),"rb"); if(!fileR) return null,err; var fileW,err = ..io.file(savePath,"w+b"); if(!fileW) { fileR.close(); return null,err; } fileR.seek("set",owner["contentOffset"]) var len = owner["contentLength"]; var outBuffer = ..raw.buffer(blockSize); var readSize = fileR.readBuffer(outBuffer,..math.min(len,blockSize)); while(readSize){ fileW.writeBuffer(outBuffer,readSize); len = len - readSize; if(len<=0) break; readSize = fileR.readBuffer(outBuffer,..math.min(len,blockSize)); } fileR.close(); fileW.close(); return true; } this[formData.name] = formData; } file.close(); outBuffer = null; return this; } }; } ::Ntdll := ..raw.loadDll("Ntdll.dll"); /**intellisense() fsys.multipartFormData = fsys.multipartFormData 用于解析 `multipart/form-data` 格式的上传文件表单。\n如果需要构建此格式的数据请使用 web.multipartFormData 库。 fsys.multipartFormData(.("文件路径","分隔符") = 解析文件返回表对象\n可选在参数@3中指定读写缓冲区大小 fsys.multipartFormData() = !fsysMultipartFormData. end intellisense**/ /**intellisense(!fsysMultipartFormData) ? = multipart/form-data对象的每个键名下保存每个字段的信息\n!stdfsysmultipartFormField. getPath() = 参数中指定的文件路径 end intellisense**/ /**intellisense(!stdfsysmultipartFormField) name = 字段名称 filename = 文件名\n如果不是文件则为空 value() = 此函数直接读取并返回此字段的数据\n较大文件应使用save函数转存文件 save(.("文件路径") = 保存文件\n上传文件数据如果不保存,在请求结束将被自动删除 contentType = MIME类型 contentLength = 数据长度 contentOffset = 偏移位置 end intellisense**/