Ver código fonte

support windows unicode filenames

David Rose 14 anos atrás
pai
commit
7667709357

+ 33 - 6
dtool/src/dtoolutil/executionEnvironment.cxx

@@ -161,6 +161,31 @@ expand_string(const string &str) {
 ////////////////////////////////////////////////////////////////////
 Filename ExecutionEnvironment::
 get_cwd() {
+#ifdef WIN32_VC
+  // getcwd() requires us to allocate a dynamic buffer and grow it on
+  // demand.
+  static size_t bufsize = 1024;
+  static wchar_t *buffer = NULL;
+
+  if (buffer == (wchar_t *)NULL) {
+    buffer = new wchar_t[bufsize];
+  }
+
+  while (_wgetcwd(buffer, bufsize) == (wchar_t *)NULL) {
+    if (errno != ERANGE) {
+      perror("getcwd");
+      return string();
+    }
+    delete[] buffer;
+    bufsize = bufsize * 2;
+    buffer = new wchar_t[bufsize];
+    assert(buffer != (wchar_t *)NULL);
+  }
+
+  Filename cwd = Filename::from_os_specific_w(buffer);
+  cwd.make_true_case();
+  return cwd;
+#else  // WIN32_VC
   // getcwd() requires us to allocate a dynamic buffer and grow it on
   // demand.
   static size_t bufsize = 1024;
@@ -184,6 +209,7 @@ get_cwd() {
   Filename cwd = Filename::from_os_specific(buffer);
   cwd.make_true_case();
   return cwd;
+#endif  // WIN32_VC
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -233,6 +259,7 @@ ns_get_environment_variable(const string &var) const {
     if (!ns_has_environment_variable("PANDA_INCOMPATIBLE_PYTHON") && Py_IsInitialized()) {
       PyObject* obj = PySys_GetObject((char*) "argv");
       if (obj) {
+        // Hmm, could this ever be a Unicode object?
         Filename main_dir = Filename::from_os_specific(PyString_AsString(PyList_GetItem(obj, 0)));
         if (main_dir.empty()) {
           // We must be running in the Python interpreter directly, so return the CWD.
@@ -479,10 +506,10 @@ read_args() {
 #endif
   if (dllhandle != 0) {
     static const DWORD buffer_size = 1024;
-    char buffer[buffer_size];
-    DWORD size = GetModuleFileName(dllhandle, buffer, buffer_size);
+    wchar_t buffer[buffer_size];
+    DWORD size = GetModuleFileNameW(dllhandle, buffer, buffer_size);
     if (size != 0) {
-      Filename tmp = Filename::from_os_specific(string(buffer, size));
+      Filename tmp = Filename::from_os_specific_w(wstring(buffer, size));
       tmp.make_true_case();
       _dtool_name = tmp;
     }
@@ -557,10 +584,10 @@ read_args() {
 #ifdef WIN32_VC
   if (_binary_name.empty()) {
     static const DWORD buffer_size = 1024;
-    char buffer[buffer_size];
-    DWORD size = GetModuleFileName(NULL, buffer, buffer_size);
+    wchar_t buffer[buffer_size];
+    DWORD size = GetModuleFileNameW(NULL, buffer, buffer_size);
     if (size != 0) {
-      Filename tmp = Filename::from_os_specific(string(buffer, size));
+      Filename tmp = Filename::from_os_specific_w(wstring(buffer, size));
       tmp.make_true_case();
       _binary_name = tmp;
     }

+ 226 - 106
dtool/src/dtoolutil/filename.cxx

@@ -522,11 +522,11 @@ get_home_directory() {
 
     if (home_directory.empty()) {
 #ifdef WIN32
-      char buffer[MAX_PATH];
+      wchar_t buffer[MAX_PATH];
       
       // On Windows, fall back to the "My Documents" folder.
-      if (SHGetSpecialFolderPath(NULL, buffer, CSIDL_PERSONAL, true)) {
-        Filename dirname = from_os_specific(buffer);
+      if (SHGetSpecialFolderPathW(NULL, buffer, CSIDL_PERSONAL, true)) {
+        Filename dirname = from_os_specific_w(buffer);
         if (dirname.is_directory()) {
           if (dirname.make_canonical()) {
             home_directory = dirname;
@@ -572,9 +572,9 @@ get_temp_directory() {
 
 #ifdef WIN32
     static const size_t buffer_size = 4096;
-    char buffer[buffer_size];
-    if (GetTempPath(buffer_size, buffer) != 0) {
-      Filename dirname = from_os_specific(buffer);
+    wchar_t buffer[buffer_size];
+    if (GetTempPathW(buffer_size, buffer) != 0) {
+      Filename dirname = from_os_specific_w(buffer);
       if (dirname.is_directory()) {
         if (dirname.make_canonical()) {
           temp_directory = dirname;
@@ -620,10 +620,10 @@ get_user_appdata_directory() {
     Filename user_appdata_directory;
 
 #ifdef WIN32
-    char buffer[MAX_PATH];
+    wchar_t buffer[MAX_PATH];
 
-    if (SHGetSpecialFolderPath(NULL, buffer, CSIDL_LOCAL_APPDATA, true)) {
-      Filename dirname = from_os_specific(buffer);
+    if (SHGetSpecialFolderPathW(NULL, buffer, CSIDL_LOCAL_APPDATA, true)) {
+      Filename dirname = from_os_specific_w(buffer);
       if (dirname.is_directory()) {
         if (dirname.make_canonical()) {
           user_appdata_directory = dirname;
@@ -669,10 +669,10 @@ get_common_appdata_directory() {
     Filename common_appdata_directory;
 
 #ifdef WIN32
-    char buffer[MAX_PATH];
+    wchar_t buffer[MAX_PATH];
 
-    if (SHGetSpecialFolderPath(NULL, buffer, CSIDL_COMMON_APPDATA, true)) {
-      Filename dirname = from_os_specific(buffer);
+    if (SHGetSpecialFolderPathW(NULL, buffer, CSIDL_COMMON_APPDATA, true)) {
+      Filename dirname = from_os_specific_w(buffer);
       if (dirname.is_directory()) {
         if (dirname.make_canonical()) {
           common_appdata_directory = dirname;
@@ -1126,14 +1126,14 @@ make_true_case() {
   }
 
 #ifdef WIN32
-  string os_specific = to_os_specific();
+  wstring os_specific = to_os_specific_w();
 
   // First, we have to convert it to its short name, then back to its
   // long name--that seems to be the trick to force Windows to throw
   // away the case we give it and get the actual file case.
   
-  char short_name[MAX_PATH + 1];
-  DWORD l = GetShortPathName(os_specific.c_str(), short_name, MAX_PATH + 1);
+  wchar_t short_name[MAX_PATH + 1];
+  DWORD l = GetShortPathNameW(os_specific.c_str(), short_name, MAX_PATH + 1);
   if (l == 0) {
     // Couldn't query the path name for some reason.  Probably the
     // file didn't exist.
@@ -1144,8 +1144,8 @@ make_true_case() {
   // according to the Windows docs, MAX_PATH will always be enough.
   assert(l < MAX_PATH + 1);
   
-  char long_name[MAX_PATH + 1];
-  l = GetLongPathName(short_name, long_name, MAX_PATH + 1);
+  wchar_t long_name[MAX_PATH + 1];
+  l = GetLongPathNameW(short_name, long_name, MAX_PATH + 1);
   if (l == 0) {
     // Couldn't query the path name for some reason.  Probably the
     // file didn't exist.
@@ -1153,15 +1153,15 @@ make_true_case() {
   }
   assert(l < MAX_PATH + 1);
 
-  Filename true_case = Filename::from_os_specific(long_name);
+  Filename true_case = Filename::from_os_specific_w(long_name);
 
   // Now sanity-check the true-case filename.  If it's not the same as
   // the source file, except for case, reject it.
-  string orig_filename = get_fullpath();
-  string new_filename = true_case.get_fullpath();
+  wstring orig_filename = get_fullpath_w();
+  wstring new_filename = true_case.get_fullpath_w();
   bool match = (orig_filename.length() == new_filename.length());
   for (size_t i = 0; i < orig_filename.length() && match; ++i) {
-    match = (tolower(orig_filename[i]) == tolower(new_filename[i]));
+    match = (TextEncoder::unicode_tolower(orig_filename[i]) == TextEncoder::unicode_tolower(new_filename[i]));
   }
   if (!match) {
     // Something went wrong.  Keep the original filename, assume it
@@ -1287,21 +1287,24 @@ to_os_short_name() const {
   assert(!get_pattern());
 
 #ifdef WIN32
-  string os_specific = to_os_specific();
+  wstring os_specific = to_os_specific_w();
   
-  char short_name[MAX_PATH + 1];
-  DWORD l = GetShortPathName(os_specific.c_str(), short_name, MAX_PATH + 1);
+  wchar_t short_name[MAX_PATH + 1];
+  DWORD l = GetShortPathNameW(os_specific.c_str(), short_name, MAX_PATH + 1);
   if (l == 0) {
     // Couldn't query the path name for some reason.  Probably the
     // file didn't exist.
-    return os_specific;
+    return to_os_specific();
   }
   // According to the Windows docs, l will return a value greater than
   // the specified length if the short_name length wasn't enough--but also
   // according to the Windows docs, MAX_PATH will always be enough.
   assert(l < MAX_PATH + 1);
 
-  return string(short_name);
+  TextEncoder encoder;
+  encoder.set_encoding(get_filesystem_encoding());
+  encoder.set_wtext(short_name);
+  return encoder.get_text();
 
 #else // WIN32
   return to_os_specific();
@@ -1321,18 +1324,21 @@ to_os_long_name() const {
   assert(!get_pattern());
 
 #ifdef WIN32
-  string os_specific = to_os_specific();
+  wstring os_specific = to_os_specific_w();
   
-  char long_name[MAX_PATH + 1];
-  DWORD l = GetLongPathName(os_specific.c_str(), long_name, MAX_PATH + 1);
+  wchar_t long_name[MAX_PATH + 1];
+  DWORD l = GetLongPathNameW(os_specific.c_str(), long_name, MAX_PATH + 1);
   if (l == 0) {
     // Couldn't query the path name for some reason.  Probably the
     // file didn't exist.
-    return os_specific;
+    return to_os_specific();
   }
   assert(l < MAX_PATH + 1);
 
-  return string(long_name);
+  TextEncoder encoder;
+  encoder.set_encoding(get_filesystem_encoding());
+  encoder.set_wtext(long_name);
+  return encoder.get_text();
 
 #else // WIN32
   return to_os_specific();
@@ -1349,17 +1355,19 @@ to_os_long_name() const {
 ////////////////////////////////////////////////////////////////////
 bool Filename::
 exists() const {
-  string os_specific = get_filename_index(0).to_os_specific();
-
 #ifdef WIN32_VC
+  wstring os_specific = get_filename_index(0).to_os_specific_w();
+
   bool exists = false;
 
-  DWORD results = GetFileAttributes(os_specific.c_str());
+  DWORD results = GetFileAttributesW(os_specific.c_str());
   if (results != -1) {
     exists = true;
   }
 
 #else  // WIN32_VC
+  string os_specific = get_filename_index(0).to_os_specific();
+
   struct stat this_buf;
   bool exists = false;
 
@@ -1380,17 +1388,19 @@ exists() const {
 ////////////////////////////////////////////////////////////////////
 bool Filename::
 is_regular_file() const {
-  string os_specific = get_filename_index(0).to_os_specific();
-
 #ifdef WIN32_VC
+  wstring os_specific = get_filename_index(0).to_os_specific_w();
+
   bool isreg = false;
 
-  DWORD results = GetFileAttributes(os_specific.c_str());
+  DWORD results = GetFileAttributesW(os_specific.c_str());
   if (results != -1) {
     isreg = ((results & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0);
   }
 
 #else  // WIN32_VC
+  string os_specific = get_filename_index(0).to_os_specific();
+
   struct stat this_buf;
   bool isreg = false;
 
@@ -1410,16 +1420,18 @@ is_regular_file() const {
 ////////////////////////////////////////////////////////////////////
 bool Filename::
 is_directory() const {
-  string os_specific = get_filename_index(0).to_os_specific();
-
 #ifdef WIN32_VC
+  wstring os_specific = get_filename_index(0).to_os_specific_w();
+
   bool isdir = false;
 
-  DWORD results = GetFileAttributes(os_specific.c_str());
+  DWORD results = GetFileAttributesW(os_specific.c_str());
   if (results != -1) {
     isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
   }
 #else  // WIN32_VC
+  string os_specific = get_filename_index(0).to_os_specific();
+
   struct stat this_buf;
   bool isdir = false;
 
@@ -1475,24 +1487,27 @@ int Filename::
 compare_timestamps(const Filename &other,
                    bool this_missing_is_old,
                    bool other_missing_is_old) const {
-  string os_specific = get_filename_index(0).to_os_specific();
-  string other_os_specific = other.get_filename_index(0).to_os_specific();
-
 #ifdef WIN32_VC
+  wstring os_specific = get_filename_index(0).to_os_specific_w();
+  wstring other_os_specific = other.get_filename_index(0).to_os_specific_w();
+
   struct _stat this_buf;
   bool this_exists = false;
 
-  if (_stat(os_specific.c_str(), &this_buf) == 0) {
+  if (_wstat(os_specific.c_str(), &this_buf) == 0) {
     this_exists = true;
   }
 
   struct _stat other_buf;
   bool other_exists = false;
 
-  if (_stat(other_os_specific.c_str(), &other_buf) == 0) {
+  if (_wstat(other_os_specific.c_str(), &other_buf) == 0) {
     other_exists = true;
   }
 #else  // WIN32_VC
+  string os_specific = get_filename_index(0).to_os_specific();
+  string other_os_specific = other.get_filename_index(0).to_os_specific();
+
   struct stat this_buf;
   bool this_exists = false;
 
@@ -1554,15 +1569,17 @@ compare_timestamps(const Filename &other,
 ////////////////////////////////////////////////////////////////////
 time_t Filename::
 get_timestamp() const {
-  string os_specific = get_filename_index(0).to_os_specific();
-
 #ifdef WIN32_VC
+  wstring os_specific = get_filename_index(0).to_os_specific_w();
+
   struct _stat this_buf;
 
-  if (_stat(os_specific.c_str(), &this_buf) == 0) {
+  if (_wstat(os_specific.c_str(), &this_buf) == 0) {
     return this_buf.st_mtime;
   }
 #else  // WIN32_VC
+  string os_specific = get_filename_index(0).to_os_specific();
+
   struct stat this_buf;
 
   if (stat(os_specific.c_str(), &this_buf) == 0) {
@@ -1583,15 +1600,17 @@ get_timestamp() const {
 ////////////////////////////////////////////////////////////////////
 time_t Filename::
 get_access_timestamp() const {
-  string os_specific = get_filename_index(0).to_os_specific();
-
 #ifdef WIN32_VC
+  wstring os_specific = get_filename_index(0).to_os_specific_w();
+
   struct _stat this_buf;
 
-  if (_stat(os_specific.c_str(), &this_buf) == 0) {
+  if (_wstat(os_specific.c_str(), &this_buf) == 0) {
     return this_buf.st_atime;
   }
 #else  // WIN32_VC
+  string os_specific = get_filename_index(0).to_os_specific();
+
   struct stat this_buf;
 
   if (stat(os_specific.c_str(), &this_buf) == 0) {
@@ -1610,15 +1629,17 @@ get_access_timestamp() const {
 ////////////////////////////////////////////////////////////////////
 off_t Filename::
 get_file_size() const {
-  string os_specific = get_filename_index(0).to_os_specific();
-
 #ifdef WIN32_VC
+  wstring os_specific = get_filename_index(0).to_os_specific_w();
+
   struct _stat this_buf;
 
-  if (_stat(os_specific.c_str(), &this_buf) == 0) {
+  if (_wstat(os_specific.c_str(), &this_buf) == 0) {
     return this_buf.st_size;
   }
 #else  // WIN32_VC
+  string os_specific = get_filename_index(0).to_os_specific();
+
   struct stat this_buf;
 
   if (stat(os_specific.c_str(), &this_buf) == 0) {
@@ -1801,15 +1822,15 @@ scan_directory(vector_string &contents) const {
   // list of files in a directory.
   size_t orig_size = contents.size();
 
-  string match;
+  wstring match;
   if (empty()) {
-    match = "*.*";
+    match = L"*.*";
   } else {
-    match = to_os_specific() + "\\*.*";
+    match = to_os_specific_w() + L"\\*.*";
   }
-  WIN32_FIND_DATA find_data;
+  WIN32_FIND_DATAW find_data;
 
-  HANDLE handle = FindFirstFile(match.c_str(), &find_data);
+  HANDLE handle = FindFirstFileW(match.c_str(), &find_data);
   if (handle == INVALID_HANDLE_VALUE) {
     if (GetLastError() == ERROR_NO_MORE_FILES) {
       // No matching files is not an error.
@@ -1818,13 +1839,16 @@ scan_directory(vector_string &contents) const {
     return false;
   }
 
+  TextEncoder encoder;
+  encoder.set_encoding(get_filesystem_encoding());
   do {
     thread_consider_yield();
-    string filename = find_data.cFileName;
-    if (filename != "." && filename != "..") {
-      contents.push_back(filename);
+    wstring filename = find_data.cFileName;
+    if (filename != L"." && filename != L"..") {
+      encoder.set_wtext(filename);
+      contents.push_back(encoder.get_text());
     }
-  } while (FindNextFile(handle, &find_data));
+  } while (FindNextFileW(handle, &find_data));
 
   bool scan_ok = (GetLastError() == ERROR_NO_MORE_FILES);
   FindClose(handle);
@@ -1980,9 +2004,15 @@ open_read(ifstream &stream) const {
   }
 #endif
 
-  string os_specific = to_os_specific();
   stream.clear();
+#ifdef WIN32_VC
+  wstring os_specific = to_os_specific_w();
   stream.open(os_specific.c_str(), open_mode);
+#else
+  string os_specific = to_os_specific();
+  stream.open(os_specific.c_str(), open_mode);
+#endif  // WIN32_VC
+
   return (!stream.fail());
 }
 
@@ -2031,12 +2061,17 @@ open_write(ofstream &stream, bool truncate) const {
 #endif
 
   stream.clear();
+#ifdef WIN32_VC
+  wstring os_specific = to_os_specific_w();
+  stream.open(os_specific.c_str(), open_mode);
+#else
   string os_specific = to_os_specific();
 #ifdef HAVE_OPEN_MASK
   stream.open(os_specific.c_str(), open_mode, 0666);
 #else
   stream.open(os_specific.c_str(), open_mode);
 #endif
+#endif  // WIN32_VC
 
   return (!stream.fail());
 }
@@ -2068,12 +2103,17 @@ open_append(ofstream &stream) const {
 #endif
 
   stream.clear();
+#ifdef WIN32_VC
+  wstring os_specific = to_os_specific_w();
+  stream.open(os_specific.c_str(), open_mode);
+#else
   string os_specific = to_os_specific();
 #ifdef HAVE_OPEN_MASK
   stream.open(os_specific.c_str(), open_mode, 0666);
 #else
   stream.open(os_specific.c_str(), open_mode);
 #endif
+#endif  // WIN32_VC
 
   return (!stream.fail());
 }
@@ -2115,12 +2155,17 @@ open_read_write(fstream &stream, bool truncate) const {
 #endif
 
   stream.clear();
+#ifdef WIN32_VC
+  wstring os_specific = to_os_specific_w();
+  stream.open(os_specific.c_str(), open_mode);
+#else
   string os_specific = to_os_specific();
 #ifdef HAVE_OPEN_MASK
   stream.open(os_specific.c_str(), open_mode, 0666);
 #else
   stream.open(os_specific.c_str(), open_mode);
 #endif
+#endif  // WIN32_VC
 
   return (!stream.fail());
 }
@@ -2153,12 +2198,17 @@ open_read_append(fstream &stream) const {
 #endif
 
   stream.clear();
+#ifdef WIN32_VC
+  wstring os_specific = to_os_specific_w();
+  stream.open(os_specific.c_str(), open_mode);
+#else
   string os_specific = to_os_specific();
 #ifdef HAVE_OPEN_MASK
   stream.open(os_specific.c_str(), open_mode, 0666);
 #else
   stream.open(os_specific.c_str(), open_mode);
 #endif
+#endif  // WIN32_VC
 
   return (!stream.fail());
 }
@@ -2397,10 +2447,10 @@ touch() const {
   // In Windows, we have to use the Windows API to do this reliably.
 
   // First, guarantee the file exists (and also get its handle).
-  string os_specific = to_os_specific();
+  wstring os_specific = to_os_specific_w();
   HANDLE fhandle;
-  fhandle = CreateFile(os_specific.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
-                       NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+  fhandle = CreateFileW(os_specific.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
+                        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   if (fhandle == INVALID_HANDLE_VALUE) {
     return false;
   }
@@ -2473,8 +2523,13 @@ touch() const {
 ////////////////////////////////////////////////////////////////////
 bool Filename::
 chdir() const {
+#ifdef WIN32_VC
+  wstring os_specific = to_os_specific_w();
+  return (_wchdir(os_specific.c_str()) >= 0);
+#else
   string os_specific = to_os_specific();
   return (::chdir(os_specific.c_str()) >= 0);
+#endif  // WIN32_VC
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2488,12 +2543,15 @@ chdir() const {
 bool Filename::
 unlink() const {
   assert(!get_pattern());
-  string os_specific = to_os_specific();
-#ifdef _WIN32
+#ifdef WIN32_VC
   // Windows can't delete a file if it's read-only.  Weird.
-  chmod(os_specific.c_str(), 0644);
-#endif
+  wstring os_specific = to_os_specific_w();
+  _wchmod(os_specific.c_str(), 0644);
+  return (_wunlink(os_specific.c_str()) == 0);
+#else
+  string os_specific = to_os_specific();
   return (::unlink(os_specific.c_str()) == 0);
+#endif  // WIN32_VC
 }
 
 
@@ -2514,6 +2572,46 @@ rename_to(const Filename &other) const {
     return true;
   }
 
+#ifdef WIN32_VC
+  wstring os_specific = to_os_specific_w();
+  wstring other_os_specific = other.to_os_specific_w();
+
+  if (_wrename(os_specific.c_str(),
+               other_os_specific.c_str()) == 0) {
+    // Successfully renamed.
+    return true;
+  }
+
+  // The above might fail if we have tried to move a file to a
+  // different filesystem.  In this case, copy the file into the same
+  // directory first, and then rename it.
+  string dirname = other.get_dirname();
+  if (dirname.empty()) {
+    dirname = ".";
+  }
+  Filename temp = Filename::temporary(dirname, "");
+  temp.set_binary();
+  if (!Filename::binary_filename(*this).copy_to(temp)) {
+    return false;
+  }
+
+  wstring temp_os_specific = temp.to_os_specific_w();
+  if (_wrename(temp_os_specific.c_str(),
+               other_os_specific.c_str()) == 0) {
+    // Successfully renamed.
+    unlink();
+    return true;
+  }
+
+  // Try unlinking the target first.
+  other.unlink();
+  if (_wrename(temp_os_specific.c_str(),
+               other_os_specific.c_str()) == 0) {
+    // Successfully renamed.
+    unlink();
+    return true;
+  }
+#else  // WIN32_VC
   string os_specific = to_os_specific();
   string other_os_specific = other.to_os_specific();
 
@@ -2552,6 +2650,7 @@ rename_to(const Filename &other) const {
     unlink();
     return true;
   }
+#endif  // WIN32_VC
 
   // Failed.
   temp.unlink();
@@ -2644,23 +2743,25 @@ make_dir() const {
   size_t slash = dirname.find('/');
   while (slash != string::npos) {
     Filename component(dirname.substr(0, slash));
+#ifdef WIN32_VC
+    wstring os_specific = component.to_os_specific_w();
+    _wmkdir(os_specific.c_str());
+#else
     string os_specific = component.to_os_specific();
-#ifndef WIN32_VC
     ::mkdir(os_specific.c_str(), 0777);
-#else
-    ::mkdir(os_specific.c_str());
-#endif
+#endif  // WIN32_VC
     slash = dirname.find('/', slash + 1);
   }
 
   // Now make the last one, and check the return value.
   Filename component(dirname);
-  string os_specific = component.to_os_specific();
-#ifndef WIN32_VC
-  int result = ::mkdir(os_specific.c_str(), 0777);
+#ifdef WIN32_VC
+  wstring os_specific = component.to_os_specific_w();
+  int result = _wmkdir(os_specific.c_str());
 #else
-  int result = ::mkdir(os_specific.c_str());
-#endif
+  string os_specific = component.to_os_specific();
+  int resutl = ::mkdir(os_specific.c_str(), 0777);
+#endif  // WIN32_VC
 
   return (result == 0);
 }
@@ -2676,12 +2777,13 @@ make_dir() const {
 ////////////////////////////////////////////////////////////////////
 bool Filename::
 mkdir() const {
+#ifdef WIN32_VC
+  wstring os_specific = to_os_specific_w();
+  int result = _wmkdir(os_specific.c_str());
+#else
   string os_specific = to_os_specific();
-#ifndef WIN32_VC
   int result = ::mkdir(os_specific.c_str(), 0777);
-#else
-  int result = ::mkdir(os_specific.c_str());
-#endif
+#endif  // WIN32_VC
 
   return (result == 0);
 }
@@ -2694,18 +2796,21 @@ mkdir() const {
 ////////////////////////////////////////////////////////////////////
 bool Filename::
 rmdir() const {
-  string os_specific = to_os_specific();
-
-  int result = ::rmdir(os_specific.c_str());
+#ifdef WIN32_VC
+  wstring os_specific = to_os_specific_w();
 
-#ifdef WIN32
+  int result = _wrmdir(os_specific.c_str());
   if (result != 0) {
     // Windows may require the directory to be writable before we can
     // remove it.
-    chmod(os_specific.c_str(), 0777);
-    result = ::rmdir(os_specific.c_str());
+    _wchmod(os_specific.c_str(), 0777);
+    result = _wrmdir(os_specific.c_str());
   }
-#endif
+
+#else  // WIN32_VC
+  string os_specific = to_os_specific();
+  int result = ::rmdir(os_specific.c_str());
+#endif  // WIN32_VC
 
   return (result == 0);
 }
@@ -2792,18 +2897,18 @@ atomic_compare_and_exchange_contents(string &orig_contents,
                                      const string &old_contents, 
                                      const string &new_contents) const {
 #ifdef WIN32_VC
-  string os_specific = to_os_specific();
-  HANDLE hfile = CreateFile(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE, 
-                            0, NULL, OPEN_ALWAYS,
-                            FILE_ATTRIBUTE_NORMAL, NULL);
+  wstring os_specific = to_os_specific_w();
+  HANDLE hfile = CreateFileW(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE, 
+                             0, NULL, OPEN_ALWAYS,
+                             FILE_ATTRIBUTE_NORMAL, NULL);
   while (hfile == INVALID_HANDLE_VALUE) {
     DWORD error = GetLastError();
     if (error == ERROR_SHARING_VIOLATION) {
       // If the file is locked by another process, yield and try again.
       Sleep(0);
-      hfile = CreateFile(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE, 
-                         0, NULL, OPEN_ALWAYS,
-                         FILE_ATTRIBUTE_NORMAL, NULL);
+      hfile = CreateFileW(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE, 
+                          0, NULL, OPEN_ALWAYS,
+                          FILE_ATTRIBUTE_NORMAL, NULL);
     } else {
       cerr << "Couldn't open file: " << os_specific 
            << ", error " << error << "\n";
@@ -2929,18 +3034,18 @@ atomic_compare_and_exchange_contents(string &orig_contents,
 bool Filename::
 atomic_read_contents(string &contents) const {
 #ifdef WIN32_VC
-  string os_specific = to_os_specific();
-  HANDLE hfile = CreateFile(os_specific.c_str(), GENERIC_READ, 
-                            FILE_SHARE_READ, NULL, OPEN_ALWAYS,
-                            FILE_ATTRIBUTE_NORMAL, NULL);
+  wstring os_specific = to_os_specific_w();
+  HANDLE hfile = CreateFileW(os_specific.c_str(), GENERIC_READ, 
+                             FILE_SHARE_READ, NULL, OPEN_ALWAYS,
+                             FILE_ATTRIBUTE_NORMAL, NULL);
   while (hfile == INVALID_HANDLE_VALUE) {
     DWORD error = GetLastError();
     if (error == ERROR_SHARING_VIOLATION) {
       // If the file is locked by another process, yield and try again.
       Sleep(0);
-      hfile = CreateFile(os_specific.c_str(), GENERIC_READ, 
-                         FILE_SHARE_READ, NULL, OPEN_ALWAYS,
-                         FILE_ATTRIBUTE_NORMAL, NULL);      
+      hfile = CreateFileW(os_specific.c_str(), GENERIC_READ, 
+                          FILE_SHARE_READ, NULL, OPEN_ALWAYS,
+                          FILE_ATTRIBUTE_NORMAL, NULL);      
     } else {
       cerr << "Couldn't open file: " << os_specific 
            << ", error " << error << "\n";
@@ -3210,9 +3315,23 @@ r_make_canonical(const Filename &cwd) {
     return false;
   }
 
+#ifdef WIN32_VC
   // First, try to cd to the filename directly.
-  string os_specific = to_os_specific();
+  wstring os_specific = to_os_specific_w();
+  if (_wchdir(os_specific.c_str()) >= 0) {
+    // That worked, save the full path string.
+    (*this) = ExecutionEnvironment::get_cwd();
 
+    // And restore the current working directory.
+    wstring osdir = cwd.to_os_specific_w();
+    if (_wchdir(osdir.c_str()) < 0) {
+      cerr << "Error!  Cannot change back to " << osdir << "\n";
+    }
+    return true;
+  }
+#else  // WIN32_VC
+  // First, try to cd to the filename directly.
+  string os_specific = to_os_specific();
   if (::chdir(os_specific.c_str()) >= 0) {
     // That worked, save the full path string.
     (*this) = ExecutionEnvironment::get_cwd();
@@ -3224,6 +3343,7 @@ r_make_canonical(const Filename &cwd) {
     }
     return true;
   }
+#endif  // WIN32_VC
 
   // That didn't work; maybe it's not a directory.  Recursively go to
   // the directory above.

+ 8 - 2
dtool/src/dtoolutil/pandaFileStreamBuf.cxx

@@ -14,6 +14,8 @@
 
 #include "pandaFileStreamBuf.h"
 #include "memoryHook.h"
+#include "filename.h"
+#include "textEncoder.h"
 
 #ifdef USE_PANDAFILESTREAM
 
@@ -133,8 +135,12 @@ open(const char *filename, ios::openmode mode) {
   flags |= FILE_FLAG_OVERLAPPED;
 #endif
 
-  _handle = CreateFile(_filename.c_str(), access, share_mode,
-                       NULL, creation_disposition, flags, NULL);
+  TextEncoder encoder;
+  encoder.set_encoding(Filename::get_filesystem_encoding());
+  encoder.set_text(_filename);
+  wstring wfilename = encoder.get_wtext();
+  _handle = CreateFileW(wfilename.c_str(), access, share_mode,
+                        NULL, creation_disposition, flags, NULL);
   if (_handle != INVALID_HANDLE_VALUE) {
     // The file was successfully opened and locked.
     _is_open = true;