/***************************************************************************** * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: file_win32.c 543 2006-01-07 22:06:24Z picard $ * * The Core Pocket Media Player * Copyright (c) 2004-2005 Gabor Kovacs * ****************************************************************************/ #include "../common.h" #if defined(TARGET_WIN32) || defined(TARGET_WINCE) #ifndef STRICT #define STRICT #endif #define WIN32_LEAN_AND_MEAN #include #ifndef ERROR_INVALID_DRIVE_OBJECT #define ERROR_INVALID_DRIVE_OBJECT 4321L #endif #ifndef ERROR_DEVICE_NOT_AVAILABLE #define ERROR_DEVICE_NOT_AVAILABLE 4319L #endif #ifndef ERROR_DEVICE_REMOVED #define ERROR_DEVICE_REMOVED 1617L #endif typedef struct filestream { stream Stream; tchar_t URL[MAXPATH]; HANDLE Handle; filepos_t Length; filepos_t Pos; bool_t Silent; bool_t Create; HANDLE Find; const tchar_t* Exts; bool_t ExtFilter; WIN32_FIND_DATA FindData; } filestream; static int Get(filestream* p, int No, void* Data, int Size) { int Result = ERR_INVALID_PARAM; switch (No) { case STREAM_URL: GETSTRING(p->URL); break; case STREAM_SILENT: GETVALUE(p->Silent,bool_t); break; case STREAM_LENGTH: GETVALUECOND(p->Length,int,p->Length>=0); break; case STREAM_CREATE: GETVALUE(p->Create,bool_t); break; } return Result; } static int Open(filestream* p, const tchar_t* URL, bool_t ReOpen) { if (p->Handle) CloseHandle(p->Handle); p->Handle = 0; p->Length = -1; if (!ReOpen) p->URL[0] = 0; else Sleep(200); if (URL && URL[0]) { HANDLE Handle; Handle = CreateFile(URL,p->Create?GENERIC_WRITE:GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,p->Create?CREATE_ALWAYS:OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL); if (Handle == INVALID_HANDLE_VALUE) { if (!ReOpen && !p->Silent) ShowError(0,ERR_ID,ERR_FILE_NOT_FOUND,URL); return ERR_FILE_NOT_FOUND; } tcscpy_s(p->URL,TSIZEOF(p->URL),URL); p->Handle = Handle; p->Length = GetFileSize(Handle,NULL); if (ReOpen) p->Pos = SetFilePointer(p->Handle,p->Pos,NULL,FILE_BEGIN); else { p->Pos = 0; #if defined(TARGET_WINCE) // wince shortcut handling if (p->Length < MAXPATH && !p->Create) { uint32_t Readed; char ShortCut[MAXPATH]; tchar_t URL[MAXPATH]; char* ch; if (ReadFile(p->Handle,ShortCut,p->Length,&Readed,NULL)) { ShortCut[Readed] = 0; for (ch=ShortCut;*ch && *ch!='#';++ch) if (!IsDigit(*ch)) break; if (ch[0] == '#' && ch[1]!=':') { char* Head = ++ch; char* Tail; if (*ch == '"') { Head++; ch = strchr(ch+1,'"'); if (ch) *(ch++) = 0; } if (ch) { Tail = strchr(ch,13); if (Tail) { *Tail = 0; ch = Tail+1; } if (!strchr(ch,13)) { ch = strchr(ch,10); if (!ch || !strchr(ch+1,10)) { if (ch) *ch = 0; StrToTcs(URL,TSIZEOF(URL),Head); return Open(p,URL,0); } } } } p->Pos = SetFilePointer(p->Handle,0,NULL,FILE_BEGIN); } } #endif } } return ERR_NONE; } static int Set(filestream* p, int No, const void* Data, int Size) { int Result = ERR_INVALID_PARAM; switch (No) { case STREAM_SILENT: SETVALUE(p->Silent,bool_t,ERR_NONE); break; case STREAM_CREATE: SETVALUE(p->Create,bool_t,ERR_NONE); break; case STREAM_URL: Result = Open(p,(const tchar_t*)Data,0); break; } return Result; } static int Read(filestream* p,void* Data,int Size) { uint32_t Readed; DWORD Error; //Sleep(100); //DEBUG_MSG3(-1,"FileRead: %08x %08x %d",p->Pos,SetFilePointer(p->Handle,0,NULL,FILE_CURRENT),Size); if (ReadFile(p->Handle,Data,Size,&Readed,NULL)) { //DEBUG_MSG2(T("READ pos:%d len:%d"),p->Pos,Readed); p->Pos += Readed; return Readed; } Error = GetLastError(); //DEBUG_MSG2(T("READ pos:%d error:%d"),p->Pos,Error); if (Error == ERROR_DEVICE_REMOVED || Error == ERROR_DEVICE_NOT_AVAILABLE || Error == ERROR_INVALID_HANDLE || Error == ERROR_INVALID_DRIVE_OBJECT || Error == ERROR_DEV_NOT_EXIST || Error == ERROR_GEN_FAILURE) Open(p,p->URL,1); return -1; } static int ReadBlock(filestream* p,block* Block,int Ofs,int Size) { return Read(p,(char*)(Block->Ptr+Ofs),Size); } static int Seek(filestream* p,int Pos,int SeekMode) { int ReTry=3; int Result; DWORD Error; switch (SeekMode) { default: case SEEK_SET: SeekMode = FILE_BEGIN; break; case SEEK_CUR: SeekMode = FILE_CURRENT; break; case SEEK_END: SeekMode = FILE_END; break; } do { //DEBUG_MSG3(-1,"FileSeek: %08x %08x %d",SetFilePointer(p->Handle,0,NULL,FILE_CURRENT),Pos,SeekMode); Result = SetFilePointer(p->Handle,Pos,NULL,SeekMode); if (Result != -1) { p->Pos = Result; break; } Error = GetLastError(); if (Error != ERROR_DEVICE_REMOVED && Error != ERROR_INVALID_HANDLE) break; Open(p,p->URL,1); } while (--ReTry>0); return Result; } static int Write(filestream* p,const void* Data,int Size) { DWORD Written; if (WriteFile(p->Handle,Data,Size,&Written,NULL)) { p->Pos += Written; return Written; } return -1; } static int EnumDir(filestream* p,const tchar_t* URL,const tchar_t* Exts,bool_t ExtFilter,streamdir* Item) { if (URL) { DWORD Attrib; tchar_t Path[MAXPATH]; p->Exts = Exts; p->ExtFilter = ExtFilter; if (p->Find != INVALID_HANDLE_VALUE) { FindClose(p->Find); p->Find = INVALID_HANDLE_VALUE; } stprintf_s(Path,TSIZEOF(Path),T("%s\\*.*"),URL); Attrib = GetFileAttributes(URL); if (URL[0] && Attrib == (DWORD)-1) return ERR_FILE_NOT_FOUND; if (!(Attrib & FILE_ATTRIBUTE_DIRECTORY)) return ERR_NOT_DIRECTORY; p->Find = FindFirstFile(Path, &p->FindData); } Item->FileName[0] = 0; Item->DisplayName[0] = 0; while (!Item->FileName[0] && p->Find != INVALID_HANDLE_VALUE) { if (p->FindData.cFileName[0]!='.') // skip unix/mac hidden files and . .. directory entries { FILETIME Local; tcscpy_s(Item->FileName,TSIZEOF(Item->FileName),p->FindData.cFileName); if (FileTimeToLocalFileTime(&p->FindData.ftLastWriteTime,&Local)) Item->Date = ((int64_t)Local.dwHighDateTime << 32)|Local.dwLowDateTime; else Item->Date = -1; if (p->FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) Item->Size = -1; else { Item->Size = p->FindData.nFileSizeLow; Item->Type = CheckExts(Item->FileName,p->Exts); if (!Item->Type && p->ExtFilter) Item->FileName[0] = 0; // skip } } if (!FindNextFile(p->Find,&p->FindData)) { FindClose(p->Find); p->Find = INVALID_HANDLE_VALUE; } } if (!Item->FileName[0]) { if (p->Find != INVALID_HANDLE_VALUE) { FindClose(p->Find); p->Find = INVALID_HANDLE_VALUE; } return ERR_END_OF_FILE; } return ERR_NONE; } static int Create(filestream* p) { p->Stream.Get = (nodeget)Get, p->Stream.Set = (nodeset)Set, p->Stream.Read = Read; p->Stream.ReadBlock = ReadBlock; p->Stream.Write = Write; p->Stream.Seek = Seek; p->Stream.EnumDir = EnumDir; p->Find = INVALID_HANDLE_VALUE; return ERR_NONE; } static void Delete(filestream* p) { Open(p,NULL,0); if (p->Find != INVALID_HANDLE_VALUE) FindClose(p->Find); } static const nodedef File = { sizeof(filestream), FILE_ID, STREAM_CLASS, PRI_MINIMUM, (nodecreate)Create, (nodedelete)Delete, }; void File_Init() { NodeRegisterClass(&File); } void File_Done() { NodeUnRegisterClass(FILE_ID); } stream* FileCreate(const tchar_t* Path) { // create fake stream filestream* p = (filestream*)malloc(sizeof(filestream)); memset(p,0,sizeof(filestream)); p->Stream.Class = FILE_ID; p->Stream.Enum = (nodeenum)StreamEnum; Create(p); return &p->Stream; } void FileRelease(stream* p) { if (p) { Delete((filestream*)p); free(p); } } bool_t FileExits(const tchar_t* Path) { return GetFileAttributes(Path) != (DWORD)-1; } int64_t FileDate(const tchar_t* Path) { int64_t Date = -1; HANDLE Find; SYSTEMTIME Time; WIN32_FIND_DATA FindData; Find = FindFirstFile(Path, &FindData); if (Find != INVALID_HANDLE_VALUE) { if (FileTimeToSystemTime(&FindData.ftLastWriteTime,&Time)) Date = ((((((int64_t)Time.wYear*100+(int64_t)Time.wMonth)*100+(int64_t)Time.wDay)*100+ (int64_t)Time.wHour)*100+(int64_t)Time.wMinute)*100+(int64_t)Time.wSecond)*1000+(int64_t)Time.wMilliseconds; FindClose(Find); } return Date; } #endif