🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

401 lines
9.8 KiB

  1. /*
  2. * Test program to try unicode file names.
  3. *
  4. * Copyright (C) 1998-2019 Toni Ronkko
  5. * This file is part of dirent. Dirent may be freely distributed
  6. * under the MIT license. For all details and documentation, see
  7. * https://github.com/tronkko/dirent
  8. */
  9. /* Silence warning about fopen being insecure */
  10. #define _CRT_SECURE_NO_WARNINGS
  11. #include <dirent.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <wchar.h>
  16. #include <time.h>
  17. #include <locale.h>
  18. #undef NDEBUG
  19. #include <assert.h>
  20. int
  21. main(
  22. int argc, char *argv[])
  23. {
  24. #ifdef WIN32
  25. wchar_t wpath[MAX_PATH+1];
  26. char path[MAX_PATH+1];
  27. DWORD i, j, k, x;
  28. BOOL ok;
  29. HANDLE fh;
  30. _WDIR *wdir;
  31. struct _wdirent *wentry;
  32. DIR *dir;
  33. struct dirent *entry;
  34. char buffer[100];
  35. FILE *fp;
  36. int counter = 0;
  37. (void) argc;
  38. (void) argv;
  39. /* Initialize random number generator */
  40. srand (((int) time (NULL)) * 257 + ((int) GetCurrentProcessId ()));
  41. /* Set current locale */
  42. if (argc > 1) {
  43. printf ("Locale %s\n", argv[1]);
  44. setlocale (LC_ALL, argv[1]);
  45. } else {
  46. setlocale (LC_ALL, "");
  47. }
  48. /****** CREATE FILE WITH UNICODE FILE NAME ******/
  49. /* Get path to temporary directory (wide-character and ascii) */
  50. i = GetTempPathW (MAX_PATH, wpath);
  51. assert (i > 0);
  52. j = GetTempPathA (MAX_PATH, path);
  53. assert (j > 0);
  54. /* Append random directory name */
  55. for (k = 0; k < 10; k++) {
  56. char c;
  57. /* Generate random character */
  58. c = "abcdefghijklmnopqrstuvwxyz"[rand() % 26];
  59. /* Append character to paths */
  60. assert (i < MAX_PATH && j < MAX_PATH);
  61. wpath[i++] = c;
  62. path[j++] = c;
  63. }
  64. /* Terminate paths */
  65. assert (i < MAX_PATH && j < MAX_PATH);
  66. wpath[i] = '\0';
  67. path[j] = '\0';
  68. /* Remember the end of directory name */
  69. k = i;
  70. /* Create directory using unicode */
  71. ok = CreateDirectoryW (wpath, NULL);
  72. if (!ok) {
  73. DWORD e = GetLastError ();
  74. wprintf (L"Cannot create directory %ls (code %u)\n", wpath, e);
  75. abort ();
  76. }
  77. /* Overwrite zero terminator with path separator */
  78. assert (i < MAX_PATH && j < MAX_PATH);
  79. wpath[i++] = '\\';
  80. /* Append a few unicode characters */
  81. assert (i < MAX_PATH);
  82. wpath[i++] = 0x6d4b;
  83. assert (i < MAX_PATH);
  84. wpath[i++] = 0x8bd5;
  85. /* Terminate string */
  86. assert (i < MAX_PATH);
  87. wpath[i] = '\0';
  88. /* Create file with unicode */
  89. fh = CreateFileW(
  90. wpath,
  91. /* Access */ GENERIC_READ | GENERIC_WRITE,
  92. /* Share mode */ 0,
  93. /* Security attributes */ NULL,
  94. /* Creation disposition */ CREATE_NEW,
  95. /* Attributes */ FILE_ATTRIBUTE_NORMAL,
  96. /* Template files */ NULL
  97. );
  98. assert (fh != INVALID_HANDLE_VALUE);
  99. /* Write some data to file */
  100. ok = WriteFile(
  101. /* File handle */ fh,
  102. /* Pointer to data */ "hep\n",
  103. /* Number of bytes to write */ 4,
  104. /* Number of bytes written */ NULL,
  105. /* Overlapped */ NULL
  106. );
  107. assert (ok);
  108. /* Close file */
  109. ok = CloseHandle (fh);
  110. assert (ok);
  111. /****** MAKE SURE THAT UNICODE FILE NAME CAN BE READ BY _WREADDIR ******/
  112. /* Zero terminate wide-character path and open directory stream */
  113. wpath[k] = '\0';
  114. wdir = _wopendir (wpath);
  115. if (wdir == NULL) {
  116. wprintf (L"Cannot open directory %ls\n", wpath);
  117. abort ();
  118. }
  119. /* Read through entries */
  120. counter = 0;
  121. while ((wentry = _wreaddir (wdir)) != NULL) {
  122. /* Skip pseudo directories */
  123. if (wcscmp (wentry->d_name, L".") == 0) {
  124. continue;
  125. }
  126. if (wcscmp (wentry->d_name, L"..") == 0) {
  127. continue;
  128. }
  129. /* Found a file */
  130. counter++;
  131. assert (wentry->d_type == DT_REG);
  132. /* Append file name to path */
  133. i = k;
  134. assert (i < MAX_PATH);
  135. wpath[i++] = '\\';
  136. x = 0;
  137. while (wentry->d_name[x] != '\0') {
  138. assert (i < MAX_PATH);
  139. wpath[i++] = wentry->d_name[x++];
  140. }
  141. assert (i < MAX_PATH);
  142. wpath[i] = '\0';
  143. /* Open file for read */
  144. fh = CreateFileW(
  145. wpath,
  146. /* Access */ GENERIC_READ,
  147. /* Share mode */ 0,
  148. /* Security attributes */ NULL,
  149. /* Creation disposition */ OPEN_EXISTING,
  150. /* Attributes */ FILE_ATTRIBUTE_NORMAL,
  151. /* Template files */ NULL
  152. );
  153. assert (fh != INVALID_HANDLE_VALUE);
  154. /* Read data from file */
  155. ok = ReadFile(
  156. /* File handle */ fh,
  157. /* Output buffer */ buffer,
  158. /* Maximum number of bytes to read */ sizeof (buffer) - 1,
  159. /* Number of bytes actually read */ &x,
  160. /* Overlapped */ NULL
  161. );
  162. assert (ok);
  163. /* Make sure that we got the file contents right */
  164. assert (x == 4);
  165. assert (buffer[0] == 'h');
  166. assert (buffer[1] == 'e');
  167. assert (buffer[2] == 'p');
  168. assert (buffer[3] == '\n');
  169. /* Close file */
  170. ok = CloseHandle (fh);
  171. assert (ok);
  172. }
  173. assert (counter == 1);
  174. /* Close directory */
  175. _wclosedir (wdir);
  176. /****** MAKE SURE THAT UNICODE FILE NAME CAN BE READ BY READDIR ******/
  177. /* Zero terminate ascii path and open directory stream */
  178. k = j;
  179. path[k] = '\0';
  180. dir = opendir (path);
  181. if (dir == NULL) {
  182. fprintf (stderr, "Cannot open directory %s\n", path);
  183. abort ();
  184. }
  185. /* Read through entries */
  186. counter = 0;
  187. while ((entry = readdir (dir)) != NULL) {
  188. /* Skip pseudo directories */
  189. if (strcmp (entry->d_name, ".") == 0) {
  190. continue;
  191. }
  192. if (strcmp (entry->d_name, "..") == 0) {
  193. continue;
  194. }
  195. /* Found a file */
  196. counter++;
  197. assert (entry->d_type == DT_REG);
  198. /* Append file name to path */
  199. j = k;
  200. assert (j < MAX_PATH);
  201. path[j++] = '\\';
  202. x = 0;
  203. while (entry->d_name[x] != '\0') {
  204. assert (j < MAX_PATH);
  205. path[j++] = entry->d_name[x++];
  206. }
  207. assert (j < MAX_PATH);
  208. path[j] = '\0';
  209. /* Open file for read */
  210. fp = fopen (path, "r");
  211. if (!fp) {
  212. fprintf (stderr, "Cannot open file %s\n", path);
  213. abort ();
  214. }
  215. /* Read data from file */
  216. if (fgets (buffer, sizeof (buffer), fp) == NULL) {
  217. fprintf (stderr, "Cannot read file %s\n", path);
  218. abort ();
  219. }
  220. /* Make sure that we got the file contents right */
  221. assert (buffer[0] == 'h');
  222. assert (buffer[1] == 'e');
  223. assert (buffer[2] == 'p');
  224. assert (buffer[3] == '\n');
  225. assert (buffer[4] == '\0');
  226. /* Close file */
  227. fclose (fp);
  228. }
  229. assert (counter == 1);
  230. /* Close directory */
  231. closedir (dir);
  232. /****** CREATE FILE WITH UTF-8 ******/
  233. /* Append UTF-8 file name (åäö.txt) to path */
  234. j = k;
  235. path[j++] = '\\';
  236. path[j++] = 0xc3;
  237. path[j++] = 0xa5;
  238. path[j++] = 0xc3;
  239. path[j++] = 0xa4;
  240. path[j++] = 0xc3;
  241. path[j++] = 0xb6;
  242. path[j++] = 0x2e;
  243. path[j++] = 0x74;
  244. path[j++] = 0x78;
  245. path[j++] = 0x74;
  246. assert (j < MAX_PATH);
  247. path[j] = '\0';
  248. /*
  249. * Create file.
  250. *
  251. * Be ware that the code below creates a different file depending on the
  252. * current locale! For example, if the current locale is
  253. * english_us.65001, then the file name will be "åäö.txt" (7 characters).
  254. * However, if the current locale is english_us.1252, then the file name
  255. * will be "ÃċÃĊö.txt" (10 characters).
  256. */
  257. printf ("Creating %s\n", path);
  258. fp = fopen (path, "w");
  259. if (!fp) {
  260. fprintf (stderr, "Cannot open file %s\n", path);
  261. abort ();
  262. }
  263. fputs ("hep\n", fp);
  264. fclose (fp);
  265. /* Open directory again */
  266. path[k] = '\0';
  267. dir = opendir (path);
  268. if (dir == NULL) {
  269. fprintf (stderr, "Cannot open directory %s\n", path);
  270. abort ();
  271. }
  272. /* Read through entries */
  273. counter = 0;
  274. while ((entry = readdir (dir)) != NULL) {
  275. /* Skip pseudo directories */
  276. if (strcmp (entry->d_name, ".") == 0) {
  277. continue;
  278. }
  279. if (strcmp (entry->d_name, "..") == 0) {
  280. continue;
  281. }
  282. /* Found a file */
  283. counter++;
  284. assert (entry->d_type == DT_REG);
  285. /* Append file name to path */
  286. j = k;
  287. assert (j < MAX_PATH);
  288. path[j++] = '\\';
  289. x = 0;
  290. while (entry->d_name[x] != '\0') {
  291. assert (j < MAX_PATH);
  292. path[j++] = entry->d_name[x++];
  293. }
  294. assert (j < MAX_PATH);
  295. path[j] = '\0';
  296. /* Print file name for debugging */
  297. printf ("Opening \"%s\" hex ", path + k + 1);
  298. x = 0;
  299. while (entry->d_name[x] != '\0') {
  300. printf ("0x%02x ", (unsigned) (entry->d_name[x++] & 0xff));
  301. }
  302. printf ("\n");
  303. /* Open file for read */
  304. fp = fopen (path, "r");
  305. if (!fp) {
  306. fprintf (stderr, "Cannot open file %s\n", path);
  307. abort ();
  308. }
  309. /* Read data from file */
  310. if (fgets (buffer, sizeof (buffer), fp) == NULL) {
  311. fprintf (stderr, "Cannot read file %s\n", path);
  312. abort ();
  313. }
  314. /* Make sure that we got the file contents right */
  315. assert (buffer[0] == 'h');
  316. assert (buffer[1] == 'e');
  317. assert (buffer[2] == 'p');
  318. assert (buffer[3] == '\n');
  319. assert (buffer[4] == '\0');
  320. /* Close file */
  321. fclose (fp);
  322. }
  323. assert (counter == 2);
  324. /* Close directory */
  325. closedir (dir);
  326. #else
  327. /* Linux */
  328. (void) argc;
  329. (void) argv;
  330. #endif
  331. return EXIT_SUCCESS;
  332. }