From: drh Date: Mon, 30 Oct 2006 13:37:22 +0000 (+0000) Subject: Changes to support non-ASCII characters in win95 filenames. X-Git-Tag: version-3.6.10~2673 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=371de5ad8b95a8af5021b786bc3bf126aa90ba07;p=thirdparty%2Fsqlite.git Changes to support non-ASCII characters in win95 filenames. Ticket #2047. (CVS 3495) FossilOrigin-Name: 9fa3ae584ae4936696fd2f23a64697f0409ef313 --- diff --git a/manifest b/manifest index 632c881ee3..9973753d24 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\soptimizer\sso\sthat\sIS\sNULL\scan\suse\san\savailable\sindex.\s(CVS\s3494) -D 2006-10-28T00:28:09 +C Changes\sto\ssupport\snon-ASCII\scharacters\sin\swin95\sfilenames.\nTicket\s#2047.\s(CVS\s3495) +D 2006-10-30T13:37:22 F Makefile.in 4379c909d46b38b8c5db3533084601621d4f14b2 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -83,7 +83,7 @@ F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3 F src/os_unix.c 523b674d93e0017320bb48b83fc0f9c9d07d3548 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e -F src/os_win.c 30e51641b0cb88826f25b2afcf8db3c83b7e45dd +F src/os_win.c 1be3a56e96eae0561c000ba70428294a1621960d F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c a1293bb4d318cfa9fa7100a08c38ad5598cb4436 F src/pager.h 0cff9de5e9019cb695a04d18df8caaaff933a272 @@ -419,7 +419,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 58171a41f706dd2fab1da5d83d2176d0103643fb -R 3d00eb1d0264ea0aeb0bc4ee950a7a9d +P 64762a9d582e4655d6bc5989d8e0ad773d659a7d +R 5ec6d2ae141bcc5225f95a80dc3a18a6 U drh -Z f47a4f5a11ed13f459b99613e5b7d9ba +Z 9d1a31671b051d96dc7533a8d807fa28 diff --git a/manifest.uuid b/manifest.uuid index 486014ce91..6490d01c87 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -64762a9d582e4655d6bc5989d8e0ad773d659a7d \ No newline at end of file +9fa3ae584ae4936696fd2f23a64697f0409ef313 \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index c01f2c0b24..dfb6bf800c 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -131,9 +131,6 @@ static WCHAR *utf8ToUnicode(const char *zFilename){ int nChar; WCHAR *zWideFilename; - if( !isNT() ){ - return 0; - } nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) ); if( zWideFilename==0 ){ @@ -169,6 +166,85 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){ return zFilename; } +/* +** Convert a multibyte character string to UTF-32, based on the current +** Ansi codepage (CP_ACP). Space to hold the returned string is obtained +** from sqliteMalloc. +*/ +static WCHAR *mbcsToUnicode(const char *zFilename){ + int nByte; + WCHAR *zMbcsFilename; + + nByte = MultiByteToWideChar(CP_ACP, 0, zFilename, -1, NULL, 0)*sizeof(WCHAR); + zMbcsFilename = sqliteMalloc( nByte*sizeof(zMbcsFilename[0]) ); + if( zMbcsFilename==0 ){ + return 0; + } + nByte = MultiByteToWideChar(CP_ACP, 0, zFilename, -1, zMbcsFilename, nByte); + if( nByte==0 ){ + sqliteFree(zMbcsFilename); + zMbcsFilename = 0; + } + return zMbcsFilename; +} + +/* +** Convert UTF-32 to multibyte character string, based on the user's Ansi +** codepage (CP_ACP). Space to hold the returned string is obtained from +** sqliteMalloc(). +*/ +static char *unicodeToMbcs(const WCHAR *zWideFilename){ + int nByte; + char *zFilename; + + nByte = WideCharToMultiByte(CP_ACP, 0, zWideFilename, -1, 0, 0, 0, 0); + zFilename = sqliteMalloc( nByte ); + if( zFilename==0 ){ + return 0; + } + nByte = WideCharToMultiByte(CP_ACP, 0, zWideFilename, -1, zFilename, nByte, + 0, 0); + if( nByte == 0 ){ + sqliteFree(zFilename); + zFilename = 0; + } + return zFilename; +} + +/* +** Convert multibyte character string to UTF-8. Space to hold the +** returned string is obtained from sqliteMalloc(). +*/ +static char *mbcsToUtf8(const char *zFilename){ + char *zFilenameUtf8; + WCHAR *zTmpWide; + + zTmpWide = mbcsToUnicode(zFilename); + if( zTmpWide==0 ){ + return 0; + } + zFilenameUtf8 = unicodeToUtf8(zTmpWide); + sqliteFree(zTmpWide); + return zFilenameUtf8; +} + +/* +** Convert UTF-8 to multibyte character string. Space to hold the +** returned string is obtained from sqliteMalloc(). +*/ +static char *utf8ToMbcs(const char *zFilename){ + char *zFilenameMbcs; + WCHAR *zTmpWide; + + zTmpWide = utf8ToUnicode(zFilename); + if( zTmpWide==0 ){ + return 0; + } + zFilenameMbcs = unicodeToMbcs(zTmpWide); + sqliteFree(zTmpWide); + return zFilenameMbcs; +} + #if OS_WINCE /************************************************************************* ** This section contains code for WinCE only. @@ -475,6 +551,23 @@ static BOOL winceLockFileEx( *****************************************************************************/ #endif /* OS_WINCE */ +/* +** Convert a UTF-8 filename into whatever form the underlying +** operating system wants filenames in. Space to hold the result +** is obtained from sqliteMalloc and must be freed by the calling +** function. +*/ +static void *convertUtf8Filename(const char *zFilename){ + void *zConverted = 0; + if( isNT() ){ + zConverted = utf8ToUnicode(zFilename); + }else{ + zConverted = utf8ToMbcs(zFilename); + } + /* caller will handle out of memory */ + return zConverted; +} + /* ** Delete the named file. ** @@ -489,25 +582,28 @@ static BOOL winceLockFileEx( */ #define MX_DELETION_ATTEMPTS 3 int sqlite3WinDelete(const char *zFilename){ - WCHAR *zWide = utf8ToUnicode(zFilename); int cnt = 0; int rc; - if( zWide ){ + void *zConverted = convertUtf8Filename(zFilename); + if( zConverted==0 ){ + return SQLITE_NOMEM; + } + if( isNT() ){ do{ - rc = DeleteFileW(zWide); - }while( rc==0 && GetFileAttributesW(zWide)!=0xffffffff + rc = DeleteFileW(zConverted); + }while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); - sqliteFree(zWide); }else{ #if OS_WINCE return SQLITE_NOMEM; #else do{ - rc = DeleteFileA(zFilename); - }while( rc==0 && GetFileAttributesA(zFilename)!=0xffffffff + rc = DeleteFileA(zConverted); + }while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); #endif } + sqliteFree(zConverted); TRACE2("DELETE \"%s\"\n", zFilename); return rc!=0 ? SQLITE_OK : SQLITE_IOERR; } @@ -517,17 +613,20 @@ int sqlite3WinDelete(const char *zFilename){ */ int sqlite3WinFileExists(const char *zFilename){ int exists = 0; - WCHAR *zWide = utf8ToUnicode(zFilename); - if( zWide ){ - exists = GetFileAttributesW(zWide) != 0xffffffff; - sqliteFree(zWide); + void *zConverted = convertUtf8Filename(zFilename); + if( zConverted==0 ){ + return SQLITE_NOMEM; + } + if( isNT() ){ + exists = GetFileAttributesW((WCHAR*)zConverted) != 0xffffffff; }else{ #if OS_WINCE return SQLITE_NOMEM; #else - exists = GetFileAttributesA(zFilename) != 0xffffffff; + exists = GetFileAttributesA((char*)zConverted) != 0xffffffff; #endif } + sqliteFree(zConverted); return exists; } @@ -554,10 +653,14 @@ int sqlite3WinOpenReadWrite( ){ winFile f; HANDLE h; - WCHAR *zWide = utf8ToUnicode(zFilename); + void *zConverted = convertUtf8Filename(zFilename); + if( zConverted==0 ){ + return SQLITE_NOMEM; + } assert( *pId==0 ); - if( zWide ){ - h = CreateFileW(zWide, + + if( isNT() ){ + h = CreateFileW((WCHAR*)zConverted, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -566,7 +669,7 @@ int sqlite3WinOpenReadWrite( NULL ); if( h==INVALID_HANDLE_VALUE ){ - h = CreateFileW(zWide, + h = CreateFileW((WCHAR*)zConverted, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -575,7 +678,7 @@ int sqlite3WinOpenReadWrite( NULL ); if( h==INVALID_HANDLE_VALUE ){ - sqliteFree(zWide); + sqliteFree(zConverted); return SQLITE_CANTOPEN; } *pReadonly = 1; @@ -585,16 +688,15 @@ int sqlite3WinOpenReadWrite( #if OS_WINCE if (!winceCreateLock(zFilename, &f)){ CloseHandle(h); - sqliteFree(zWide); + sqliteFree(zConverted); return SQLITE_CANTOPEN; } #endif - sqliteFree(zWide); }else{ #if OS_WINCE return SQLITE_NOMEM; #else - h = CreateFileA(zFilename, + h = CreateFileA((char*)zConverted, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -603,7 +705,7 @@ int sqlite3WinOpenReadWrite( NULL ); if( h==INVALID_HANDLE_VALUE ){ - h = CreateFileA(zFilename, + h = CreateFileA((char*)zConverted, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -612,6 +714,7 @@ int sqlite3WinOpenReadWrite( NULL ); if( h==INVALID_HANDLE_VALUE ){ + sqliteFree(zConverted); return SQLITE_CANTOPEN; } *pReadonly = 1; @@ -620,6 +723,9 @@ int sqlite3WinOpenReadWrite( } #endif /* OS_WINCE */ } + + sqliteFree(zConverted); + f.h = h; #if OS_WINCE f.zDeleteOnClose = 0; @@ -653,7 +759,10 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ winFile f; HANDLE h; int fileflags; - WCHAR *zWide = utf8ToUnicode(zFilename); + void *zConverted = convertUtf8Filename(zFilename); + if( zConverted==0 ){ + return SQLITE_NOMEM; + } assert( *pId == 0 ); fileflags = FILE_FLAG_RANDOM_ACCESS; #if !OS_WINCE @@ -661,10 +770,10 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE; } #endif - if( zWide ){ + if( isNT() ){ int cnt = 0; do{ - h = CreateFileW(zWide, + h = CreateFileW((WCHAR*)zConverted, GENERIC_READ | GENERIC_WRITE, 0, NULL, @@ -673,14 +782,13 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ NULL ); }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) ); - sqliteFree(zWide); }else{ #if OS_WINCE return SQLITE_NOMEM; #else int cnt = 0; do{ - h = CreateFileA(zFilename, + h = CreateFileA((char*)zConverted, GENERIC_READ | GENERIC_WRITE, 0, NULL, @@ -691,6 +799,7 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ }while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) ); #endif /* OS_WINCE */ } + sqliteFree(zConverted); if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } @@ -713,10 +822,13 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){ winFile f; HANDLE h; - WCHAR *zWide = utf8ToUnicode(zFilename); + void *zConverted = convertUtf8Filename(zFilename); + if( zConverted==0 ){ + return SQLITE_NOMEM; + } assert( *pId==0 ); - if( zWide ){ - h = CreateFileW(zWide, + if( isNT() ){ + h = CreateFileW((WCHAR*)zConverted, GENERIC_READ, 0, NULL, @@ -724,12 +836,11 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL ); - sqliteFree(zWide); }else{ #if OS_WINCE return SQLITE_NOMEM; #else - h = CreateFileA(zFilename, + h = CreateFileA((char*)zConverted, GENERIC_READ, 0, NULL, @@ -739,6 +850,7 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){ ); #endif } + sqliteFree(zConverted); if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } @@ -804,9 +916,21 @@ int sqlite3WinTempFileName(char *zBuf){ strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30); zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0; sqliteFree(zMulti); + }else{ + return SQLITE_NOMEM; } }else{ - GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath); + char *zUtf8; + char zMbcsPath[SQLITE_TEMPNAME_SIZE]; + GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zMbcsPath); + zUtf8 = mbcsToUtf8(zMbcsPath); + if( zUtf8 ){ + strncpy(zTempPath, zUtf8, SQLITE_TEMPNAME_SIZE-30); + zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0; + sqliteFree(zUtf8); + }else{ + return SQLITE_NOMEM; + } } for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} zTempPath[i] = 0; @@ -1024,20 +1148,24 @@ static int unlockReadLock(winFile *pFile){ */ int sqlite3WinIsDirWritable(char *zDirname){ int fileAttr; - WCHAR *zWide; + void *zConverted; if( zDirname==0 ) return 0; if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0; - zWide = utf8ToUnicode(zDirname); - if( zWide ){ - fileAttr = GetFileAttributesW(zWide); - sqliteFree(zWide); + + zConverted = convertUtf8Filename(zDirname); + if( zConverted==0 ){ + return SQLITE_NOMEM; + } + if( isNT() ){ + fileAttr = GetFileAttributesW((WCHAR*)zConverted); }else{ #if OS_WINCE return 0; #else - fileAttr = GetFileAttributesA(zDirname); + fileAttr = GetFileAttributesA((char*)zConverted); #endif } + sqliteFree(zConverted); if( fileAttr == 0xffffffff ) return 0; if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){ return 0; @@ -1260,24 +1388,33 @@ char *sqlite3WinFullPathname(const char *zRelative){ /* WinCE has no concept of a relative pathname, or so I am told. */ zFull = sqliteStrDup(zRelative); #else - char *zNotUsed; - WCHAR *zWide; int nByte; - zWide = utf8ToUnicode(zRelative); - if( zWide ){ + void *zConverted; + zConverted = convertUtf8Filename(zRelative); + if( isNT() ){ WCHAR *zTemp, *zNotUsedW; - nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1; + nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, &zNotUsedW) + 1; zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) ); - if( zTemp==0 ) return 0; - GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW); - sqliteFree(zWide); + if( zTemp==0 ){ + sqliteFree(zConverted); + return 0; + } + GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, &zNotUsedW); + sqliteFree(zConverted); zFull = unicodeToUtf8(zTemp); sqliteFree(zTemp); }else{ - nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1; - zFull = sqliteMalloc( nByte*sizeof(zFull[0]) ); - if( zFull==0 ) return 0; - GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed); + char *zTemp, *zNotUsed; + nByte = GetFullPathNameA((char*)zConverted, 0, 0, &zNotUsed) + 1; + zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) ); + if( zTemp==0 ){ + sqliteFree(zConverted); + return 0; + } + GetFullPathNameA((char*)zConverted, nByte, zTemp, &zNotUsed); + sqliteFree(zConverted); + zFull = mbcsToUtf8(zTemp); + sqliteFree(zTemp); } #endif return zFull;