Source code of Windows XP (NT5)
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.

369 lines
11 KiB

  1. #define NOCOMM
  2. #define NOWH
  3. #include "windows.h"
  4. #include "parse.h"
  5. #define chSpace ' '
  6. #define chPeriod '.'
  7. long ParseFile(ULPSTR lpstrFileName);
  8. LPSTR mystrchr(LPSTR, int);
  9. #define chMatchOne '?'
  10. #define chMatchAny '*'
  11. LPSTR mystrchr(LPSTR str, int ch)
  12. {
  13. while(*str)
  14. {
  15. if (ch == *str)
  16. return(str);
  17. str = AnsiNext(str);
  18. }
  19. return(NULL);
  20. }
  21. /*---------------------------------------------------------------------------
  22. * GetFileTitle
  23. * Purpose: API to outside world to obtain the title of a file given the
  24. * file name. Useful if file name received via some method
  25. * other that GetOpenFileName (e.g. command line, drag drop).
  26. * Assumes: lpszFile points to NULL terminated DOS filename (may have path)
  27. * lpszTitle points to buffer to receive NULL terminated file title
  28. * wBufSize is the size of buffer pointed to by lpszTitle
  29. * Returns: 0 on success
  30. * < 0, Parsing failure (invalid file name)
  31. * > 0, buffer too small, size needed (including NULL terminator)
  32. *--------------------------------------------------------------------------*/
  33. short FAR PASCAL
  34. GetFileTitle(LPCSTR lpszFile, LPSTR lpszTitle, WORD wBufSize)
  35. {
  36. short nNeeded;
  37. LPSTR lpszPtr;
  38. nNeeded = (WORD) ParseFile((ULPSTR)lpszFile);
  39. if (nNeeded >= 0) /* Is the filename valid? */
  40. {
  41. lpszPtr = (LPSTR)lpszFile + nNeeded;
  42. if ((nNeeded = (short)(lstrlen(lpszPtr) + 1)) <= (short) wBufSize)
  43. {
  44. /* ParseFile() fails if wildcards in directory, but OK if in name */
  45. /* Since they aren't OK here, the check needed here */
  46. if (mystrchr(lpszPtr, chMatchAny) || mystrchr(lpszPtr, chMatchOne))
  47. {
  48. nNeeded = PARSE_WILDCARDINFILE; /* Failure */
  49. }
  50. else
  51. {
  52. lstrcpy(lpszTitle, lpszPtr);
  53. nNeeded = 0; /* Success */
  54. }
  55. }
  56. }
  57. return(nNeeded);
  58. }
  59. /*---------------------------------------------------------------------------
  60. * ParseFile
  61. * Purpose: Determine if the filename is a legal DOS name
  62. * Input: Long pointer to a SINGLE file name
  63. * Circumstance checked:
  64. * 1) Valid as directory name, but not as file name
  65. * 2) Empty String
  66. * 3) Illegal Drive label
  67. * 4) Period in invalid location (in extention, 1st in file name)
  68. * 5) Missing directory character
  69. * 6) Illegal character
  70. * 7) Wildcard in directory name
  71. * 8) Double slash beyond 1st 2 characters
  72. * 9) Space character in the middle of the name (trailing spaces OK)
  73. * 10) Filename greater than 8 characters
  74. * 11) Extention greater than 3 characters
  75. * Notes:
  76. * Filename length is NOT checked.
  77. * Valid filenames will have leading spaces, trailing spaces and
  78. * terminating period stripped in place.
  79. *
  80. * Returns: If valid, LOWORD is byte offset to filename
  81. * HIWORD is byte offset to extention
  82. * if string ends with period, 0
  83. * if no extention is given, string length
  84. * If invalid, LOWORD is error code suggesting problem (< 0)
  85. * HIWORD is approximate offset where problem found
  86. * Note that this may be beyond the offending character
  87. * History:
  88. * Thu 24-Jan-1991 12:20:00 -by- Clark R. Cyr [clarkc]
  89. * Initial writing
  90. * Thu 21-Feb-1991 10:19:00 -by- Clark R. Cyr [clarkc]
  91. * Changed to unsigned character pointer
  92. *--------------------------------------------------------------------------*/
  93. long ParseFile(ULPSTR lpstrFileName)
  94. {
  95. short nFile, nExt, nFileOffset, nExtOffset;
  96. BOOL bExt;
  97. BOOL bWildcard;
  98. short nNetwork = 0;
  99. BOOL bUNCPath = FALSE;
  100. ULPSTR lpstr = lpstrFileName;
  101. /* Strip off initial white space. Note that TAB is not checked */
  102. /* because it cannot be received out of a standard edit control */
  103. /* 30 January 1991 clarkc */
  104. while (*lpstr == chSpace)
  105. lpstr++;
  106. if (!*lpstr)
  107. {
  108. nFileOffset = PARSE_EMPTYSTRING;
  109. goto FAILURE;
  110. }
  111. if (lpstr != lpstrFileName)
  112. {
  113. lstrcpy((LPSTR)lpstrFileName, (LPSTR)lpstr);
  114. lpstr = lpstrFileName;
  115. }
  116. if (*AnsiNext((LPSTR)lpstr) == ':')
  117. {
  118. unsigned char cDrive = (unsigned char)((*lpstr | (unsigned char) 0x20)); /* make lowercase */
  119. /* This does not test if the drive exists, only if it's legal */
  120. if ((cDrive < 'a') || (cDrive > 'z'))
  121. {
  122. nFileOffset = PARSE_INVALIDDRIVE;
  123. goto FAILURE;
  124. }
  125. lpstr = (ULPSTR)AnsiNext(AnsiNext((LPSTR)lpstr));
  126. }
  127. if ((*lpstr == '\\') || (*lpstr == '/'))
  128. {
  129. if (*++lpstr == chPeriod) /* cannot have c:\. */
  130. {
  131. if ((*++lpstr != '\\') && (*lpstr != '/'))
  132. {
  133. if (!*lpstr) /* it's the root directory */
  134. goto MustBeDir;
  135. nFileOffset = PARSE_INVALIDPERIOD;
  136. goto FAILURE;
  137. }
  138. else
  139. ++lpstr; /* it's saying top directory (again), thus allowed */
  140. }
  141. else if ((*lpstr == '\\') && (*(lpstr-1) == '\\'))
  142. {
  143. /* It seems that for a full network path, whether a drive is declared or
  144. * not is insignificant, though if a drive is given, it must be valid
  145. * (hence the code above should remain there).
  146. * 13 February 1991 clarkc
  147. */
  148. ++lpstr; /* ...since it's the first slash, 2 are allowed */
  149. nNetwork = -1; /* Must receive server and share to be real */
  150. bUNCPath = TRUE; /* No wildcards allowed if UNC name */
  151. }
  152. else if (*lpstr == '/')
  153. {
  154. nFileOffset = PARSE_INVALIDDIRCHAR;
  155. goto FAILURE;
  156. }
  157. }
  158. else if (*lpstr == chPeriod)
  159. {
  160. if (*++lpstr == chPeriod) /* Is this up one directory? */
  161. ++lpstr;
  162. if (!*lpstr)
  163. goto MustBeDir;
  164. if ((*lpstr != '\\') && (*lpstr != '/'))
  165. {
  166. nFileOffset = PARSE_INVALIDPERIOD;
  167. goto FAILURE;
  168. }
  169. else
  170. ++lpstr; /* it's saying directory, thus allowed */
  171. }
  172. if (!*lpstr)
  173. {
  174. goto MustBeDir;
  175. }
  176. /* Should point to first char in 8.3 filename by now */
  177. nFileOffset = nExtOffset = nFile = nExt = 0;
  178. bWildcard = bExt = FALSE;
  179. while (*lpstr)
  180. {
  181. /*
  182. * The next comparison MUST be unsigned to allow for extended characters!
  183. * 21 Feb 1991 clarkc
  184. */
  185. if (*lpstr < chSpace)
  186. {
  187. nFileOffset = PARSE_INVALIDCHAR;
  188. goto FAILURE;
  189. }
  190. switch (*lpstr)
  191. {
  192. case '"': /* All invalid */
  193. case '+':
  194. case ',':
  195. case ':':
  196. case ';':
  197. case '<':
  198. case '=':
  199. case '>':
  200. case '[':
  201. case ']':
  202. case '|':
  203. {
  204. nFileOffset = PARSE_INVALIDCHAR;
  205. goto FAILURE;
  206. }
  207. case '\\': /* Subdirectory indicators */
  208. case '/':
  209. nNetwork++;
  210. if (bWildcard)
  211. {
  212. nFileOffset = PARSE_WILDCARDINDIR;
  213. goto FAILURE;
  214. }
  215. else if (nFile == 0) /* can't have 2 in a row */
  216. {
  217. nFileOffset = PARSE_INVALIDDIRCHAR;
  218. goto FAILURE;
  219. }
  220. else
  221. { /* reset flags */
  222. ++lpstr;
  223. if (!nNetwork && !*lpstr)
  224. {
  225. nFileOffset = PARSE_INVALIDNETPATH;
  226. goto FAILURE;
  227. }
  228. nFile = nExt = 0;
  229. bExt = FALSE;
  230. }
  231. break;
  232. case chSpace:
  233. {
  234. ULPSTR lpSpace = lpstr;
  235. *lpSpace = '\0';
  236. while (*++lpSpace)
  237. {
  238. if (*lpSpace != chSpace)
  239. {
  240. *lpstr = chSpace; /* Reset string, abandon ship */
  241. nFileOffset = PARSE_INVALIDSPACE;
  242. goto FAILURE;
  243. }
  244. }
  245. }
  246. break;
  247. case chPeriod:
  248. if (nFile == 0)
  249. {
  250. if (*++lpstr == chPeriod)
  251. ++lpstr;
  252. if (!*lpstr)
  253. goto MustBeDir;
  254. if ((*lpstr != '\\') && (*lpstr != '/'))
  255. {
  256. nFileOffset = PARSE_INVALIDPERIOD;
  257. goto FAILURE;
  258. }
  259. ++lpstr; /* Flags are already set */
  260. }
  261. else if (bExt)
  262. {
  263. nFileOffset = PARSE_INVALIDPERIOD; /* can't have one in ext */
  264. goto FAILURE;
  265. }
  266. else
  267. {
  268. nExtOffset = 0;
  269. ++lpstr;
  270. bExt = TRUE;
  271. }
  272. break;
  273. case '*':
  274. case '?':
  275. if (bUNCPath)
  276. {
  277. nFileOffset = PARSE_INVALIDNETPATH;
  278. goto FAILURE;
  279. }
  280. bWildcard = TRUE;
  281. /* Fall through to normal character processing */
  282. default:
  283. if (bExt)
  284. {
  285. if (++nExt == 1)
  286. nExtOffset = (short)(lpstr - lpstrFileName);
  287. else if (nExt > 3)
  288. {
  289. nFileOffset = PARSE_EXTENTIONTOOLONG;
  290. goto FAILURE;
  291. }
  292. if ((nNetwork == -1) && (nFile + nExt > 11))
  293. {
  294. nFileOffset = PARSE_INVALIDNETPATH;
  295. goto FAILURE;
  296. }
  297. }
  298. else if (++nFile == 1)
  299. nFileOffset = (short)(lpstr - lpstrFileName);
  300. else if (nFile > 8)
  301. {
  302. /* If it's a server name, it can have 11 characters */
  303. if (nNetwork != -1)
  304. {
  305. nFileOffset = PARSE_FILETOOLONG;
  306. goto FAILURE;
  307. }
  308. else if (nFile > 11)
  309. {
  310. nFileOffset = PARSE_INVALIDNETPATH;
  311. goto FAILURE;
  312. }
  313. }
  314. lpstr = (ULPSTR)AnsiNext((LPSTR)lpstr);
  315. break;
  316. }
  317. }
  318. /* Did we start with a double backslash but not have any more slashes? */
  319. if (nNetwork == -1)
  320. {
  321. nFileOffset = PARSE_INVALIDNETPATH;
  322. goto FAILURE;
  323. }
  324. if (!nFile)
  325. {
  326. MustBeDir:
  327. nFileOffset = PARSE_DIRECTORYNAME;
  328. goto FAILURE;
  329. }
  330. if ((*(lpstr - 1) == chPeriod) && /* if true, no extention wanted */
  331. (*AnsiNext((LPSTR)(lpstr-2)) == chPeriod))
  332. *(lpstr - 1) = '\0'; /* Remove terminating period */
  333. else if (!nExt)
  334. FAILURE:
  335. nExtOffset = (short)(lpstr - lpstrFileName);
  336. return(MAKELONG(nFileOffset, nExtOffset));
  337. }