| 3962 | |
| 3963 | |
| 3964 | ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) |
| 3965 | { if (flags!=ZIP_MEMORY && flags!=ZIP_FILENAME && flags!=ZIP_HANDLE) return ZR_ARGS; |
| 3966 | if (flags==ZIP_MEMORY) |
| 3967 | { if (index!=currentfile) |
| 3968 | { if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; |
| 3969 | if (index>=(int)uf->gi.number_entry) return ZR_ARGS; |
| 3970 | if (index<(int)uf->num_file) unzGoToFirstFile(uf); |
| 3971 | while ((int)uf->num_file<index) unzGoToNextFile(uf); |
| 3972 | unzOpenCurrentFile(uf,password); currentfile=index; |
| 3973 | } |
| 3974 | bool reached_eof; |
| 3975 | int res = unzReadCurrentFile(uf,dst,len,&reached_eof); |
| 3976 | if (res<=0) {unzCloseCurrentFile(uf); currentfile=-1;} |
| 3977 | if (reached_eof) return ZR_OK; |
| 3978 | if (res>0) return ZR_MORE; |
| 3979 | if (res==UNZ_PASSWORD) return ZR_PASSWORD; |
| 3980 | return ZR_FLATE; |
| 3981 | } |
| 3982 | // otherwise we're writing to a handle or a file |
| 3983 | if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; |
| 3984 | if (index>=(int)uf->gi.number_entry) return ZR_ARGS; |
| 3985 | if (index<(int)uf->num_file) unzGoToFirstFile(uf); |
| 3986 | while ((int)uf->num_file<index) unzGoToNextFile(uf); |
| 3987 | ZIPENTRY ze; Get(index,&ze); |
| 3988 | // zipentry=directory is handled specially |
| 3989 | if ((ze.attr&FILE_ATTRIBUTE_DIRECTORY)!=0) |
| 3990 | { if (flags==ZIP_HANDLE) return ZR_OK; // don't do anything |
| 3991 | const TCHAR *dir = (const TCHAR*)dst; |
| 3992 | bool isabsolute = (dir[0]=='/' || dir[0]=='\\' || (dir[0]!=0 && dir[1]==':')); |
| 3993 | if (isabsolute) EnsureDirectory(0,dir); else EnsureDirectory(rootdir,dir); |
| 3994 | return ZR_OK; |
| 3995 | } |
| 3996 | // otherwise, we write the zipentry to a file/handle |
| 3997 | HANDLE h; |
| 3998 | if (flags==ZIP_HANDLE) h=dst; |
| 3999 | else |
| 4000 | { const TCHAR *ufn = (const TCHAR*)dst; |
| 4001 | // We'll qualify all relative names to our root dir, and leave absolute names as they are |
| 4002 | // ufn="zipfile.txt" dir="" name="zipfile.txt" fn="c:\\currentdir\\zipfile.txt" |
| 4003 | // ufn="dir1/dir2/subfile.txt" dir="dir1/dir2/" name="subfile.txt" fn="c:\\currentdir\\dir1/dir2/subfiles.txt" |
| 4004 | // ufn="\z\file.txt" dir="\z\" name="file.txt" fn="\z\file.txt" |
| 4005 | // This might be a security risk, in the case where we just use the zipentry's name as "ufn", where |
| 4006 | // a malicious zip could unzip itself into c:\windows. Our solution is that GetZipItem (which |
| 4007 | // is how the user retrieve's the file's name within the zip) never returns absolute paths. |
| 4008 | const TCHAR *name=ufn; const TCHAR *c=name; while (*c!=0) {if (*c=='/' || *c=='\\') name=c+1; c++;} |
| 4009 | TCHAR dir[MAX_PATH]; _tcscpy_s(dir, MAX_PATH, ufn); if (name==ufn) *dir=0; else dir[name-ufn]=0; |
| 4010 | TCHAR fn[MAX_PATH]; |
| 4011 | bool isabsolute = (dir[0]=='/' || dir[0]=='\\' || (dir[0]!=0 && dir[1]==':')); |
| 4012 | if (isabsolute) {wsprintf(fn,_T("%s%s"),dir,name); EnsureDirectory(0,dir);} |
| 4013 | else {wsprintf(fn,_T("%s%s%s"),rootdir,dir,name); EnsureDirectory(rootdir,dir);} |
| 4014 | // |
| 4015 | h = CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,ze.attr,NULL); |
| 4016 | } |
| 4017 | if (h==INVALID_HANDLE_VALUE) return ZR_NOFILE; |
| 4018 | unzOpenCurrentFile(uf,password); |
| 4019 | if (unzbuf==0) unzbuf=new char[16384]; DWORD haderr=0; |
| 4020 | // |
| 4021 |
no test coverage detected