exfat_nls.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. */
  18. #include "exfat_config.h"
  19. #include "exfat_global.h"
  20. #include "exfat_data.h"
  21. #include "exfat_nls.h"
  22. #include "exfat_api.h"
  23. #include "exfat_super.h"
  24. #include "exfat.h"
  25. #include <linux/nls.h>
  26. static UINT16 bad_dos_chars[] = {
  27. 0x002B, 0x002C, 0x003B, 0x003D, 0x005B, 0x005D,
  28. 0xFF0B, 0xFF0C, 0xFF1B, 0xFF1D, 0xFF3B, 0xFF3D,
  29. 0
  30. };
  31. static UINT16 bad_uni_chars[] = {
  32. 0x0022, 0x002A, 0x002F, 0x003A,
  33. 0x003C, 0x003E, 0x003F, 0x005C, 0x007C,
  34. 0
  35. };
  36. static INT32 convert_uni_to_ch(struct nls_table *nls, UINT8 *ch, UINT16 uni, INT32 *lossy);
  37. static INT32 convert_ch_to_uni(struct nls_table *nls, UINT16 *uni, UINT8 *ch, INT32 *lossy);
  38. UINT16 nls_upper(struct super_block *sb, UINT16 a)
  39. {
  40. FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
  41. if (EXFAT_SB(sb)->options.casesensitive)
  42. return(a);
  43. if ((p_fs->vol_utbl)[get_col_index(a)] != NULL)
  44. return (p_fs->vol_utbl)[get_col_index(a)][get_row_index(a)];
  45. else
  46. return a;
  47. }
  48. INT32 nls_dosname_cmp(struct super_block *sb, UINT8 *a, UINT8 *b)
  49. {
  50. return(STRNCMP((void *) a, (void *) b, DOS_NAME_LENGTH));
  51. }
  52. INT32 nls_uniname_cmp(struct super_block *sb, UINT16 *a, UINT16 *b)
  53. {
  54. INT32 i;
  55. for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) {
  56. if (nls_upper(sb, *a) != nls_upper(sb, *b)) return(1);
  57. if (*a == 0x0) return(0);
  58. }
  59. return(0);
  60. }
  61. void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, INT32 *p_lossy)
  62. {
  63. INT32 i, j, len, lossy = FALSE;
  64. UINT8 buf[MAX_CHARSET_SIZE];
  65. UINT8 lower = 0, upper = 0;
  66. UINT8 *dosname = p_dosname->name;
  67. UINT16 *uniname = p_uniname->name;
  68. UINT16 *p, *last_period;
  69. struct nls_table *nls = EXFAT_SB(sb)->nls_disk;
  70. for (i = 0; i < DOS_NAME_LENGTH; i++) {
  71. *(dosname+i) = ' ';
  72. }
  73. if (!nls_uniname_cmp(sb, uniname, (UINT16 *) UNI_CUR_DIR_NAME)) {
  74. *(dosname) = '.';
  75. p_dosname->name_case = 0x0;
  76. if (p_lossy != NULL) *p_lossy = FALSE;
  77. return;
  78. }
  79. if (!nls_uniname_cmp(sb, uniname, (UINT16 *) UNI_PAR_DIR_NAME)) {
  80. *(dosname) = '.';
  81. *(dosname+1) = '.';
  82. p_dosname->name_case = 0x0;
  83. if (p_lossy != NULL) *p_lossy = FALSE;
  84. return;
  85. }
  86. last_period = NULL;
  87. for (p = uniname; *p; p++) {
  88. if (*p == (UINT16) '.') last_period = p;
  89. }
  90. i = 0;
  91. while (i < DOS_NAME_LENGTH) {
  92. if (i == 8) {
  93. if (last_period == NULL) break;
  94. if (uniname <= last_period) {
  95. if (uniname < last_period) lossy = TRUE;
  96. uniname = last_period + 1;
  97. }
  98. }
  99. if (*uniname == (UINT16) '\0') {
  100. break;
  101. } else if (*uniname == (UINT16) ' ') {
  102. lossy = TRUE;
  103. } else if (*uniname == (UINT16) '.') {
  104. if (uniname < last_period) lossy = TRUE;
  105. else i = 8;
  106. } else if (WSTRCHR(bad_dos_chars, *uniname)) {
  107. lossy = TRUE;
  108. *(dosname+i) = '_';
  109. i++;
  110. } else {
  111. len = convert_uni_to_ch(nls, buf, *uniname, &lossy);
  112. if (len > 1) {
  113. if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH)) {
  114. break;
  115. }
  116. if ((i < 8) && ((i+len) > 8)) {
  117. i = 8;
  118. continue;
  119. }
  120. lower = 0xFF;
  121. for (j = 0; j < len; j++, i++) {
  122. *(dosname+i) = *(buf+j);
  123. }
  124. } else {
  125. if ((*buf >= 'a') && (*buf <= 'z')) {
  126. *(dosname+i) = *buf - ('a' - 'A');
  127. if (i < 8) lower |= 0x08;
  128. else lower |= 0x10;
  129. } else if ((*buf >= 'A') && (*buf <= 'Z')) {
  130. *(dosname+i) = *buf;
  131. if (i < 8) upper |= 0x08;
  132. else upper |= 0x10;
  133. } else {
  134. *(dosname+i) = *buf;
  135. }
  136. i++;
  137. }
  138. }
  139. uniname++;
  140. }
  141. if (*dosname == 0xE5) *dosname = 0x05;
  142. if (*uniname != 0x0) lossy = TRUE;
  143. if (upper & lower) p_dosname->name_case = 0xFF;
  144. else p_dosname->name_case = lower;
  145. if (p_lossy != NULL) *p_lossy = lossy;
  146. }
  147. void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname)
  148. {
  149. INT32 i = 0, j, n = 0;
  150. UINT8 buf[DOS_NAME_LENGTH+2];
  151. UINT8 *dosname = p_dosname->name;
  152. UINT16 *uniname = p_uniname->name;
  153. struct nls_table *nls = EXFAT_SB(sb)->nls_disk;
  154. if (*dosname == 0x05) {
  155. *buf = 0xE5;
  156. i++;
  157. n++;
  158. }
  159. for ( ; i < 8; i++, n++) {
  160. if (*(dosname+i) == ' ') break;
  161. if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x08))
  162. *(buf+n) = *(dosname+i) + ('a' - 'A');
  163. else
  164. *(buf+n) = *(dosname+i);
  165. }
  166. if (*(dosname+8) != ' ') {
  167. *(buf+n) = '.';
  168. n++;
  169. }
  170. for (i = 8; i < DOS_NAME_LENGTH; i++, n++) {
  171. if (*(dosname+i) == ' ') break;
  172. if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x10))
  173. *(buf+n) = *(dosname+i) + ('a' - 'A');
  174. else
  175. *(buf+n) = *(dosname+i);
  176. }
  177. *(buf+n) = '\0';
  178. i = j = 0;
  179. while (j < (MAX_NAME_LENGTH-1)) {
  180. if (*(buf+i) == '\0') break;
  181. i += convert_ch_to_uni(nls, uniname, (buf+i), NULL);
  182. uniname++;
  183. j++;
  184. }
  185. *uniname = (UINT16) '\0';
  186. }
  187. void nls_uniname_to_cstring(struct super_block *sb, UINT8 *p_cstring, UNI_NAME_T *p_uniname)
  188. {
  189. INT32 i, j, len;
  190. UINT8 buf[MAX_CHARSET_SIZE];
  191. UINT16 *uniname = p_uniname->name;
  192. struct nls_table *nls = EXFAT_SB(sb)->nls_io;
  193. i = 0;
  194. while (i < (MAX_NAME_LENGTH-1)) {
  195. if (*uniname == (UINT16) '\0') break;
  196. len = convert_uni_to_ch(nls, buf, *uniname, NULL);
  197. if (len > 1) {
  198. for (j = 0; j < len; j++)
  199. *p_cstring++ = (INT8) *(buf+j);
  200. } else {
  201. *p_cstring++ = (INT8) *buf;
  202. }
  203. uniname++;
  204. i++;
  205. }
  206. *p_cstring = '\0';
  207. }
  208. void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, UINT8 *p_cstring, INT32 *p_lossy)
  209. {
  210. INT32 i, j, lossy = FALSE;
  211. UINT8 *end_of_name;
  212. UINT16 upname[MAX_NAME_LENGTH];
  213. UINT16 *uniname = p_uniname->name;
  214. struct nls_table *nls = EXFAT_SB(sb)->nls_io;
  215. end_of_name = p_cstring + STRLEN((INT8 *) p_cstring);
  216. while (*(--end_of_name) == ' ') {
  217. if (end_of_name < p_cstring) break;
  218. }
  219. *(++end_of_name) = '\0';
  220. if (STRCMP((INT8 *) p_cstring, ".") && STRCMP((INT8 *) p_cstring, "..")) {
  221. while (*(--end_of_name) == '.') {
  222. if (end_of_name < p_cstring) break;
  223. }
  224. *(++end_of_name) = '\0';
  225. }
  226. if (*p_cstring == '\0')
  227. lossy = TRUE;
  228. i = j = 0;
  229. while (j < (MAX_NAME_LENGTH-1)) {
  230. if (*(p_cstring+i) == '\0') break;
  231. i += convert_ch_to_uni(nls, uniname, (UINT8 *)(p_cstring+i), &lossy);
  232. if ((*uniname < 0x0020) || WSTRCHR(bad_uni_chars, *uniname))
  233. lossy = TRUE;
  234. *(upname+j) = nls_upper(sb, *uniname);
  235. uniname++;
  236. j++;
  237. }
  238. if (*(p_cstring+i) != '\0')
  239. lossy = TRUE;
  240. *uniname = (UINT16) '\0';
  241. p_uniname->name_len = j;
  242. p_uniname->name_hash = calc_checksum_2byte((void *) upname, j<<1, 0, CS_DEFAULT);
  243. if (p_lossy != NULL)
  244. *p_lossy = lossy;
  245. }
  246. static INT32 convert_ch_to_uni(struct nls_table *nls, UINT16 *uni, UINT8 *ch, INT32 *lossy)
  247. {
  248. int len;
  249. *uni = 0x0;
  250. if (ch[0] < 0x80) {
  251. *uni = (UINT16) ch[0];
  252. return(1);
  253. }
  254. if ((len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni)) < 0) {
  255. printk("%s: fail to use nls \n", __func__);
  256. if (lossy != NULL)
  257. *lossy = TRUE;
  258. *uni = (UINT16) '_';
  259. if (!strcmp(nls->charset, "utf8")) return(1);
  260. else return(2);
  261. }
  262. return(len);
  263. }
  264. static INT32 convert_uni_to_ch(struct nls_table *nls, UINT8 *ch, UINT16 uni, INT32 *lossy)
  265. {
  266. int len;
  267. ch[0] = 0x0;
  268. if (uni < 0x0080) {
  269. ch[0] = (UINT8) uni;
  270. return(1);
  271. }
  272. if ((len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE)) < 0) {
  273. printk("%s: fail to use nls \n", __func__);
  274. if (lossy != NULL) *lossy = TRUE;
  275. ch[0] = '_';
  276. return(1);
  277. }
  278. return(len);
  279. }