Common.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "Common.h"
  5. #include "Exceptions.h"
  6. #include "TextsCore.h"
  7. #include "Interface.h"
  8. #include "PuttyIntf.h"
  9. #include <StrUtils.hpp>
  10. #include <math.h>
  11. #include <shellapi.h>
  12. //---------------------------------------------------------------------------
  13. #pragma package(smart_init)
  14. //---------------------------------------------------------------------------
  15. #ifdef _DEBUG
  16. #include <stdio.h>
  17. void __fastcall Trace(const AnsiString SourceFile, const AnsiString Func,
  18. int Line, const AnsiString Message)
  19. {
  20. const char * FileName = getenv(TRACEENV);
  21. if (FileName == NULL)
  22. {
  23. FileName = "c:\\winscptrace.log";
  24. }
  25. FILE * File = fopen(FileName, "a");
  26. if (File != NULL)
  27. {
  28. fprintf(File, "[%s] %s:%d:%s\n %s\n",
  29. Now().TimeString().c_str(),
  30. ExtractFileName(SourceFile).c_str(), Line, Func.c_str(), Message.c_str());
  31. fclose(File);
  32. }
  33. }
  34. //---------------------------------------------------------------------------
  35. void __fastcall DoAssert(char * Message, char * Filename, int LineNumber)
  36. {
  37. Trace(Filename, "assert", LineNumber, Message);
  38. _assert(Message, Filename, LineNumber);
  39. }
  40. #endif // ifdef _DEBUG
  41. //---------------------------------------------------------------------------
  42. // TCriticalSection
  43. //---------------------------------------------------------------------------
  44. __fastcall TCriticalSection::TCriticalSection()
  45. {
  46. FAcquired = 0;
  47. InitializeCriticalSection(&FSection);
  48. }
  49. //---------------------------------------------------------------------------
  50. __fastcall TCriticalSection::~TCriticalSection()
  51. {
  52. assert(FAcquired == 0);
  53. DeleteCriticalSection(&FSection);
  54. }
  55. //---------------------------------------------------------------------------
  56. void __fastcall TCriticalSection::Enter()
  57. {
  58. EnterCriticalSection(&FSection);
  59. FAcquired++;
  60. }
  61. //---------------------------------------------------------------------------
  62. void __fastcall TCriticalSection::Leave()
  63. {
  64. FAcquired--;
  65. LeaveCriticalSection(&FSection);
  66. }
  67. //---------------------------------------------------------------------------
  68. // TGuard
  69. //---------------------------------------------------------------------------
  70. __fastcall TGuard::TGuard(TCriticalSection * ACriticalSection) :
  71. FCriticalSection(ACriticalSection)
  72. {
  73. assert(ACriticalSection != NULL);
  74. FCriticalSection->Enter();
  75. }
  76. //---------------------------------------------------------------------------
  77. __fastcall TGuard::~TGuard()
  78. {
  79. FCriticalSection->Leave();
  80. }
  81. //---------------------------------------------------------------------------
  82. // TUnguard
  83. //---------------------------------------------------------------------------
  84. __fastcall TUnguard::TUnguard(TCriticalSection * ACriticalSection) :
  85. FCriticalSection(ACriticalSection)
  86. {
  87. assert(ACriticalSection != NULL);
  88. FCriticalSection->Leave();
  89. }
  90. //---------------------------------------------------------------------------
  91. __fastcall TUnguard::~TUnguard()
  92. {
  93. FCriticalSection->Enter();
  94. }
  95. //---------------------------------------------------------------------------
  96. //---------------------------------------------------------------------------
  97. const char EngShortMonthNames[12][4] =
  98. {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  99. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  100. //---------------------------------------------------------------------------
  101. AnsiString ReplaceChar(AnsiString Str, Char A, Char B)
  102. {
  103. for (Integer Index = 0; Index < Str.Length(); Index++)
  104. if (Str[Index+1] == A) Str[Index+1] = B;
  105. return Str;
  106. }
  107. //---------------------------------------------------------------------------
  108. AnsiString DeleteChar(AnsiString Str, Char C)
  109. {
  110. int P;
  111. while ((P = Str.Pos(C)) > 0)
  112. {
  113. Str.Delete(P, 1);
  114. }
  115. return Str;
  116. }
  117. //---------------------------------------------------------------------------
  118. void PackStr(AnsiString &Str)
  119. {
  120. // Following will free unnecessary bytes
  121. Str = Str.c_str();
  122. }
  123. //---------------------------------------------------------------------------
  124. AnsiString MakeValidFileName(AnsiString FileName)
  125. {
  126. AnsiString IllegalChars = ";,=+<>|\"[] \\/?*";
  127. for (int Index = 0; Index < IllegalChars.Length(); Index++)
  128. {
  129. FileName = ReplaceChar(FileName, IllegalChars[Index+1], '-');
  130. }
  131. return FileName;
  132. }
  133. //---------------------------------------------------------------------------
  134. AnsiString RootKeyToStr(HKEY RootKey)
  135. {
  136. if (RootKey == HKEY_USERS) return "HKEY_USERS";
  137. else
  138. if (RootKey == HKEY_LOCAL_MACHINE) return "HKEY_LOCAL_MACHINE";
  139. else
  140. if (RootKey == HKEY_CURRENT_USER) return "HKEY_CURRENT_USER";
  141. else
  142. if (RootKey == HKEY_CLASSES_ROOT) return "HKEY_CLASSES_ROOT";
  143. else
  144. if (RootKey == HKEY_CURRENT_CONFIG) return "HKEY_CURRENT_CONFIG";
  145. else
  146. if (RootKey == HKEY_DYN_DATA) return "HKEY_DYN_DATA";
  147. else
  148. { Abort(); return ""; };
  149. }
  150. //---------------------------------------------------------------------------
  151. AnsiString BooleanToEngStr(bool B)
  152. {
  153. return B ? "Yes" : "No";
  154. }
  155. //---------------------------------------------------------------------------
  156. AnsiString BooleanToStr(bool B)
  157. {
  158. return B ? LoadStr(YES_STR) : LoadStr(NO_STR);
  159. }
  160. //---------------------------------------------------------------------------
  161. AnsiString CutToChar(AnsiString &Str, Char Ch, bool Trim)
  162. {
  163. Integer P = Str.Pos(Ch);
  164. AnsiString Result;
  165. if (P)
  166. {
  167. Result = Str.SubString(1, P-1);
  168. Str.Delete(1, P);
  169. }
  170. else
  171. {
  172. Result = Str;
  173. Str = "";
  174. }
  175. if (Trim)
  176. {
  177. Result = Result.TrimRight();
  178. Str = Str.TrimLeft();
  179. }
  180. return Result;
  181. }
  182. //---------------------------------------------------------------------------
  183. AnsiString CutToChars(AnsiString & Str, AnsiString Chs, bool Trim,
  184. char * Delimiter)
  185. {
  186. int P;
  187. for (P = 1; P <= Str.Length(); P++)
  188. {
  189. if (IsDelimiter(Chs, Str, P))
  190. {
  191. break;
  192. }
  193. }
  194. AnsiString Result;
  195. if (P <= Str.Length())
  196. {
  197. if (Delimiter != NULL)
  198. {
  199. *Delimiter = Str[P];
  200. }
  201. Result = Str.SubString(1, P-1);
  202. Str.Delete(1, P);
  203. }
  204. else
  205. {
  206. if (Delimiter != NULL)
  207. {
  208. *Delimiter = '\0';
  209. }
  210. Result = Str;
  211. Str = "";
  212. }
  213. if (Trim)
  214. {
  215. Result = Result.TrimRight();
  216. Str = Str.TrimLeft();
  217. }
  218. return Result;
  219. }
  220. //---------------------------------------------------------------------------
  221. AnsiString DelimitStr(AnsiString Str, AnsiString Chars)
  222. {
  223. for (int i = 1; i <= Str.Length(); i++)
  224. {
  225. if (Str.IsDelimiter(Chars, i))
  226. {
  227. Str.Insert("\\", i);
  228. i++;
  229. }
  230. }
  231. return Str;
  232. }
  233. //---------------------------------------------------------------------------
  234. AnsiString ShellDelimitStr(AnsiString Str, char Quote)
  235. {
  236. AnsiString Chars = "$\\";
  237. if (Quote == '"')
  238. {
  239. Chars += "`\"";
  240. }
  241. return DelimitStr(Str, Chars);
  242. }
  243. //---------------------------------------------------------------------------
  244. AnsiString ExceptionLogString(Exception *E)
  245. {
  246. assert(E);
  247. if (E->InheritsFrom(__classid(Exception)))
  248. {
  249. AnsiString Msg;
  250. Msg = FORMAT("(%s) %s", (E->ClassName(), E->Message));
  251. if (E->InheritsFrom(__classid(ExtException)))
  252. {
  253. TStrings * MoreMessages = ((ExtException*)E)->MoreMessages;
  254. if (MoreMessages)
  255. {
  256. Msg += "\n" +
  257. StringReplace(MoreMessages->Text, "\r", "", TReplaceFlags() << rfReplaceAll);
  258. }
  259. }
  260. return Msg;
  261. }
  262. else
  263. {
  264. char Buffer[1024];
  265. ExceptionErrorMessage(ExceptObject(), ExceptAddr(), Buffer, sizeof(Buffer));
  266. return AnsiString(Buffer);
  267. }
  268. }
  269. //---------------------------------------------------------------------------
  270. bool IsDots(const AnsiString Str)
  271. {
  272. char * str = Str.c_str();
  273. return (str[strspn(str, ".")] == '\0');
  274. }
  275. //---------------------------------------------------------------------------
  276. AnsiString __fastcall SystemTemporaryDirectory()
  277. {
  278. AnsiString TempDir;
  279. TempDir.SetLength(MAX_PATH);
  280. TempDir.SetLength(GetTempPath(MAX_PATH, TempDir.c_str()));
  281. return TempDir;
  282. }
  283. //---------------------------------------------------------------------------
  284. AnsiString __fastcall StripPathQuotes(const AnsiString Path)
  285. {
  286. if ((Path.Length() >= 2) &&
  287. (Path[1] == '\"') && (Path[Path.Length()] == '\"'))
  288. {
  289. return Path.SubString(2, Path.Length() - 2);
  290. }
  291. else
  292. {
  293. return Path;
  294. }
  295. }
  296. //---------------------------------------------------------------------------
  297. AnsiString __fastcall AddPathQuotes(AnsiString Path)
  298. {
  299. Path = StripPathQuotes(Path);
  300. if (Path.Pos(" "))
  301. {
  302. Path = "\"" + Path + "\"";
  303. }
  304. return Path;
  305. }
  306. //---------------------------------------------------------------------------
  307. void __fastcall SplitCommand(AnsiString Command, AnsiString &Program,
  308. AnsiString & Params, AnsiString & Dir)
  309. {
  310. Command = Command.Trim();
  311. Params = "";
  312. Dir = "";
  313. if (!Command.IsEmpty() && (Command[1] == '\"'))
  314. {
  315. Command.Delete(1, 1);
  316. int P = Command.Pos('"');
  317. if (P)
  318. {
  319. Program = Command.SubString(1, P-1).Trim();
  320. Params = Command.SubString(P + 1, Command.Length() - P).Trim();
  321. }
  322. else
  323. {
  324. throw Exception(FMTLOAD(INVALID_SHELL_COMMAND, ("\"" + Command)));
  325. }
  326. }
  327. else
  328. {
  329. int P = Command.Pos(" ");
  330. if (P)
  331. {
  332. Program = Command.SubString(1, P).Trim();
  333. Params = Command.SubString(P + 1, Command.Length() - P).Trim();
  334. }
  335. else
  336. {
  337. Program = Command;
  338. }
  339. }
  340. int B = Program.LastDelimiter("\\/");
  341. if (B)
  342. {
  343. Dir = Program.SubString(1, B).Trim();
  344. }
  345. }
  346. //---------------------------------------------------------------------------
  347. AnsiString __fastcall ExtractProgram(AnsiString Command)
  348. {
  349. AnsiString Program;
  350. AnsiString Params;
  351. AnsiString Dir;
  352. SplitCommand(Command, Program, Params, Dir);
  353. return Program;
  354. }
  355. //---------------------------------------------------------------------------
  356. AnsiString __fastcall FormatCommand(AnsiString Program, AnsiString Params)
  357. {
  358. Program = Program.Trim();
  359. Params = Params.Trim();
  360. if (!Params.IsEmpty()) Params = " " + Params;
  361. if (Program.Pos(" ")) Program = "\"" + Program + "\"";
  362. return Program + Params;
  363. }
  364. //---------------------------------------------------------------------------
  365. const char ShellCommandFileNamePattern[] = "!.!";
  366. //---------------------------------------------------------------------------
  367. void __fastcall ReformatFileNameCommand(AnsiString & Command)
  368. {
  369. AnsiString Program, Params, Dir;
  370. SplitCommand(Command, Program, Params, Dir);
  371. if (Params.Pos(ShellCommandFileNamePattern) == 0)
  372. {
  373. Params = Params + (Params.IsEmpty() ? "" : " ") + ShellCommandFileNamePattern;
  374. }
  375. Command = FormatCommand(Program, Params);
  376. }
  377. //---------------------------------------------------------------------------
  378. AnsiString __fastcall ExpandFileNameCommand(const AnsiString Command,
  379. const AnsiString FileName)
  380. {
  381. return AnsiReplaceStr(Command, ShellCommandFileNamePattern,
  382. AddPathQuotes(FileName));
  383. }
  384. //---------------------------------------------------------------------------
  385. bool __fastcall IsDisplayableStr(const AnsiString Str)
  386. {
  387. bool Displayable = true;
  388. int Index = 1;
  389. while ((Index <= Str.Length()) && Displayable)
  390. {
  391. if (Str[Index] < '\32')
  392. {
  393. Displayable = false;
  394. }
  395. Index++;
  396. }
  397. return Displayable;
  398. }
  399. //---------------------------------------------------------------------------
  400. AnsiString __fastcall CharToHex(char Ch)
  401. {
  402. return IntToHex((unsigned char)Ch, 2);
  403. }
  404. //---------------------------------------------------------------------------
  405. AnsiString __fastcall StrToHex(const AnsiString Str)
  406. {
  407. AnsiString Result;
  408. for (int i = 1; i <= Str.Length(); i++)
  409. {
  410. Result += CharToHex(Str[i]);
  411. }
  412. return Result;
  413. }
  414. //---------------------------------------------------------------------------
  415. AnsiString __fastcall HexToStr(const AnsiString Hex)
  416. {
  417. static AnsiString Digits = "0123456789ABCDEF";
  418. AnsiString Result;
  419. int L, P1, P2;
  420. L = Hex.Length();
  421. if (L % 2 == 0)
  422. {
  423. for (int i = 1; i <= Hex.Length(); i += 2)
  424. {
  425. P1 = Digits.Pos(Hex[i]);
  426. P2 = Digits.Pos(Hex[i + 1]);
  427. if (P1 <= 0 || P2 <= 0)
  428. {
  429. break;
  430. }
  431. else
  432. {
  433. Result += static_cast<char>((P1 - 1) * 16 + P2 - 1);
  434. }
  435. }
  436. }
  437. return Result;
  438. }
  439. //---------------------------------------------------------------------------
  440. unsigned int __fastcall HexToInt(const AnsiString Hex, int MinChars)
  441. {
  442. static AnsiString Digits = "0123456789ABCDEF";
  443. int Result = 0;
  444. int I = 1;
  445. while (I <= Hex.Length())
  446. {
  447. int A = Digits.Pos(Hex[I]);
  448. if (A <= 0)
  449. {
  450. if ((MinChars < 0) || (I <= MinChars))
  451. {
  452. Result = 0;
  453. }
  454. break;
  455. }
  456. Result = (Result * 16) + (A - 1);
  457. I++;
  458. }
  459. return Result;
  460. }
  461. //---------------------------------------------------------------------------
  462. __int64 __fastcall ParseSize(AnsiString SizeStr)
  463. {
  464. return parse_blocksize(SizeStr.c_str());
  465. }
  466. //---------------------------------------------------------------------------
  467. bool __fastcall FileSearchRec(const AnsiString FileName, TSearchRec & Rec)
  468. {
  469. int FindAttrs = faReadOnly | faHidden | faSysFile | faDirectory | faArchive;
  470. bool Result = (FindFirst(FileName, FindAttrs, Rec) == 0);
  471. if (Result)
  472. {
  473. FindClose(Rec);
  474. }
  475. return Result;
  476. }
  477. //---------------------------------------------------------------------------
  478. void __fastcall ProcessLocalDirectory(AnsiString DirName,
  479. TProcessLocalFileEvent CallBackFunc, void * Param,
  480. int FindAttrs)
  481. {
  482. assert(CallBackFunc);
  483. if (FindAttrs < 0)
  484. {
  485. FindAttrs = faReadOnly | faHidden | faSysFile | faDirectory | faArchive;
  486. }
  487. TSearchRec SearchRec;
  488. DirName = IncludeTrailingBackslash(DirName);
  489. if (FindFirst(DirName + "*.*", FindAttrs, SearchRec) == 0)
  490. {
  491. try
  492. {
  493. do
  494. {
  495. if ((SearchRec.Name != ".") && (SearchRec.Name != ".."))
  496. {
  497. CallBackFunc(DirName + SearchRec.Name, SearchRec, Param);
  498. }
  499. } while (FindNext(SearchRec) == 0);
  500. }
  501. __finally
  502. {
  503. FindClose(SearchRec);
  504. }
  505. }
  506. }
  507. //---------------------------------------------------------------------------
  508. struct TDateTimeParams
  509. {
  510. TDateTime UnixEpoch;
  511. double BaseDifference;
  512. long BaseDifferenceSec;
  513. double CurrentDaylightDifference;
  514. long CurrentDaylightDifferenceSec;
  515. double CurrentDifference;
  516. long CurrentDifferenceSec;
  517. double StandardDifference;
  518. long StandardDifferenceSec;
  519. double DaylightDifference;
  520. long DaylightDifferenceSec;
  521. SYSTEMTIME StandardDate;
  522. SYSTEMTIME DaylightDate;
  523. };
  524. static bool DateTimeParamsInitialized = false;
  525. static TDateTimeParams DateTimeParams;
  526. static TCriticalSection DateTimeParamsSection;
  527. //---------------------------------------------------------------------------
  528. static TDateTimeParams * __fastcall GetDateTimeParams()
  529. {
  530. if (!DateTimeParamsInitialized)
  531. {
  532. TGuard Guard(&DateTimeParamsSection);
  533. if (!DateTimeParamsInitialized)
  534. {
  535. TIME_ZONE_INFORMATION TZI;
  536. unsigned long GTZI;
  537. GTZI = GetTimeZoneInformation(&TZI);
  538. switch (GTZI)
  539. {
  540. case TIME_ZONE_ID_UNKNOWN:
  541. DateTimeParams.CurrentDifferenceSec = 0;
  542. DateTimeParams.CurrentDaylightDifferenceSec = 0;
  543. break;
  544. case TIME_ZONE_ID_STANDARD:
  545. DateTimeParams.CurrentDaylightDifferenceSec = TZI.StandardBias;
  546. break;
  547. case TIME_ZONE_ID_DAYLIGHT:
  548. DateTimeParams.CurrentDaylightDifferenceSec = TZI.DaylightBias;
  549. break;
  550. case TIME_ZONE_ID_INVALID:
  551. default:
  552. throw Exception(TIMEZONE_ERROR);
  553. }
  554. // Is it same as SysUtils::UnixDateDelta = 25569 ??
  555. DateTimeParams.UnixEpoch = EncodeDate(1970, 1, 1);
  556. DateTimeParams.BaseDifferenceSec = TZI.Bias;
  557. DateTimeParams.BaseDifference = double(TZI.Bias) / 1440;
  558. DateTimeParams.BaseDifferenceSec *= 60;
  559. DateTimeParams.CurrentDifferenceSec = TZI.Bias +
  560. DateTimeParams.CurrentDaylightDifferenceSec;
  561. DateTimeParams.CurrentDifference =
  562. double(DateTimeParams.CurrentDifferenceSec) / 1440;
  563. DateTimeParams.CurrentDifferenceSec *= 60;
  564. DateTimeParams.CurrentDaylightDifference =
  565. double(DateTimeParams.CurrentDaylightDifferenceSec) / 1440;
  566. DateTimeParams.CurrentDaylightDifferenceSec *= 60;
  567. DateTimeParams.DaylightDifferenceSec = TZI.DaylightBias * 60;
  568. DateTimeParams.DaylightDifference = double(TZI.DaylightBias) / 1440;
  569. DateTimeParams.StandardDifferenceSec = TZI.StandardBias * 60;
  570. DateTimeParams.StandardDifference = double(TZI.StandardBias) / 1440;
  571. DateTimeParams.StandardDate = TZI.StandardDate;
  572. DateTimeParams.DaylightDate = TZI.DaylightDate;
  573. DateTimeParamsInitialized = true;
  574. }
  575. }
  576. return &DateTimeParams;
  577. }
  578. //---------------------------------------------------------------------------
  579. static void __fastcall EncodeDSTMargin(const SYSTEMTIME & Date, unsigned short Year,
  580. TDateTime & Result)
  581. {
  582. if (Date.wYear == 0)
  583. {
  584. TDateTime Temp = EncodeDate(Year, Date.wMonth, 1);
  585. Result = Temp + ((Date.wDayOfWeek - DayOfWeek(Temp) + 8) % 7) +
  586. (7 * (Date.wDay - 1));
  587. if (Date.wDay == 5)
  588. {
  589. unsigned short Month = static_cast<unsigned short>(Date.wMonth + 1);
  590. if (Month > 12)
  591. {
  592. Month = static_cast<unsigned short>(Month - 12);
  593. Year++;
  594. }
  595. if (Result > EncodeDate(Year, Month, 1))
  596. {
  597. Result -= 7;
  598. }
  599. }
  600. Result += EncodeTime(Date.wHour, Date.wMinute, Date.wSecond,
  601. Date.wMilliseconds);
  602. }
  603. else
  604. {
  605. Result = EncodeDate(Year, Date.wMonth, Date.wDay) +
  606. EncodeTime(Date.wHour, Date.wMinute, Date.wSecond, Date.wMilliseconds);
  607. }
  608. }
  609. //---------------------------------------------------------------------------
  610. static bool __fastcall IsDateInDST(const TDateTime & DateTime)
  611. {
  612. struct TDSTCache
  613. {
  614. bool Filled;
  615. unsigned short Year;
  616. TDateTime StandardDate;
  617. TDateTime DaylightDate;
  618. };
  619. static TDSTCache DSTCache[10];
  620. static int DSTCacheCount = 0;
  621. static TCriticalSection Section;
  622. TDateTimeParams * Params = GetDateTimeParams();
  623. bool Result;
  624. if (Params->StandardDate.wMonth == 0)
  625. {
  626. Result = false;
  627. }
  628. else
  629. {
  630. unsigned short Year, Month, Day;
  631. DecodeDate(DateTime, Year, Month, Day);
  632. TDSTCache * CurrentCache = &DSTCache[0];
  633. int CacheIndex = 0;
  634. while ((CacheIndex < DSTCacheCount) && (CacheIndex < LENOF(DSTCache)) &&
  635. CurrentCache->Filled && (CurrentCache->Year != Year))
  636. {
  637. CacheIndex++;
  638. CurrentCache++;
  639. }
  640. if ((CacheIndex < DSTCacheCount) && (CacheIndex < LENOF(DSTCache)) &&
  641. CurrentCache->Filled)
  642. {
  643. assert(CurrentCache->Year == Year);
  644. Result = (DateTime >= CurrentCache->DaylightDate) &&
  645. (DateTime < CurrentCache->StandardDate);
  646. }
  647. else
  648. {
  649. TDSTCache NewCache;
  650. EncodeDSTMargin(Params->StandardDate, Year, NewCache.StandardDate);
  651. EncodeDSTMargin(Params->DaylightDate, Year, NewCache.DaylightDate);
  652. if (DSTCacheCount < LENOF(DSTCache))
  653. {
  654. TGuard Guard(&Section);
  655. if (DSTCacheCount < LENOF(DSTCache))
  656. {
  657. NewCache.Year = Year;
  658. DSTCache[DSTCacheCount] = NewCache;
  659. DSTCache[DSTCacheCount].Filled = true;
  660. DSTCacheCount++;
  661. }
  662. }
  663. Result = (DateTime >= NewCache.DaylightDate) &&
  664. (DateTime < NewCache.StandardDate);
  665. }
  666. }
  667. return Result;
  668. }
  669. //---------------------------------------------------------------------------
  670. TDateTime __fastcall UnixToDateTime(__int64 TimeStamp, bool ConsiderDST)
  671. {
  672. TDateTimeParams * Params = GetDateTimeParams();
  673. TDateTime Result;
  674. Result = Params->UnixEpoch + (double(TimeStamp) / 86400) - Params->CurrentDifference;
  675. if (ConsiderDST)
  676. {
  677. Result -= (IsDateInDST(Result) ?
  678. Params->DaylightDifference : Params->StandardDifference);
  679. }
  680. return Result;
  681. }
  682. //---------------------------------------------------------------------------
  683. inline __int64 __fastcall Round(double Number)
  684. {
  685. double Floor = floor(Number);
  686. double Ceil = ceil(Number);
  687. return ((Number - Floor) > (Ceil - Number)) ? Ceil : Floor;
  688. }
  689. //---------------------------------------------------------------------------
  690. #define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
  691. ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
  692. #define TIME_WIN_TO_POSIX(ft, t) ((t) = (__int64) \
  693. ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
  694. //---------------------------------------------------------------------------
  695. static __int64 __fastcall DateTimeToUnix(const TDateTime DateTime)
  696. {
  697. TDateTimeParams * Params = GetDateTimeParams();
  698. return Round(double(DateTime - Params->UnixEpoch) * 86400) +
  699. Params->CurrentDifferenceSec;
  700. }
  701. //---------------------------------------------------------------------------
  702. FILETIME __fastcall DateTimeToFileTime(const TDateTime DateTime,
  703. bool /*ConsiderDST*/)
  704. {
  705. FILETIME Result;
  706. __int64 UnixTimeStamp = DateTimeToUnix(DateTime);
  707. TIME_POSIX_TO_WIN(UnixTimeStamp, Result);
  708. return Result;
  709. }
  710. //---------------------------------------------------------------------------
  711. __int64 __fastcall ConvertTimestampToUnix(const FILETIME & FileTime,
  712. bool ConsiderDST)
  713. {
  714. __int64 Result;
  715. TIME_WIN_TO_POSIX(FileTime, Result);
  716. if (ConsiderDST)
  717. {
  718. FILETIME LocalFileTime;
  719. SYSTEMTIME SystemTime;
  720. TDateTime DateTime;
  721. FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
  722. FileTimeToSystemTime(&LocalFileTime, &SystemTime);
  723. DateTime = SystemTimeToDateTime(SystemTime);
  724. TDateTimeParams * Params = GetDateTimeParams();
  725. Result += (IsDateInDST(DateTime) ?
  726. Params->DaylightDifferenceSec : Params->StandardDifferenceSec);
  727. }
  728. return Result;
  729. }
  730. //---------------------------------------------------------------------------
  731. __int64 __fastcall ConvertTimestampToUnixSafe(const FILETIME & FileTime,
  732. bool ConsiderDST)
  733. {
  734. __int64 Result;
  735. if ((FileTime.dwLowDateTime == 0) &&
  736. (FileTime.dwHighDateTime == 0))
  737. {
  738. Result = DateTimeToUnix(Now());
  739. }
  740. else
  741. {
  742. Result = ConvertTimestampToUnix(FileTime, ConsiderDST);
  743. }
  744. return Result;
  745. }
  746. //---------------------------------------------------------------------------
  747. TDateTime __fastcall AdjustDateTimeFromUnix(TDateTime DateTime, bool ConsiderDST)
  748. {
  749. TDateTimeParams * Params = GetDateTimeParams();
  750. DateTime = DateTime - Params->CurrentDaylightDifference;
  751. bool IsInDST = IsDateInDST(DateTime);
  752. // shift always, even with ConsiderDST == false
  753. DateTime = DateTime - (!IsInDST ? Params->DaylightDifference :
  754. Params->StandardDifference);
  755. if (ConsiderDST)
  756. {
  757. if (IsInDST)
  758. {
  759. //DateTime = DateTime - Params->DaylightDifference;
  760. }
  761. else
  762. {
  763. DateTime = DateTime + Params->DaylightDifference;
  764. }
  765. }
  766. return DateTime;
  767. }
  768. //---------------------------------------------------------------------------
  769. __inline static bool __fastcall UnifySignificance(unsigned short & V1,
  770. unsigned short & V2)
  771. {
  772. bool Result = (V1 == 0) || (V2 == 0);
  773. if (Result)
  774. {
  775. V1 = 0;
  776. V2 = 0;
  777. }
  778. return Result;
  779. }
  780. //---------------------------------------------------------------------------
  781. void __fastcall UnifyDateTimePrecision(TDateTime & DateTime1, TDateTime & DateTime2)
  782. {
  783. unsigned short Y1, M1, D1, H1, N1, S1, MS1;
  784. unsigned short Y2, M2, D2, H2, N2, S2, MS2;
  785. bool Changed;
  786. if (DateTime1 != DateTime2)
  787. {
  788. DateTime1.DecodeDate(&Y1, &M1, &D1);
  789. DateTime1.DecodeTime(&H1, &N1, &S1, &MS1);
  790. DateTime2.DecodeDate(&Y2, &M2, &D2);
  791. DateTime2.DecodeTime(&H2, &N2, &S2, &MS2);
  792. Changed = UnifySignificance(MS1, MS2);
  793. if (Changed && UnifySignificance(S1, S2) && UnifySignificance(N1, N2) &&
  794. UnifySignificance(H1, H2) && UnifySignificance(D1, D2) &&
  795. UnifySignificance(M1, M2))
  796. {
  797. UnifySignificance(Y1, Y2);
  798. }
  799. if (Changed)
  800. {
  801. DateTime1 = EncodeDate(Y1, M1, D1) + EncodeTime(H1, N1, S1, MS1);
  802. DateTime2 = EncodeDate(Y2, M2, D2) + EncodeTime(H2, N2, S2, MS2);
  803. }
  804. }
  805. }
  806. //---------------------------------------------------------------------------
  807. AnsiString __fastcall FixedLenDateTimeFormat(const AnsiString & Format)
  808. {
  809. AnsiString Result = Format;
  810. bool AsIs = false;
  811. int Index = 1;
  812. while (Index <= Result.Length())
  813. {
  814. char F = Result[Index];
  815. if ((F == '\'') || (F == '\"'))
  816. {
  817. AsIs = !AsIs;
  818. Index++;
  819. }
  820. else if (!AsIs && ((F == 'a') || (F == 'A')))
  821. {
  822. if (Result.SubString(Index, 5).LowerCase() == "am/pm")
  823. {
  824. Index += 5;
  825. }
  826. else if (Result.SubString(Index, 3).LowerCase() == "a/p")
  827. {
  828. Index += 3;
  829. }
  830. else if (Result.SubString(Index, 4).LowerCase() == "ampm")
  831. {
  832. Index += 4;
  833. }
  834. else
  835. {
  836. Index++;
  837. }
  838. }
  839. else
  840. {
  841. if (!AsIs && (strchr("dDeEmMhHnNsS", F) != NULL) &&
  842. ((Index == Result.Length()) || (Result[Index + 1] != F)))
  843. {
  844. Result.Insert(F, Index);
  845. }
  846. while ((Index <= Result.Length()) && (F == Result[Index]))
  847. {
  848. Index++;
  849. }
  850. }
  851. }
  852. return Result;
  853. }
  854. //---------------------------------------------------------------------------
  855. int __fastcall CompareFileTime(TDateTime T1, TDateTime T2)
  856. {
  857. // "FAT" time precision
  858. // 1 ms more solves the rounding issues (see also CustomDirView.pas)
  859. static TDateTime Second(0, 0, 1, 1);
  860. int Result;
  861. if (T1 == T2)
  862. {
  863. // just optimalisation
  864. Result = 0;
  865. }
  866. else if ((T1 < T2) && (T2 - T1 > Second))
  867. {
  868. Result = -1;
  869. }
  870. else if ((T1 > T2) && (T1 - T2 > Second))
  871. {
  872. Result = 1;
  873. }
  874. else
  875. {
  876. Result = 0;
  877. }
  878. return Result;
  879. }
  880. //---------------------------------------------------------------------------
  881. bool __fastcall RecursiveDeleteFile(const AnsiString FileName, bool ToRecycleBin)
  882. {
  883. SHFILEOPSTRUCT Data;
  884. memset(&Data, 0, sizeof(Data));
  885. Data.hwnd = NULL;
  886. Data.wFunc = FO_DELETE;
  887. AnsiString FileList(FileName);
  888. FileList.SetLength(FileList.Length() + 2);
  889. FileList[FileList.Length() - 1] = '\0';
  890. FileList[FileList.Length()] = '\0';
  891. Data.pFrom = FileList.c_str();
  892. Data.pTo = "";
  893. Data.fFlags = FOF_NOCONFIRMATION | FOF_RENAMEONCOLLISION | FOF_NOCONFIRMMKDIR |
  894. FOF_NOERRORUI | FOF_SILENT;
  895. if (ToRecycleBin)
  896. {
  897. Data.fFlags |= FOF_ALLOWUNDO;
  898. }
  899. int Result = SHFileOperation(&Data);
  900. return (Result == 0);
  901. }
  902. //---------------------------------------------------------------------------
  903. int __fastcall CancelAnswer(int Answers)
  904. {
  905. int Result;
  906. if ((Answers & qaCancel) != 0)
  907. {
  908. Result = qaCancel;
  909. }
  910. else if ((Answers & qaNo) != 0)
  911. {
  912. Result = qaNo;
  913. }
  914. else if ((Answers & qaAbort) != 0)
  915. {
  916. Result = qaAbort;
  917. }
  918. else if ((Answers & qaOK) != 0)
  919. {
  920. Result = qaOK;
  921. }
  922. else
  923. {
  924. assert(false);
  925. Result = qaCancel;
  926. }
  927. return Result;
  928. }
  929. //---------------------------------------------------------------------------
  930. int __fastcall AbortAnswer(int Answers)
  931. {
  932. int Result;
  933. if (FLAGSET(Answers, qaAbort))
  934. {
  935. Result = qaAbort;
  936. }
  937. else
  938. {
  939. Result = CancelAnswer(Answers);
  940. }
  941. return Result;
  942. }
  943. //---------------------------------------------------------------------------
  944. int __fastcall ContinueAnswer(int Answers)
  945. {
  946. int Result;
  947. if (FLAGSET(Answers, qaSkip))
  948. {
  949. Result = qaSkip;
  950. }
  951. else if (FLAGSET(Answers, qaIgnore))
  952. {
  953. Result = qaIgnore;
  954. }
  955. else if (FLAGSET(Answers, qaYes))
  956. {
  957. Result = qaYes;
  958. }
  959. else if (FLAGSET(Answers, qaOK))
  960. {
  961. Result = qaOK;
  962. }
  963. else
  964. {
  965. assert(false);
  966. Result = CancelAnswer(Answers);
  967. }
  968. return Result;
  969. }
  970. //---------------------------------------------------------------------------
  971. TPasLibModule * __fastcall FindModule(void * Instance)
  972. {
  973. TPasLibModule * CurModule;
  974. CurModule = reinterpret_cast<TPasLibModule*>(LibModuleList);
  975. while (CurModule)
  976. {
  977. if (CurModule->Instance == Instance)
  978. {
  979. break;
  980. }
  981. else
  982. {
  983. CurModule = CurModule->Next;
  984. }
  985. }
  986. return CurModule;
  987. }
  988. //---------------------------------------------------------------------------
  989. AnsiString __fastcall LoadStr(int Ident, unsigned int MaxLength)
  990. {
  991. TPasLibModule * MainModule = FindModule(HInstance);
  992. assert(MainModule != NULL);
  993. AnsiString Result;
  994. Result.SetLength(MaxLength);
  995. int Length = LoadString(MainModule->ResInstance, Ident, Result.c_str(), MaxLength);
  996. Result.SetLength(Length);
  997. return Result;
  998. }
  999. //---------------------------------------------------------------------------
  1000. AnsiString __fastcall LoadStrPart(int Ident, int Part)
  1001. {
  1002. AnsiString Result;
  1003. AnsiString Str = LoadStr(Ident);
  1004. while (Part > 0)
  1005. {
  1006. Result = CutToChar(Str, '|', false);
  1007. Part--;
  1008. }
  1009. return Result;
  1010. }
  1011. //---------------------------------------------------------------------------
  1012. AnsiString __fastcall DecodeUrlChars(AnsiString S)
  1013. {
  1014. int i = 1;
  1015. while (i <= S.Length())
  1016. {
  1017. switch (S[i])
  1018. {
  1019. case '+':
  1020. S[i] = ' ';
  1021. break;
  1022. case '%':
  1023. if (i <= S.Length() - 2)
  1024. {
  1025. S[i] = HexToStr(S.SubString(i + 1, 2))[1];
  1026. S.Delete(i + 1, 2);
  1027. }
  1028. break;
  1029. }
  1030. i++;
  1031. }
  1032. return S;
  1033. }
  1034. //---------------------------------------------------------------------------
  1035. AnsiString __fastcall EncodeUrlChars(AnsiString S, AnsiString Ignore)
  1036. {
  1037. AnsiString Encode = "/ ";
  1038. int i = 1;
  1039. while (i <= S.Length())
  1040. {
  1041. if ((Encode.Pos(S[i]) > 0) &&
  1042. (Ignore.Pos(S[i]) == 0))
  1043. {
  1044. AnsiString H = CharToHex(S[i]);
  1045. S.Insert(H, i + 1);
  1046. S[i] = '%';
  1047. i += H.Length();
  1048. }
  1049. i++;
  1050. }
  1051. return S;
  1052. }
  1053. //---------------------------------------------------------------------------
  1054. void __fastcall OemToAnsi(AnsiString & Str)
  1055. {
  1056. if (!Str.IsEmpty())
  1057. {
  1058. Str.Unique();
  1059. OemToChar(Str.c_str(), Str.c_str());
  1060. }
  1061. }
  1062. //---------------------------------------------------------------------------
  1063. void __fastcall AnsiToOem(AnsiString & Str)
  1064. {
  1065. if (!Str.IsEmpty())
  1066. {
  1067. Str.Unique();
  1068. CharToOem(Str.c_str(), Str.c_str());
  1069. }
  1070. }
  1071. //---------------------------------------------------------------------------
  1072. struct TUnicodeEmitParams
  1073. {
  1074. WideString Buffer;
  1075. int Pos;
  1076. int Len;
  1077. };
  1078. //---------------------------------------------------------------------------
  1079. extern "C" void UnicodeEmit(void * AParams, long int Output)
  1080. {
  1081. if (Output == 0xFFFFL) // see Putty's charset\internal.h
  1082. {
  1083. throw Exception(LoadStr(DECODE_UTF_ERROR));
  1084. }
  1085. TUnicodeEmitParams * Params = (TUnicodeEmitParams *)AParams;
  1086. if (Params->Pos >= Params->Len)
  1087. {
  1088. Params->Len += 50;
  1089. Params->Buffer.SetLength(Params->Len);
  1090. }
  1091. Params->Pos++;
  1092. Params->Buffer[Params->Pos] = (wchar_t)Output;
  1093. }
  1094. //---------------------------------------------------------------------------
  1095. AnsiString __fastcall DecodeUTF(const AnsiString UTF)
  1096. {
  1097. charset_state State;
  1098. char * Str;
  1099. TUnicodeEmitParams Params;
  1100. AnsiString Result;
  1101. State.s0 = 0;
  1102. Str = UTF.c_str();
  1103. Params.Pos = 0;
  1104. Params.Len = UTF.Length();
  1105. Params.Buffer.SetLength(Params.Len);
  1106. while (*Str)
  1107. {
  1108. read_utf8(NULL, (unsigned char)*Str, &State, UnicodeEmit, &Params);
  1109. Str++;
  1110. }
  1111. Params.Buffer.SetLength(Params.Pos);
  1112. return Params.Buffer;
  1113. }
  1114. //---------------------------------------------------------------------------
  1115. struct TUnicodeEmitParams2
  1116. {
  1117. AnsiString Buffer;
  1118. int Pos;
  1119. int Len;
  1120. };
  1121. //---------------------------------------------------------------------------
  1122. extern "C" void UnicodeEmit2(void * AParams, long int Output)
  1123. {
  1124. if (Output == 0xFFFFL) // see Putty's charset\internal.h
  1125. {
  1126. throw Exception(LoadStr(DECODE_UTF_ERROR));
  1127. }
  1128. TUnicodeEmitParams2 * Params = (TUnicodeEmitParams2 *)AParams;
  1129. if (Params->Pos >= Params->Len)
  1130. {
  1131. Params->Len += 50;
  1132. Params->Buffer.SetLength(Params->Len);
  1133. }
  1134. Params->Pos++;
  1135. Params->Buffer[Params->Pos] = (unsigned char)Output;
  1136. }
  1137. //---------------------------------------------------------------------------
  1138. AnsiString __fastcall EncodeUTF(const WideString Source)
  1139. {
  1140. // WideString::c_bstr() returns NULL for empty strings
  1141. // (as opposite to AnsiString::c_str() which returns "")
  1142. if (Source.IsEmpty())
  1143. {
  1144. return "";
  1145. }
  1146. else
  1147. {
  1148. charset_state State;
  1149. wchar_t * Str;
  1150. TUnicodeEmitParams2 Params;
  1151. AnsiString Result;
  1152. State.s0 = 0;
  1153. Str = Source.c_bstr();
  1154. Params.Pos = 0;
  1155. Params.Len = Source.Length();
  1156. Params.Buffer.SetLength(Params.Len);
  1157. while (*Str)
  1158. {
  1159. write_utf8(NULL, (wchar_t)*Str, &State, UnicodeEmit2, &Params);
  1160. Str++;
  1161. }
  1162. Params.Buffer.SetLength(Params.Pos);
  1163. return Params.Buffer;
  1164. }
  1165. }