pathfn.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458
  1. #include "rar.hpp"
  2. char* PointToName(const char *Path)
  3. {
  4. const char *Found=NULL;
  5. for (const char *s=Path;*s!=0;s=charnext(s))
  6. if (IsPathDiv(*s))
  7. Found=(char*)(s+1);
  8. if (Found!=NULL)
  9. return((char*)Found);
  10. return (char*)((*Path && IsDriveDiv(Path[1]) && charnext(Path)==Path+1) ? Path+2:Path);
  11. }
  12. wchar* PointToName(const wchar *Path)
  13. {
  14. for (int I=(int)wcslen(Path)-1;I>=0;I--)
  15. if (IsPathDiv(Path[I]))
  16. return (wchar*)&Path[I+1];
  17. return (wchar*)((*Path && IsDriveDiv(Path[1])) ? Path+2:Path);
  18. }
  19. char* PointToLastChar(const char *Path)
  20. {
  21. for (const char *s=Path,*p=Path;;p=s,s=charnext(s))
  22. if (*s==0)
  23. return((char *)p);
  24. }
  25. wchar* PointToLastChar(const wchar *Path)
  26. {
  27. size_t Length=wcslen(Path);
  28. return((wchar*)(Length>0 ? Path+Length-1:Path));
  29. }
  30. char* ConvertPath(const char *SrcPath,char *DestPath)
  31. {
  32. const char *DestPtr=SrcPath;
  33. // Prevent \..\ in any part of path string.
  34. for (const char *s=DestPtr;*s!=0;s++)
  35. if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3]))
  36. DestPtr=s+4;
  37. // Remove any sequence of . and \ in the beginning of path string.
  38. while (*DestPtr!=0)
  39. {
  40. const char *s=DestPtr;
  41. if (s[0] && IsDriveDiv(s[1]))
  42. s+=2;
  43. else
  44. if (s[0]=='\\' && s[1]=='\\')
  45. {
  46. const char *Slash=strchr(s+2,'\\');
  47. if (Slash!=NULL && (Slash=strchr(Slash+1,'\\'))!=NULL)
  48. s=Slash+1;
  49. }
  50. for (const char *t=s;*t!=0;t++)
  51. if (IsPathDiv(*t))
  52. s=t+1;
  53. else
  54. if (*t!='.')
  55. break;
  56. if (s==DestPtr)
  57. break;
  58. DestPtr=s;
  59. }
  60. // Code above does not remove last "..", doing here.
  61. if (DestPtr[0]=='.' && DestPtr[1]=='.' && DestPtr[2]==0)
  62. DestPtr+=2;
  63. if (DestPath!=NULL)
  64. {
  65. // SrcPath and DestPath can point to same memory area,
  66. // so we use the temporary buffer for copying.
  67. char TmpStr[NM];
  68. strncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
  69. strcpy(DestPath,TmpStr);
  70. }
  71. return((char *)DestPtr);
  72. }
  73. wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
  74. {
  75. const wchar *DestPtr=SrcPath;
  76. // Prevent \..\ in any part of path string.
  77. for (const wchar *s=DestPtr;*s!=0;s++)
  78. if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3]))
  79. DestPtr=s+4;
  80. // Remove any sequence of . and \ in the beginning of path string.
  81. while (*DestPtr!=0)
  82. {
  83. const wchar *s=DestPtr;
  84. if (s[0] && IsDriveDiv(s[1]))
  85. s+=2;
  86. if (s[0]=='\\' && s[1]=='\\')
  87. {
  88. const wchar *Slash=wcschr(s+2,'\\');
  89. if (Slash!=NULL && (Slash=wcschr(Slash+1,'\\'))!=NULL)
  90. s=Slash+1;
  91. }
  92. for (const wchar *t=s;*t!=0;t++)
  93. if (IsPathDiv(*t))
  94. s=t+1;
  95. else
  96. if (*t!='.')
  97. break;
  98. if (s==DestPtr)
  99. break;
  100. DestPtr=s;
  101. }
  102. // Code above does not remove last "..", doing here.
  103. if (DestPtr[0]=='.' && DestPtr[1]=='.' && DestPtr[2]==0)
  104. DestPtr+=2;
  105. if (DestPath!=NULL)
  106. {
  107. // SrcPath and DestPath can point to same memory area,
  108. // so we use the temporary buffer for copying.
  109. wchar TmpStr[NM];
  110. wcsncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
  111. wcscpy(DestPath,TmpStr);
  112. }
  113. return((wchar *)DestPtr);
  114. }
  115. void SetExt(char *Name,const char *NewExt)
  116. {
  117. char *Dot=GetExt(Name);
  118. if (NewExt==NULL)
  119. {
  120. if (Dot!=NULL)
  121. *Dot=0;
  122. }
  123. else
  124. if (Dot==NULL)
  125. {
  126. strcat(Name,".");
  127. strcat(Name,NewExt);
  128. }
  129. else
  130. strcpy(Dot+1,NewExt);
  131. }
  132. void SetExt(wchar *Name,const wchar *NewExt)
  133. {
  134. if (Name==NULL || *Name==0)
  135. return;
  136. wchar *Dot=GetExt(Name);
  137. if (NewExt==NULL)
  138. {
  139. if (Dot!=NULL)
  140. *Dot=0;
  141. }
  142. else
  143. if (Dot==NULL)
  144. {
  145. wcscat(Name,L".");
  146. wcscat(Name,NewExt);
  147. }
  148. else
  149. wcscpy(Dot+1,NewExt);
  150. }
  151. #ifndef SFX_MODULE
  152. void SetSFXExt(char *SFXName)
  153. {
  154. #ifdef _UNIX
  155. SetExt(SFXName,"sfx");
  156. #endif
  157. #if defined(_WIN_ALL) || defined(_EMX)
  158. SetExt(SFXName,"exe");
  159. #endif
  160. }
  161. #endif
  162. #ifndef SFX_MODULE
  163. void SetSFXExt(wchar *SFXName)
  164. {
  165. if (SFXName==NULL || *SFXName==0)
  166. return;
  167. #ifdef _UNIX
  168. SetExt(SFXName,L"sfx");
  169. #endif
  170. #if defined(_WIN_ALL) || defined(_EMX)
  171. SetExt(SFXName,L"exe");
  172. #endif
  173. }
  174. #endif
  175. char *GetExt(const char *Name)
  176. {
  177. return(Name==NULL ? NULL:strrchrd(PointToName(Name),'.'));
  178. }
  179. wchar *GetExt(const wchar *Name)
  180. {
  181. return(Name==NULL ? NULL:wcsrchr(PointToName(Name),'.'));
  182. }
  183. // 'Ext' is an extension without the leading dot, like "rar".
  184. bool CmpExt(const char *Name,const char *Ext)
  185. {
  186. char *NameExt=GetExt(Name);
  187. return(NameExt!=NULL && stricomp(NameExt+1,Ext)==0);
  188. }
  189. // 'Ext' is an extension without the leading dot, like L"rar".
  190. bool CmpExt(const wchar *Name,const wchar *Ext)
  191. {
  192. wchar *NameExt=GetExt(Name);
  193. return(NameExt!=NULL && wcsicomp(NameExt+1,Ext)==0);
  194. }
  195. bool IsWildcard(const char *Str,const wchar *StrW)
  196. {
  197. if (StrW!=NULL && *StrW!=0)
  198. return(wcspbrk(StrW,L"*?")!=NULL);
  199. return(Str==NULL ? false:strpbrk(Str,"*?")!=NULL);
  200. }
  201. bool IsPathDiv(int Ch)
  202. {
  203. #if defined(_WIN_ALL) || defined(_EMX)
  204. return(Ch=='\\' || Ch=='/');
  205. #else
  206. return(Ch==CPATHDIVIDER);
  207. #endif
  208. }
  209. bool IsDriveDiv(int Ch)
  210. {
  211. #ifdef _UNIX
  212. return(false);
  213. #else
  214. return(Ch==':');
  215. #endif
  216. }
  217. int GetPathDisk(const char *Path)
  218. {
  219. if (IsDiskLetter(Path))
  220. return(etoupper(*Path)-'A');
  221. else
  222. return(-1);
  223. }
  224. int GetPathDisk(const wchar *Path)
  225. {
  226. if (IsDiskLetter(Path))
  227. return(etoupperw(*Path)-'A');
  228. else
  229. return(-1);
  230. }
  231. void AddEndSlash(char *Path)
  232. {
  233. char *LastChar=PointToLastChar(Path);
  234. if (*LastChar!=0 && *LastChar!=CPATHDIVIDER)
  235. strcat(LastChar,PATHDIVIDER);
  236. }
  237. void AddEndSlash(wchar *Path)
  238. {
  239. size_t Length=wcslen(Path);
  240. if (Length>0 && Path[Length-1]!=CPATHDIVIDER)
  241. wcscat(Path,PATHDIVIDERW);
  242. }
  243. // Returns file path including the trailing path separator symbol.
  244. void GetFilePath(const char *FullName,char *Path,int MaxLength)
  245. {
  246. size_t PathLength=Min(MaxLength-1,PointToName(FullName)-FullName);
  247. strncpy(Path,FullName,PathLength);
  248. Path[PathLength]=0;
  249. }
  250. // Returns file path including the trailing path separator symbol.
  251. void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength)
  252. {
  253. size_t PathLength=Min(MaxLength-1,PointToName(FullName)-FullName);
  254. wcsncpy(Path,FullName,PathLength);
  255. Path[PathLength]=0;
  256. }
  257. // Removes name and returns file path without the trailing
  258. // path separator symbol.
  259. void RemoveNameFromPath(char *Path)
  260. {
  261. char *Name=PointToName(Path);
  262. if (Name>=Path+2 && (!IsDriveDiv(Path[1]) || Name>=Path+4))
  263. Name--;
  264. *Name=0;
  265. }
  266. // Removes name and returns file path without the trailing
  267. // path separator symbol.
  268. void RemoveNameFromPath(wchar *Path)
  269. {
  270. wchar *Name=PointToName(Path);
  271. if (Name>=Path+2 && (!IsDriveDiv(Path[1]) || Name>=Path+4))
  272. Name--;
  273. *Name=0;
  274. }
  275. #if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
  276. void GetAppDataPath(char *Path)
  277. {
  278. LPMALLOC g_pMalloc;
  279. SHGetMalloc(&g_pMalloc);
  280. LPITEMIDLIST ppidl;
  281. *Path=0;
  282. bool Success=false;
  283. if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR &&
  284. SHGetPathFromIDListA(ppidl,Path) && *Path!=0)
  285. {
  286. AddEndSlash(Path);
  287. strcat(Path,"WinRAR");
  288. Success=FileExist(Path) || MakeDir(Path,NULL,false,0)==MKDIR_SUCCESS;
  289. }
  290. if (!Success)
  291. {
  292. GetModuleFileNameA(NULL,Path,NM);
  293. RemoveNameFromPath(Path);
  294. }
  295. g_pMalloc->Free(ppidl);
  296. }
  297. #endif
  298. #if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
  299. void GetAppDataPath(wchar *Path)
  300. {
  301. LPMALLOC g_pMalloc;
  302. SHGetMalloc(&g_pMalloc);
  303. LPITEMIDLIST ppidl;
  304. *Path=0;
  305. bool Success=false;
  306. if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR &&
  307. SHGetPathFromIDListW(ppidl,Path) && *Path!=0)
  308. {
  309. AddEndSlash(Path);
  310. wcscat(Path,L"WinRAR");
  311. Success=FileExist(NULL,Path) || MakeDir(NULL,Path,false,0)==MKDIR_SUCCESS;
  312. }
  313. if (!Success)
  314. {
  315. GetModuleFileNameW(NULL,Path,NM);
  316. RemoveNameFromPath(Path);
  317. }
  318. g_pMalloc->Free(ppidl);
  319. }
  320. #endif
  321. #if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
  322. void GetRarDataPath(char *Path)
  323. {
  324. *Path=0;
  325. HKEY hKey;
  326. if (RegOpenKeyExA(HKEY_CURRENT_USER,"Software\\WinRAR\\Paths",0,
  327. KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS)
  328. {
  329. DWORD DataSize=NM,Type;
  330. RegQueryValueExA(hKey,"AppData",0,&Type,(BYTE *)Path,&DataSize);
  331. RegCloseKey(hKey);
  332. }
  333. if (*Path==0 || !FileExist(Path))
  334. GetAppDataPath(Path);
  335. }
  336. #endif
  337. #if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
  338. void GetRarDataPath(wchar *Path)
  339. {
  340. *Path=0;
  341. HKEY hKey;
  342. if (RegOpenKeyExW(HKEY_CURRENT_USER,L"Software\\WinRAR\\Paths",0,
  343. KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS)
  344. {
  345. DWORD DataSize=NM,Type;
  346. RegQueryValueExW(hKey,L"AppData",0,&Type,(BYTE *)Path,&DataSize);
  347. RegCloseKey(hKey);
  348. }
  349. if (*Path==0 || !FileExist(NULL,Path))
  350. GetAppDataPath(Path);
  351. }
  352. #endif
  353. #ifndef SFX_MODULE
  354. bool EnumConfigPaths(char *Path,int Number)
  355. {
  356. #ifdef _EMX
  357. static char RARFileName[NM];
  358. if (Number==-1)
  359. strcpy(RARFileName,Path);
  360. if (Number!=0)
  361. return(false);
  362. #ifndef _DJGPP
  363. if (_osmode==OS2_MODE)
  364. {
  365. PTIB ptib;
  366. PPIB ppib;
  367. DosGetInfoBlocks(&ptib, &ppib);
  368. DosQueryModuleName(ppib->pib_hmte,NM,Path);
  369. }
  370. else
  371. #endif
  372. strcpy(Path,RARFileName);
  373. RemoveNameFromPath(Path);
  374. return(true);
  375. #elif defined(_UNIX)
  376. static const char *AltPath[]={
  377. "/etc","/etc/rar","/usr/lib","/usr/local/lib","/usr/local/etc"
  378. };
  379. if (Number==0)
  380. {
  381. char *EnvStr=getenv("HOME");
  382. strncpy(Path, (EnvStr==NULL) ? AltPath[0] : EnvStr, NM-1);
  383. Path[NM-1]=0;
  384. return(true);
  385. }
  386. Number--;
  387. if (Number<0 || Number>=sizeof(AltPath)/sizeof(AltPath[0]))
  388. return(false);
  389. strcpy(Path,AltPath[Number]);
  390. return(true);
  391. #elif defined(_WIN_ALL)
  392. if (Number<0 || Number>1)
  393. return(false);
  394. if (Number==0)
  395. GetRarDataPath(Path);
  396. else
  397. {
  398. GetModuleFileNameA(NULL,Path,NM);
  399. RemoveNameFromPath(Path);
  400. }
  401. return(true);
  402. #else
  403. return(false);
  404. #endif
  405. }
  406. #endif
  407. #if defined(_WIN_ALL) && !defined(SFX_MODULE)
  408. bool EnumConfigPaths(wchar *Path,int Number)
  409. {
  410. if (Number<0 || Number>1)
  411. return(false);
  412. if (Number==0)
  413. GetRarDataPath(Path);
  414. else
  415. {
  416. GetModuleFileNameW(NULL,Path,NM);
  417. RemoveNameFromPath(Path);
  418. }
  419. return(true);
  420. }
  421. #endif
  422. #ifndef SFX_MODULE
  423. void GetConfigName(const char *Name,char *FullName,bool CheckExist)
  424. {
  425. *FullName=0;
  426. for (int I=0;EnumConfigPaths(FullName,I);I++)
  427. {
  428. AddEndSlash(FullName);
  429. strcat(FullName,Name);
  430. if (!CheckExist || WildFileExist(FullName))
  431. break;
  432. }
  433. }
  434. #endif
  435. #if defined(_WIN_ALL) && !defined(SFX_MODULE)
  436. void GetConfigName(const wchar *Name,wchar *FullName,bool CheckExist)
  437. {
  438. *FullName=0;
  439. for (int I=0;EnumConfigPaths(FullName,I);I++)
  440. {
  441. AddEndSlash(FullName);
  442. wcscat(FullName,Name);
  443. if (!CheckExist || WildFileExist(NULL,FullName))
  444. break;
  445. }
  446. }
  447. #endif
  448. // Returns a pointer to rightmost digit of volume number.
  449. char* GetVolNumPart(char *ArcName)
  450. {
  451. // Pointing to last name character.
  452. char *ChPtr=ArcName+strlen(ArcName)-1;
  453. // Skipping the archive extension.
  454. while (!IsDigit(*ChPtr) && ChPtr>ArcName)
  455. ChPtr--;
  456. // Skipping the numeric part of name.
  457. char *NumPtr=ChPtr;
  458. while (IsDigit(*NumPtr) && NumPtr>ArcName)
  459. NumPtr--;
  460. // Searching for first numeric part in names like name.part##of##.rar.
  461. // Stop search on the first dot.
  462. while (NumPtr>ArcName && *NumPtr!='.')
  463. {
  464. if (IsDigit(*NumPtr))
  465. {
  466. // Validate the first numeric part only if it has a dot somewhere
  467. // before it.
  468. char *Dot=strchrd(PointToName(ArcName),'.');
  469. if (Dot!=NULL && Dot<NumPtr)
  470. ChPtr=NumPtr;
  471. break;
  472. }
  473. NumPtr--;
  474. }
  475. return(ChPtr);
  476. }
  477. // Returns a pointer to rightmost digit of volume number.
  478. wchar* GetVolNumPart(wchar *ArcName)
  479. {
  480. // Pointing to last name character.
  481. wchar *ChPtr=ArcName+wcslen(ArcName)-1;
  482. // Skipping the archive extension.
  483. while (!IsDigit(*ChPtr) && ChPtr>ArcName)
  484. ChPtr--;
  485. // Skipping the numeric part of name.
  486. wchar *NumPtr=ChPtr;
  487. while (IsDigit(*NumPtr) && NumPtr>ArcName)
  488. NumPtr--;
  489. // Searching for first numeric part in names like name.part##of##.rar.
  490. // Stop search on the first dot.
  491. while (NumPtr>ArcName && *NumPtr!='.')
  492. {
  493. if (IsDigit(*NumPtr))
  494. {
  495. // Validate the first numeric part only if it has a dot somewhere
  496. // before it.
  497. wchar *Dot=wcschr(PointToName(ArcName),'.');
  498. if (Dot!=NULL && Dot<NumPtr)
  499. ChPtr=NumPtr;
  500. break;
  501. }
  502. NumPtr--;
  503. }
  504. return(ChPtr);
  505. }
  506. void NextVolumeName(char *ArcName,wchar *ArcNameW,uint MaxLength,bool OldNumbering)
  507. {
  508. if (ArcName!=NULL && *ArcName!=0)
  509. {
  510. char *ChPtr;
  511. if ((ChPtr=GetExt(ArcName))==NULL)
  512. {
  513. strncatz(ArcName,".rar",MaxLength);
  514. ChPtr=GetExt(ArcName);
  515. }
  516. else
  517. if (ChPtr[1]==0 && strlen(ArcName)<MaxLength-3 || stricomp(ChPtr+1,"exe")==0 || stricomp(ChPtr+1,"sfx")==0)
  518. strcpy(ChPtr+1,"rar");
  519. if (!OldNumbering)
  520. {
  521. ChPtr=GetVolNumPart(ArcName);
  522. while ((++(*ChPtr))=='9'+1)
  523. {
  524. *ChPtr='0';
  525. ChPtr--;
  526. if (ChPtr<ArcName || !IsDigit(*ChPtr))
  527. {
  528. for (char *EndPtr=ArcName+strlen(ArcName);EndPtr!=ChPtr;EndPtr--)
  529. *(EndPtr+1)=*EndPtr;
  530. *(ChPtr+1)='1';
  531. break;
  532. }
  533. }
  534. }
  535. else
  536. if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
  537. strcpy(ChPtr+2,"00");
  538. else
  539. {
  540. ChPtr+=3;
  541. while ((++(*ChPtr))=='9'+1)
  542. if (*(ChPtr-1)=='.')
  543. {
  544. *ChPtr='A';
  545. break;
  546. }
  547. else
  548. {
  549. *ChPtr='0';
  550. ChPtr--;
  551. }
  552. }
  553. }
  554. if (ArcNameW!=NULL && *ArcNameW!=0)
  555. {
  556. wchar *ChPtr;
  557. if ((ChPtr=GetExt(ArcNameW))==NULL)
  558. {
  559. wcsncatz(ArcNameW,L".rar",MaxLength);
  560. ChPtr=GetExt(ArcNameW);
  561. }
  562. else
  563. if (ChPtr[1]==0 && wcslen(ArcNameW)<MaxLength-3 || wcsicomp(ChPtr+1,L"exe")==0 || wcsicomp(ChPtr+1,L"sfx")==0)
  564. wcscpy(ChPtr+1,L"rar");
  565. if (!OldNumbering)
  566. {
  567. ChPtr=GetVolNumPart(ArcNameW);
  568. while ((++(*ChPtr))=='9'+1)
  569. {
  570. *ChPtr='0';
  571. ChPtr--;
  572. if (ChPtr<ArcNameW || !IsDigit(*ChPtr))
  573. {
  574. for (wchar *EndPtr=ArcNameW+wcslen(ArcNameW);EndPtr!=ChPtr;EndPtr--)
  575. *(EndPtr+1)=*EndPtr;
  576. *(ChPtr+1)='1';
  577. break;
  578. }
  579. }
  580. }
  581. else
  582. if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
  583. wcscpy(ChPtr+2,L"00");
  584. else
  585. {
  586. ChPtr+=3;
  587. while ((++(*ChPtr))=='9'+1)
  588. if (*(ChPtr-1)=='.')
  589. {
  590. *ChPtr='A';
  591. break;
  592. }
  593. else
  594. {
  595. *ChPtr='0';
  596. ChPtr--;
  597. }
  598. }
  599. }
  600. }
  601. bool IsNameUsable(const char *Name)
  602. {
  603. #ifndef _UNIX
  604. if (Name[0] && Name[1] && strchr(Name+2,':')!=NULL)
  605. return(false);
  606. for (const char *s=Name;*s!=0;s=charnext(s))
  607. {
  608. if ((byte)*s<32)
  609. return(false);
  610. if (*s==' ' && IsPathDiv(s[1]))
  611. return(false);
  612. }
  613. #endif
  614. #ifdef _WIN_ALL
  615. // In Windows we need to check if all file name characters are defined
  616. // in current code page. For example, in Korean CP949 a lot of high ASCII
  617. // characters are not defined, cannot be used in file names, but cannot be
  618. // detected by other checks in this function.
  619. if (MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,Name,-1,NULL,0)==0 &&
  620. GetLastError()==ERROR_NO_UNICODE_TRANSLATION)
  621. return false;
  622. #endif
  623. return(*Name!=0 && strpbrk(Name,"?*<>|\"")==NULL);
  624. }
  625. bool IsNameUsable(const wchar *Name)
  626. {
  627. #ifndef _UNIX
  628. if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL)
  629. return(false);
  630. for (const wchar *s=Name;*s!=0;s++)
  631. {
  632. if ((uint)*s<32)
  633. return(false);
  634. if (*s==' ' && IsPathDiv(s[1]))
  635. return(false);
  636. }
  637. #endif
  638. return(*Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL);
  639. }
  640. void MakeNameUsable(char *Name,bool Extended)
  641. {
  642. #ifdef _WIN_ALL
  643. // In Windows we also need to convert characters not defined in current
  644. // code page. This double conversion changes them to '?', which is
  645. // catched by code below.
  646. size_t NameLength=strlen(Name);
  647. wchar NameW[NM];
  648. CharToWide(Name,NameW,ASIZE(NameW));
  649. WideToChar(NameW,Name,NameLength+1);
  650. Name[NameLength]=0;
  651. #endif
  652. for (char *s=Name;*s!=0;s=charnext(s))
  653. {
  654. if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32)
  655. *s='_';
  656. #ifdef _EMX
  657. if (*s=='=')
  658. *s='_';
  659. #endif
  660. #ifndef _UNIX
  661. if (s-Name>1 && *s==':')
  662. *s='_';
  663. if (*s==' ' && IsPathDiv(s[1]))
  664. *s='_';
  665. #endif
  666. }
  667. }
  668. void MakeNameUsable(wchar *Name,bool Extended)
  669. {
  670. for (wchar *s=Name;*s!=0;s++)
  671. {
  672. if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32)
  673. *s='_';
  674. #ifndef _UNIX
  675. if (s-Name>1 && *s==':')
  676. *s='_';
  677. if (*s==' ' && IsPathDiv(s[1]))
  678. *s='_';
  679. #endif
  680. }
  681. }
  682. char* UnixSlashToDos(char *SrcName,char *DestName,uint MaxLength)
  683. {
  684. if (DestName!=NULL && DestName!=SrcName)
  685. if (strlen(SrcName)>=MaxLength)
  686. {
  687. *DestName=0;
  688. return(DestName);
  689. }
  690. else
  691. strcpy(DestName,SrcName);
  692. for (char *s=SrcName;*s!=0;s=charnext(s))
  693. {
  694. if (*s=='/')
  695. if (DestName==NULL)
  696. *s='\\';
  697. else
  698. DestName[s-SrcName]='\\';
  699. }
  700. return(DestName==NULL ? SrcName:DestName);
  701. }
  702. char* DosSlashToUnix(char *SrcName,char *DestName,uint MaxLength)
  703. {
  704. if (DestName!=NULL && DestName!=SrcName)
  705. if (strlen(SrcName)>=MaxLength)
  706. {
  707. *DestName=0;
  708. return(DestName);
  709. }
  710. else
  711. strcpy(DestName,SrcName);
  712. for (char *s=SrcName;*s!=0;s=charnext(s))
  713. {
  714. if (*s=='\\')
  715. if (DestName==NULL)
  716. *s='/';
  717. else
  718. DestName[s-SrcName]='/';
  719. }
  720. return(DestName==NULL ? SrcName:DestName);
  721. }
  722. wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName,uint MaxLength)
  723. {
  724. if (DestName!=NULL && DestName!=SrcName)
  725. if (wcslen(SrcName)>=MaxLength)
  726. {
  727. *DestName=0;
  728. return(DestName);
  729. }
  730. else
  731. wcscpy(DestName,SrcName);
  732. for (wchar *s=SrcName;*s!=0;s++)
  733. {
  734. if (*s=='/')
  735. if (DestName==NULL)
  736. *s='\\';
  737. else
  738. DestName[s-SrcName]='\\';
  739. }
  740. return(DestName==NULL ? SrcName:DestName);
  741. }
  742. wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName,uint MaxLength)
  743. {
  744. if (DestName!=NULL && DestName!=SrcName)
  745. if (wcslen(SrcName)>=MaxLength)
  746. {
  747. *DestName=0;
  748. return(DestName);
  749. }
  750. else
  751. wcscpy(DestName,SrcName);
  752. for (wchar *s=SrcName;*s!=0;s++)
  753. {
  754. if (*s=='\\')
  755. if (DestName==NULL)
  756. *s='/';
  757. else
  758. DestName[s-SrcName]='/';
  759. }
  760. return(DestName==NULL ? SrcName:DestName);
  761. }
  762. void ConvertNameToFull(const char *Src,char *Dest)
  763. {
  764. #ifdef _WIN_ALL
  765. #ifndef _WIN_CE
  766. char FullName[NM],*NamePtr;
  767. DWORD Code=GetFullPathNameA(Src,ASIZE(FullName),FullName,&NamePtr);
  768. if (Code!=0 && Code<ASIZE(FullName))
  769. strcpy(Dest,FullName);
  770. else
  771. #endif
  772. if (Src!=Dest)
  773. strcpy(Dest,Src);
  774. #else
  775. char FullName[NM];
  776. if (IsPathDiv(*Src) || IsDiskLetter(Src))
  777. strcpy(FullName,Src);
  778. else
  779. {
  780. if (getcwd(FullName,sizeof(FullName))==NULL)
  781. *FullName=0;
  782. else
  783. AddEndSlash(FullName);
  784. strcat(FullName,Src);
  785. }
  786. strcpy(Dest,FullName);
  787. #endif
  788. }
  789. void ConvertNameToFull(const wchar *Src,wchar *Dest)
  790. {
  791. if (Src==NULL || *Src==0)
  792. {
  793. *Dest=0;
  794. return;
  795. }
  796. #ifdef _WIN_ALL
  797. #ifndef _WIN_CE
  798. if (WinNT())
  799. #endif
  800. {
  801. #ifndef _WIN_CE
  802. wchar FullName[NM],*NamePtr;
  803. DWORD Code=GetFullPathNameW(Src,ASIZE(FullName),FullName,&NamePtr);
  804. if (Code!=0 && Code<ASIZE(FullName))
  805. wcscpy(Dest,FullName);
  806. else
  807. #endif
  808. if (Src!=Dest)
  809. wcscpy(Dest,Src);
  810. }
  811. #ifndef _WIN_CE
  812. else
  813. {
  814. char AnsiName[NM];
  815. WideToChar(Src,AnsiName);
  816. ConvertNameToFull(AnsiName,AnsiName);
  817. CharToWide(AnsiName,Dest);
  818. }
  819. #endif
  820. #else
  821. char AnsiName[NM];
  822. WideToChar(Src,AnsiName);
  823. ConvertNameToFull(AnsiName,AnsiName);
  824. CharToWide(AnsiName,Dest);
  825. #endif
  826. }
  827. bool IsFullPath(const char *Path)
  828. {
  829. char PathOnly[NM];
  830. GetFilePath(Path,PathOnly,ASIZE(PathOnly));
  831. if (IsWildcard(PathOnly,NULL))
  832. return(true);
  833. #if defined(_WIN_ALL) || defined(_EMX)
  834. return(Path[0]=='\\' && Path[1]=='\\' ||
  835. IsDiskLetter(Path) && IsPathDiv(Path[2]));
  836. #else
  837. return(IsPathDiv(Path[0]));
  838. #endif
  839. }
  840. bool IsFullPath(const wchar *Path)
  841. {
  842. wchar PathOnly[NM];
  843. GetFilePath(Path,PathOnly,ASIZE(PathOnly));
  844. if (IsWildcard(NULL,PathOnly))
  845. return(true);
  846. #if defined(_WIN_ALL) || defined(_EMX)
  847. return(Path[0]=='\\' && Path[1]=='\\' ||
  848. IsDiskLetter(Path) && IsPathDiv(Path[2]));
  849. #else
  850. return(IsPathDiv(Path[0]));
  851. #endif
  852. }
  853. bool IsDiskLetter(const char *Path)
  854. {
  855. char Letter=etoupper(Path[0]);
  856. return(Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1]));
  857. }
  858. bool IsDiskLetter(const wchar *Path)
  859. {
  860. wchar Letter=etoupperw(Path[0]);
  861. return(Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1]));
  862. }
  863. void GetPathRoot(const char *Path,char *Root)
  864. {
  865. *Root=0;
  866. if (IsDiskLetter(Path))
  867. sprintf(Root,"%c:\\",*Path);
  868. else
  869. if (Path[0]=='\\' && Path[1]=='\\')
  870. {
  871. const char *Slash=strchr(Path+2,'\\');
  872. if (Slash!=NULL)
  873. {
  874. size_t Length;
  875. if ((Slash=strchr(Slash+1,'\\'))!=NULL)
  876. Length=Slash-Path+1;
  877. else
  878. Length=strlen(Path);
  879. strncpy(Root,Path,Length);
  880. Root[Length]=0;
  881. }
  882. }
  883. }
  884. void GetPathRoot(const wchar *Path,wchar *Root)
  885. {
  886. *Root=0;
  887. if (IsDiskLetter(Path))
  888. sprintfw(Root,4,L"%c:\\",*Path);
  889. else
  890. if (Path[0]=='\\' && Path[1]=='\\')
  891. {
  892. const wchar *Slash=wcschr(Path+2,'\\');
  893. if (Slash!=NULL)
  894. {
  895. size_t Length;
  896. if ((Slash=wcschr(Slash+1,'\\'))!=NULL)
  897. Length=Slash-Path+1;
  898. else
  899. Length=wcslen(Path);
  900. wcsncpy(Root,Path,Length);
  901. Root[Length]=0;
  902. }
  903. }
  904. }
  905. int ParseVersionFileName(char *Name,wchar *NameW,bool Truncate)
  906. {
  907. int Version=0;
  908. char *VerText=strrchrd(Name,';');
  909. if (VerText!=NULL)
  910. {
  911. Version=atoi(VerText+1);
  912. if (Truncate)
  913. *VerText=0;
  914. }
  915. if (NameW!=NULL)
  916. {
  917. wchar *VerTextW=wcsrchr(NameW,';');
  918. if (VerTextW!=NULL)
  919. {
  920. if (Version==0)
  921. Version=atoiw(VerTextW+1);
  922. if (Truncate)
  923. *VerTextW=0;
  924. }
  925. }
  926. return(Version);
  927. }
  928. #if !defined(SFX_MODULE) && !defined(SETUP)
  929. // Get the name of first volume. Return the leftmost digit of volume number.
  930. char* VolNameToFirstName(const char *VolName,char *FirstName,bool NewNumbering)
  931. {
  932. if (FirstName!=VolName)
  933. strcpy(FirstName,VolName);
  934. char *VolNumStart=FirstName;
  935. if (NewNumbering)
  936. {
  937. char N='1';
  938. // From the rightmost digit of volume number to the left.
  939. for (char *ChPtr=GetVolNumPart(FirstName);ChPtr>FirstName;ChPtr--)
  940. if (IsDigit(*ChPtr))
  941. {
  942. *ChPtr=N; // Set the rightmost digit to '1' and others to '0'.
  943. N='0';
  944. }
  945. else
  946. if (N=='0')
  947. {
  948. VolNumStart=ChPtr+1; // Store the position of leftmost digit in volume number.
  949. break;
  950. }
  951. }
  952. else
  953. {
  954. // Old volume numbering scheme. Just set the extension to ".rar".
  955. SetExt(FirstName,"rar");
  956. VolNumStart=GetExt(FirstName);
  957. }
  958. if (!FileExist(FirstName))
  959. {
  960. // If the first volume, which name we just generated, is not exist,
  961. // check if volume with same name and any other extension is available.
  962. // It can help in case of *.exe or *.sfx first volume.
  963. char Mask[NM];
  964. strcpy(Mask,FirstName);
  965. SetExt(Mask,"*");
  966. FindFile Find;
  967. Find.SetMask(Mask);
  968. FindData FD;
  969. while (Find.Next(&FD))
  970. {
  971. Archive Arc;
  972. if (Arc.Open(FD.Name,FD.NameW) && Arc.IsArchive(true) && !Arc.NotFirstVolume)
  973. {
  974. strcpy(FirstName,FD.Name);
  975. break;
  976. }
  977. }
  978. }
  979. return(VolNumStart);
  980. }
  981. #endif
  982. #if !defined(SFX_MODULE) && !defined(SETUP)
  983. // Get the name of first volume. Return the leftmost digit of volume number.
  984. wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,bool NewNumbering)
  985. {
  986. if (FirstName!=VolName)
  987. wcscpy(FirstName,VolName);
  988. wchar *VolNumStart=FirstName;
  989. if (NewNumbering)
  990. {
  991. wchar N='1';
  992. // From the rightmost digit of volume number to the left.
  993. for (wchar *ChPtr=GetVolNumPart(FirstName);ChPtr>FirstName;ChPtr--)
  994. if (IsDigit(*ChPtr))
  995. {
  996. *ChPtr=N; // Set the rightmost digit to '1' and others to '0'.
  997. N='0';
  998. }
  999. else
  1000. if (N=='0')
  1001. {
  1002. VolNumStart=ChPtr+1; // Store the position of leftmost digit in volume number.
  1003. break;
  1004. }
  1005. }
  1006. else
  1007. {
  1008. // Old volume numbering scheme. Just set the extension to ".rar".
  1009. SetExt(FirstName,L"rar");
  1010. VolNumStart=GetExt(FirstName);
  1011. }
  1012. if (!FileExist(NULL,FirstName))
  1013. {
  1014. // If the first volume, which name we just generated, is not exist,
  1015. // check if volume with same name and any other extension is available.
  1016. // It can help in case of *.exe or *.sfx first volume.
  1017. wchar Mask[NM];
  1018. wcscpy(Mask,FirstName);
  1019. SetExt(Mask,L"*");
  1020. FindFile Find;
  1021. Find.SetMaskW(Mask);
  1022. FindData FD;
  1023. while (Find.Next(&FD))
  1024. {
  1025. Archive Arc;
  1026. if (Arc.Open(FD.Name,FD.NameW) && Arc.IsArchive(true) && !Arc.NotFirstVolume)
  1027. {
  1028. wcscpy(FirstName,FD.NameW);
  1029. break;
  1030. }
  1031. }
  1032. }
  1033. return(VolNumStart);
  1034. }
  1035. #endif
  1036. #ifndef SFX_MODULE
  1037. static void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
  1038. uint ArcNumber,bool &ArcNumPresent);
  1039. void GenerateArchiveName(char *ArcName,wchar *ArcNameW,size_t MaxSize,
  1040. char *GenerateMask,bool Archiving)
  1041. {
  1042. // Must be enough space for archive name plus all stuff in mask plus
  1043. // extra overhead produced by mask 'N' (archive number) characters.
  1044. // One 'N' character can result in several numbers if we process more
  1045. // than 9 archives.
  1046. char NewName[NM+MAX_GENERATE_MASK+20];
  1047. wchar NewNameW[NM+MAX_GENERATE_MASK+20];
  1048. uint ArcNumber=1;
  1049. while (true) // Loop for 'N' (archive number) processing.
  1050. {
  1051. strncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
  1052. wcsncpyz(NewNameW,NullToEmpty(ArcNameW),ASIZE(NewNameW));
  1053. bool ArcNumPresent=false;
  1054. GenArcName(NewName,NewNameW,GenerateMask,ArcNumber,ArcNumPresent);
  1055. if (!ArcNumPresent)
  1056. break;
  1057. if (!FileExist(NewName,NewNameW))
  1058. {
  1059. if (!Archiving && ArcNumber>1)
  1060. {
  1061. // If we perform non-archiving operation, we need to use the last
  1062. // existing archive before the first unused name. So we generate
  1063. // the name for (ArcNumber-1) below.
  1064. strncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
  1065. wcsncpyz(NewNameW,NullToEmpty(ArcNameW),ASIZE(NewNameW));
  1066. GenArcName(NewName,NewNameW,GenerateMask,ArcNumber-1,ArcNumPresent);
  1067. }
  1068. break;
  1069. }
  1070. ArcNumber++;
  1071. }
  1072. if (ArcName!=NULL && *ArcName!=0)
  1073. strncpyz(ArcName,NewName,MaxSize);
  1074. if (ArcNameW!=NULL && *ArcNameW!=0)
  1075. wcsncpyz(ArcNameW,NewNameW,MaxSize);
  1076. }
  1077. void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
  1078. uint ArcNumber,bool &ArcNumPresent)
  1079. {
  1080. bool Prefix=false;
  1081. if (*GenerateMask=='+')
  1082. {
  1083. Prefix=true; // Add the time string before the archive name.
  1084. GenerateMask++; // Skip '+' in the beginning of time mask.
  1085. }
  1086. char Mask[MAX_GENERATE_MASK];
  1087. strncpyz(Mask,*GenerateMask ? GenerateMask:"yyyymmddhhmmss",ASIZE(Mask));
  1088. bool QuoteMode=false,Hours=false;
  1089. for (uint I=0;Mask[I]!=0;I++)
  1090. {
  1091. if (Mask[I]=='{' || Mask[I]=='}')
  1092. {
  1093. QuoteMode=(Mask[I]=='{');
  1094. continue;
  1095. }
  1096. if (QuoteMode)
  1097. continue;
  1098. int CurChar=etoupper(Mask[I]);
  1099. if (CurChar=='H')
  1100. Hours=true;
  1101. if (Hours && CurChar=='M')
  1102. {
  1103. // Replace minutes with 'I'. We use 'M' both for months and minutes,
  1104. // so we treat as minutes only those 'M' which are found after hours.
  1105. Mask[I]='I';
  1106. }
  1107. if (CurChar=='N')
  1108. {
  1109. uint Digits=GetDigits(ArcNumber);
  1110. uint NCount=0;
  1111. while (etoupper(Mask[I+NCount])=='N')
  1112. NCount++;
  1113. // Here we ensure that we have enough 'N' characters to fit all digits
  1114. // of archive number. We'll replace them by actual number later
  1115. // in this function.
  1116. if (NCount<Digits)
  1117. {
  1118. memmove(Mask+I+Digits,Mask+I+NCount,strlen(Mask+I+NCount)+1);
  1119. memset(Mask+I,'N',Digits);
  1120. }
  1121. I+=Max(Digits,NCount)-1;
  1122. ArcNumPresent=true;
  1123. continue;
  1124. }
  1125. }
  1126. RarTime CurTime;
  1127. CurTime.SetCurrentTime();
  1128. RarLocalTime rlt;
  1129. CurTime.GetLocal(&rlt);
  1130. char Ext[NM];
  1131. *Ext=0;
  1132. if (ArcName!=NULL && *ArcName!=0)
  1133. {
  1134. char *Dot;
  1135. if ((Dot=GetExt(ArcName))==NULL)
  1136. strcpy(Ext,*PointToName(ArcName)==0 ? ".rar":"");
  1137. else
  1138. {
  1139. strcpy(Ext,Dot);
  1140. *Dot=0;
  1141. }
  1142. }
  1143. wchar ExtW[NM];
  1144. *ExtW=0;
  1145. if (ArcNameW!=NULL && *ArcNameW!=0)
  1146. {
  1147. wchar *DotW;
  1148. if ((DotW=GetExt(ArcNameW))==NULL)
  1149. wcscpy(ExtW,*PointToName(ArcNameW)==0 ? L".rar":L"");
  1150. else
  1151. {
  1152. wcscpy(ExtW,DotW);
  1153. *DotW=0;
  1154. }
  1155. }
  1156. int WeekDay=rlt.wDay==0 ? 6:rlt.wDay-1;
  1157. int StartWeekDay=rlt.yDay-WeekDay;
  1158. if (StartWeekDay<0)
  1159. if (StartWeekDay<=-4)
  1160. StartWeekDay+=IsLeapYear(rlt.Year-1) ? 366:365;
  1161. else
  1162. StartWeekDay=0;
  1163. int CurWeek=StartWeekDay/7+1;
  1164. if (StartWeekDay%7>=4)
  1165. CurWeek++;
  1166. char Field[10][6];
  1167. sprintf(Field[0],"%04d",rlt.Year);
  1168. sprintf(Field[1],"%02d",rlt.Month);
  1169. sprintf(Field[2],"%02d",rlt.Day);
  1170. sprintf(Field[3],"%02d",rlt.Hour);
  1171. sprintf(Field[4],"%02d",rlt.Minute);
  1172. sprintf(Field[5],"%02d",rlt.Second);
  1173. sprintf(Field[6],"%02d",CurWeek);
  1174. sprintf(Field[7],"%d",WeekDay+1);
  1175. sprintf(Field[8],"%03d",rlt.yDay+1);
  1176. sprintf(Field[9],"%05d",ArcNumber);
  1177. const char *MaskChars="YMDHISWAEN";
  1178. int CField[sizeof(Field)/sizeof(Field[0])];
  1179. memset(CField,0,sizeof(CField));
  1180. QuoteMode=false;
  1181. for (int I=0;Mask[I]!=0;I++)
  1182. {
  1183. if (Mask[I]=='{' || Mask[I]=='}')
  1184. {
  1185. QuoteMode=(Mask[I]=='{');
  1186. continue;
  1187. }
  1188. if (QuoteMode)
  1189. continue;
  1190. const char *Ch=strchr(MaskChars,etoupper(Mask[I]));
  1191. if (Ch!=NULL)
  1192. CField[Ch-MaskChars]++;
  1193. }
  1194. char DateText[MAX_GENERATE_MASK];
  1195. *DateText=0;
  1196. QuoteMode=false;
  1197. for (size_t I=0,J=0;Mask[I]!=0 && J<ASIZE(DateText)-1;I++)
  1198. {
  1199. if (Mask[I]=='{' || Mask[I]=='}')
  1200. {
  1201. QuoteMode=(Mask[I]=='{');
  1202. continue;
  1203. }
  1204. const char *Ch=strchr(MaskChars,etoupper(Mask[I]));
  1205. if (Ch==NULL || QuoteMode)
  1206. DateText[J]=Mask[I];
  1207. else
  1208. {
  1209. size_t FieldPos=Ch-MaskChars;
  1210. int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--;
  1211. if (FieldPos==1 && etoupper(Mask[I+1])=='M' && etoupper(Mask[I+2])=='M')
  1212. {
  1213. strncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J);
  1214. J=strlen(DateText);
  1215. I+=2;
  1216. continue;
  1217. }
  1218. if (CharPos<0)
  1219. DateText[J]=Mask[I];
  1220. else
  1221. DateText[J]=Field[FieldPos][CharPos];
  1222. }
  1223. DateText[++J]=0;
  1224. }
  1225. wchar DateTextW[ASIZE(DateText)];
  1226. CharToWide(DateText,DateTextW);
  1227. if (Prefix)
  1228. {
  1229. if (ArcName!=NULL && *ArcName!=0)
  1230. {
  1231. char NewName[NM];
  1232. GetFilePath(ArcName,NewName,ASIZE(NewName));
  1233. AddEndSlash(NewName);
  1234. strcat(NewName,DateText);
  1235. strcat(NewName,PointToName(ArcName));
  1236. strcpy(ArcName,NewName);
  1237. }
  1238. if (ArcNameW!=NULL && *ArcNameW!=0)
  1239. {
  1240. wchar NewNameW[NM];
  1241. GetFilePath(ArcNameW,NewNameW,ASIZE(NewNameW));
  1242. AddEndSlash(NewNameW);
  1243. wcscat(NewNameW,DateTextW);
  1244. wcscat(NewNameW,PointToName(ArcNameW));
  1245. wcscpy(ArcNameW,NewNameW);
  1246. }
  1247. }
  1248. else
  1249. {
  1250. if (ArcName!=NULL && *ArcName!=0)
  1251. strcat(ArcName,DateText);
  1252. if (ArcNameW!=NULL && *ArcNameW!=0)
  1253. wcscat(ArcNameW,DateTextW);
  1254. }
  1255. if (ArcName!=NULL && *ArcName!=0)
  1256. strcat(ArcName,Ext);
  1257. if (ArcNameW!=NULL && *ArcNameW!=0)
  1258. wcscat(ArcNameW,ExtW);
  1259. }
  1260. #endif
  1261. wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize)
  1262. {
  1263. if (NameW!=NULL && *NameW!=0)
  1264. {
  1265. if (DestW!=NameW)
  1266. wcsncpy(DestW,NameW,DestSize);
  1267. }
  1268. else
  1269. if (Name!=NULL)
  1270. CharToWide(Name,DestW,DestSize);
  1271. else
  1272. *DestW=0;
  1273. // Ensure that we return a zero terminate string for security reasons.
  1274. if (DestSize>0)
  1275. DestW[DestSize-1]=0;
  1276. return(DestW);
  1277. }
  1278. // Unlike WideToChar, always returns the zero terminated string,
  1279. // even if the destination buffer size is not enough.
  1280. char* GetAsciiName(const wchar *NameW,char *Name,size_t DestSize)
  1281. {
  1282. if (DestSize>0)
  1283. {
  1284. WideToChar(NameW,Name,DestSize);
  1285. Name[DestSize-1]=0;
  1286. }
  1287. else
  1288. *Name=0;
  1289. return Name;
  1290. }