/* * Test program to try unicode file names. * * Copyright (C) 1998-2019 Toni Ronkko * This file is part of dirent. Dirent may be freely distributed * under the MIT license. For all details and documentation, see * https://github.com/tronkko/dirent */ /* Silence warning about fopen being insecure */ #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #undef NDEBUG #include int main( int argc, char *argv[]) { #ifdef WIN32 wchar_t wpath[MAX_PATH+1]; char path[MAX_PATH+1]; DWORD i, j, k, x; BOOL ok; HANDLE fh; _WDIR *wdir; struct _wdirent *wentry; DIR *dir; struct dirent *entry; char buffer[100]; FILE *fp; int counter = 0; (void) argc; (void) argv; /* Initialize random number generator */ srand (((int) time (NULL)) * 257 + ((int) GetCurrentProcessId ())); /* Set current locale */ if (argc > 1) { printf ("Locale %s\n", argv[1]); setlocale (LC_ALL, argv[1]); } else { setlocale (LC_ALL, ""); } /****** CREATE FILE WITH UNICODE FILE NAME ******/ /* Get path to temporary directory (wide-character and ascii) */ i = GetTempPathW (MAX_PATH, wpath); assert (i > 0); j = GetTempPathA (MAX_PATH, path); assert (j > 0); /* Append random directory name */ for (k = 0; k < 10; k++) { char c; /* Generate random character */ c = "abcdefghijklmnopqrstuvwxyz"[rand() % 26]; /* Append character to paths */ assert (i < MAX_PATH && j < MAX_PATH); wpath[i++] = c; path[j++] = c; } /* Terminate paths */ assert (i < MAX_PATH && j < MAX_PATH); wpath[i] = '\0'; path[j] = '\0'; /* Remember the end of directory name */ k = i; /* Create directory using unicode */ ok = CreateDirectoryW (wpath, NULL); if (!ok) { DWORD e = GetLastError (); wprintf (L"Cannot create directory %ls (code %u)\n", wpath, e); abort (); } /* Overwrite zero terminator with path separator */ assert (i < MAX_PATH && j < MAX_PATH); wpath[i++] = '\\'; /* Append a few unicode characters */ assert (i < MAX_PATH); wpath[i++] = 0x6d4b; assert (i < MAX_PATH); wpath[i++] = 0x8bd5; /* Terminate string */ assert (i < MAX_PATH); wpath[i] = '\0'; /* Create file with unicode */ fh = CreateFileW( wpath, /* Access */ GENERIC_READ | GENERIC_WRITE, /* Share mode */ 0, /* Security attributes */ NULL, /* Creation disposition */ CREATE_NEW, /* Attributes */ FILE_ATTRIBUTE_NORMAL, /* Template files */ NULL ); assert (fh != INVALID_HANDLE_VALUE); /* Write some data to file */ ok = WriteFile( /* File handle */ fh, /* Pointer to data */ "hep\n", /* Number of bytes to write */ 4, /* Number of bytes written */ NULL, /* Overlapped */ NULL ); assert (ok); /* Close file */ ok = CloseHandle (fh); assert (ok); /****** MAKE SURE THAT UNICODE FILE NAME CAN BE READ BY _WREADDIR ******/ /* Zero terminate wide-character path and open directory stream */ wpath[k] = '\0'; wdir = _wopendir (wpath); if (wdir == NULL) { wprintf (L"Cannot open directory %ls\n", wpath); abort (); } /* Read through entries */ counter = 0; while ((wentry = _wreaddir (wdir)) != NULL) { /* Skip pseudo directories */ if (wcscmp (wentry->d_name, L".") == 0) { continue; } if (wcscmp (wentry->d_name, L"..") == 0) { continue; } /* Found a file */ counter++; assert (wentry->d_type == DT_REG); /* Append file name to path */ i = k; assert (i < MAX_PATH); wpath[i++] = '\\'; x = 0; while (wentry->d_name[x] != '\0') { assert (i < MAX_PATH); wpath[i++] = wentry->d_name[x++]; } assert (i < MAX_PATH); wpath[i] = '\0'; /* Open file for read */ fh = CreateFileW( wpath, /* Access */ GENERIC_READ, /* Share mode */ 0, /* Security attributes */ NULL, /* Creation disposition */ OPEN_EXISTING, /* Attributes */ FILE_ATTRIBUTE_NORMAL, /* Template files */ NULL ); assert (fh != INVALID_HANDLE_VALUE); /* Read data from file */ ok = ReadFile( /* File handle */ fh, /* Output buffer */ buffer, /* Maximum number of bytes to read */ sizeof (buffer) - 1, /* Number of bytes actually read */ &x, /* Overlapped */ NULL ); assert (ok); /* Make sure that we got the file contents right */ assert (x == 4); assert (buffer[0] == 'h'); assert (buffer[1] == 'e'); assert (buffer[2] == 'p'); assert (buffer[3] == '\n'); /* Close file */ ok = CloseHandle (fh); assert (ok); } assert (counter == 1); /* Close directory */ _wclosedir (wdir); /****** MAKE SURE THAT UNICODE FILE NAME CAN BE READ BY READDIR ******/ /* Zero terminate ascii path and open directory stream */ k = j; path[k] = '\0'; dir = opendir (path); if (dir == NULL) { fprintf (stderr, "Cannot open directory %s\n", path); abort (); } /* Read through entries */ counter = 0; while ((entry = readdir (dir)) != NULL) { /* Skip pseudo directories */ if (strcmp (entry->d_name, ".") == 0) { continue; } if (strcmp (entry->d_name, "..") == 0) { continue; } /* Found a file */ counter++; assert (entry->d_type == DT_REG); /* Append file name to path */ j = k; assert (j < MAX_PATH); path[j++] = '\\'; x = 0; while (entry->d_name[x] != '\0') { assert (j < MAX_PATH); path[j++] = entry->d_name[x++]; } assert (j < MAX_PATH); path[j] = '\0'; /* Open file for read */ fp = fopen (path, "r"); if (!fp) { fprintf (stderr, "Cannot open file %s\n", path); abort (); } /* Read data from file */ if (fgets (buffer, sizeof (buffer), fp) == NULL) { fprintf (stderr, "Cannot read file %s\n", path); abort (); } /* Make sure that we got the file contents right */ assert (buffer[0] == 'h'); assert (buffer[1] == 'e'); assert (buffer[2] == 'p'); assert (buffer[3] == '\n'); assert (buffer[4] == '\0'); /* Close file */ fclose (fp); } assert (counter == 1); /* Close directory */ closedir (dir); /****** CREATE FILE WITH UTF-8 ******/ /* Append UTF-8 file name (åäö.txt) to path */ j = k; path[j++] = '\\'; path[j++] = 0xc3; path[j++] = 0xa5; path[j++] = 0xc3; path[j++] = 0xa4; path[j++] = 0xc3; path[j++] = 0xb6; path[j++] = 0x2e; path[j++] = 0x74; path[j++] = 0x78; path[j++] = 0x74; assert (j < MAX_PATH); path[j] = '\0'; /* * Create file. * * Be ware that the code below creates a different file depending on the * current locale! For example, if the current locale is * english_us.65001, then the file name will be "åäö.txt" (7 characters). * However, if the current locale is english_us.1252, then the file name * will be "ÃċÃĊö.txt" (10 characters). */ printf ("Creating %s\n", path); fp = fopen (path, "w"); if (!fp) { fprintf (stderr, "Cannot open file %s\n", path); abort (); } fputs ("hep\n", fp); fclose (fp); /* Open directory again */ path[k] = '\0'; dir = opendir (path); if (dir == NULL) { fprintf (stderr, "Cannot open directory %s\n", path); abort (); } /* Read through entries */ counter = 0; while ((entry = readdir (dir)) != NULL) { /* Skip pseudo directories */ if (strcmp (entry->d_name, ".") == 0) { continue; } if (strcmp (entry->d_name, "..") == 0) { continue; } /* Found a file */ counter++; assert (entry->d_type == DT_REG); /* Append file name to path */ j = k; assert (j < MAX_PATH); path[j++] = '\\'; x = 0; while (entry->d_name[x] != '\0') { assert (j < MAX_PATH); path[j++] = entry->d_name[x++]; } assert (j < MAX_PATH); path[j] = '\0'; /* Print file name for debugging */ printf ("Opening \"%s\" hex ", path + k + 1); x = 0; while (entry->d_name[x] != '\0') { printf ("0x%02x ", (unsigned) (entry->d_name[x++] & 0xff)); } printf ("\n"); /* Open file for read */ fp = fopen (path, "r"); if (!fp) { fprintf (stderr, "Cannot open file %s\n", path); abort (); } /* Read data from file */ if (fgets (buffer, sizeof (buffer), fp) == NULL) { fprintf (stderr, "Cannot read file %s\n", path); abort (); } /* Make sure that we got the file contents right */ assert (buffer[0] == 'h'); assert (buffer[1] == 'e'); assert (buffer[2] == 'p'); assert (buffer[3] == '\n'); assert (buffer[4] == '\0'); /* Close file */ fclose (fp); } assert (counter == 2); /* Close directory */ closedir (dir); #else /* Linux */ (void) argc; (void) argv; #endif return EXIT_SUCCESS; }