Rev 4 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | daniel-mar | 1 | unit Functions; |
2 | |||
3 | interface |
||
4 | |||
5 | uses |
||
6 | Windows, Messages, SysUtils, StrUtils, IniFiles, Classes, Forms, Variants, MsHTML, |
||
7 | SHDocVw, StdCtrls; |
||
8 | |||
9 | function GetDosOutput(CommandLine: string; Work: string = ''): string; |
||
10 | function StrIPos(const SubStr, S: string): Integer; |
||
11 | procedure WaitForBrowser(WB: TWebbrowser); |
||
12 | function LoadFileToStr(const FileName: TFileName): AnsiString; |
||
13 | function LastPos(const SubStr, S: string): integer; |
||
14 | function ParseCHM(chmFile: string): boolean; |
||
15 | procedure BrowseURL(WebBrowser1: TWebBrowser; url: string); |
||
16 | procedure BrowseContent(WebBrowser1: TWebBrowser; html: string); |
||
17 | function IsTextHTML(s: string): boolean; |
||
18 | function GetWordUnderCaret(AMemo: TMemo): string; |
||
19 | function IsValidPHPExe(const exeFile: string): boolean; |
||
20 | |||
21 | implementation |
||
22 | |||
23 | function GetDosOutput(CommandLine: string; Work: string = ''): string; |
||
24 | var |
||
25 | SA: TSecurityAttributes; |
||
26 | SI: TStartupInfo; |
||
27 | PI: TProcessInformation; |
||
28 | StdOutPipeRead, StdOutPipeWrite: THandle; |
||
29 | WasOK: Boolean; |
||
30 | Buffer: array[0..255] of AnsiChar; |
||
31 | BytesRead: Cardinal; |
||
32 | WorkDir: string; |
||
33 | Handle: Boolean; |
||
34 | begin |
||
35 | if Work = '' then Work := ExtractFilePath(ParamStr(0)); |
||
36 | |||
37 | Result := ''; |
||
38 | with SA do begin |
||
39 | nLength := SizeOf(SA); |
||
40 | bInheritHandle := True; |
||
41 | lpSecurityDescriptor := nil; |
||
42 | end; |
||
43 | CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0); |
||
44 | try |
||
45 | with SI do |
||
46 | begin |
||
47 | FillChar(SI, SizeOf(SI), 0); |
||
48 | cb := SizeOf(SI); |
||
49 | dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; |
||
50 | wShowWindow := SW_HIDE; |
||
51 | hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin |
||
52 | hStdOutput := StdOutPipeWrite; |
||
53 | hStdError := StdOutPipeWrite; |
||
54 | end; |
||
55 | WorkDir := Work; |
||
56 | Handle := CreateProcess(nil, PChar('cmd.exe /C "' + CommandLine + '"'), |
||
57 | nil, nil, True, 0, nil, |
||
58 | PChar(WorkDir), SI, PI); |
||
59 | CloseHandle(StdOutPipeWrite); |
||
60 | if Handle then |
||
61 | try |
||
62 | repeat |
||
63 | WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil); |
||
64 | if BytesRead > 0 then |
||
65 | begin |
||
66 | Buffer[BytesRead] := #0; |
||
67 | Result := Result + Buffer; |
||
68 | end; |
||
69 | until not WasOK or (BytesRead = 0); |
||
70 | WaitForSingleObject(PI.hProcess, INFINITE); |
||
71 | finally |
||
72 | CloseHandle(PI.hThread); |
||
73 | CloseHandle(PI.hProcess); |
||
74 | end; |
||
75 | finally |
||
76 | CloseHandle(StdOutPipeRead); |
||
77 | end; |
||
78 | end; |
||
79 | |||
80 | function StrIPos(const SubStr, S: string): Integer; |
||
81 | begin |
||
82 | Result := Pos(UpperCase(SubStr), UpperCase(S)); |
||
83 | end; |
||
84 | |||
85 | procedure WaitForBrowser(WB: TWebbrowser); |
||
86 | begin |
||
87 | while (WB.Busy) |
||
88 | and not (Application.Terminated) do |
||
89 | begin |
||
90 | Application.ProcessMessages; |
||
91 | Sleep(100); |
||
92 | end; |
||
93 | end; |
||
94 | |||
95 | function LoadFileToStr(const FileName: TFileName): AnsiString; |
||
96 | var |
||
97 | FileStream : TFileStream; |
||
98 | |||
99 | begin |
||
100 | Result:= ''; |
||
101 | FileStream:= TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); |
||
102 | try |
||
103 | if FileStream.Size>0 then begin |
||
104 | SetLength(Result, FileStream.Size); |
||
105 | FileStream.Read(Result[1], FileStream.Size); |
||
106 | end; |
||
107 | finally |
||
108 | FileStream.Free; |
||
109 | end; |
||
110 | end; |
||
111 | |||
112 | function LastPos(const SubStr, S: string): integer; |
||
113 | var |
||
114 | I, J, K: integer; |
||
115 | begin |
||
116 | Result := 0; |
||
117 | I := Length(S); |
||
118 | K := Length(SubStr); |
||
119 | if (K = 0) or (K > I) then |
||
120 | Exit; |
||
121 | while (Result = 0) and (I >= K) do |
||
122 | begin |
||
123 | J := K; |
||
124 | if S[I] = SubStr[J] then |
||
125 | begin |
||
126 | while (J > 1) and (S[I + J - K - 1] = SubStr[J - 1]) do |
||
127 | Dec(J); |
||
128 | if J = 1 then |
||
129 | Result := I - K + 1; |
||
130 | end; |
||
131 | Dec(I); |
||
132 | end; |
||
133 | end; |
||
134 | |||
135 | function ParseCHM(chmFile: string): boolean; |
||
136 | var |
||
137 | test, candidate, candidate2: string; |
||
138 | p, p2, q: integer; |
||
139 | i: integer; |
||
140 | good: Boolean; |
||
141 | ini: TMemIniFile; |
||
142 | domain: string; |
||
143 | sl: TStringList; |
||
144 | symbolCount: Integer; |
||
145 | sl2: TStrings; |
||
146 | outFile: string; |
||
147 | begin |
||
148 | // TODO: problem: mysqli::commit has /res/mysqli.commit.html -> keyword is NOT commit alone |
||
149 | |||
150 | outFile := ChangeFileExt(chmFile, '.ini'); |
||
151 | DeleteFile(outFile); |
||
152 | test := LoadFileToStr(chmFile); |
||
153 | if Pos('/php_manual_', test) = -1 then |
||
154 | begin |
||
155 | result := false; |
||
156 | exit; |
||
157 | end; |
||
158 | p := 0; |
||
159 | ini := TMemIniFile.Create(outFile); |
||
160 | try |
||
161 | ini.WriteString('_Info_', 'Source', chmFile); |
||
162 | ini.WriteString('_Info_', 'Generated', DateTimeToStr(Now)); |
||
163 | ini.WriteString('_Info_', 'GeneratorVer', '1.0'); |
||
164 | ini.WriteString('_Info_', 'Signature', '$ViaThinkSoft$'); |
||
165 | {$REGION 'Excludes'} |
||
166 | // TODO: more excludes |
||
167 | ini.WriteBool('_HelpExclude_', 'about', true); |
||
168 | ini.WriteBool('_HelpExclude_', 'apache', true); |
||
169 | {$ENDREGION} |
||
170 | while true do |
||
171 | begin |
||
172 | Application.ProcessMessages; |
||
173 | |||
174 | p := PosEx('/res/', Test, p+1); |
||
175 | if p = 0 then break; |
||
176 | p2 := PosEx('.html', Test, p); |
||
177 | if p = 0 then break; |
||
178 | candidate := copy(Test, p+5, p2-p-5); |
||
179 | if candidate = '' then continue; |
||
180 | if Length(candidate) > 50 then continue; |
||
181 | good := true; |
||
182 | for i := p+5 to p2-1 do |
||
183 | begin |
||
184 | if ord(test[i]) < 32 then |
||
185 | begin |
||
186 | good := false; |
||
187 | break; |
||
188 | end; |
||
189 | if not (test[i] in ['a'..'z', 'A'..'Z', '.', '-', '_', '0'..'9']) then |
||
190 | begin |
||
191 | ini.WriteInteger('_Errors_', 'Contains unexpected character! ' + candidate, ini.ReadInteger('_Errors_', 'Contains unexpected character! ' + candidate, 0)+1); |
||
192 | good := false; |
||
193 | break; |
||
194 | end; |
||
195 | end; |
||
196 | if good then |
||
197 | begin |
||
198 | candidate2 := LowerCase(StringReplace(candidate, '-', '_', [rfReplaceAll])); |
||
199 | q := LastPos('.', candidate2); |
||
200 | domain := copy(candidate2, 1, q-1); |
||
201 | if domain = '' then continue; |
||
202 | candidate2 := copy(candidate2, q+1, Length(candidate2)-q); |
||
203 | ini.WriteInteger('_Category_', domain, ini.ReadInteger('_Category_', domain, 0)+1); |
||
204 | ini.WriteString(domain, candidate2, '/res/'+candidate+'.html'); |
||
205 | if not ini.ReadBool('_HelpExclude_', domain, false) |
||
206 | and (candidate2 <> 'configuration') |
||
207 | and (candidate2 <> 'constants') |
||
208 | and (candidate2 <> 'installation') |
||
209 | and (candidate2 <> 'requirements') |
||
210 | and (candidate2 <> 'resources') |
||
211 | and (candidate2 <> 'setup') then |
||
212 | begin |
||
213 | if ini.ReadString('_HelpWords_', candidate2, '') <> '' then |
||
214 | begin |
||
215 | ini.WriteInteger('_Conflicts_', candidate2, ini.ReadInteger('_Conflicts_', candidate2, 0)+1); |
||
216 | end; |
||
217 | |||
218 | ini.WriteString('_HelpWords_', candidate2, '/res/'+candidate+'.html'); |
||
219 | end; |
||
220 | end; |
||
221 | end; |
||
222 | |||
223 | sl := TStringList.Create; |
||
224 | sl2 := TStringList.Create; |
||
225 | try |
||
226 | ini.ReadSections(sl); |
||
227 | ini.WriteInteger('_Info_', 'TotalDomains', sl.Count); |
||
228 | symbolCount := 0; |
||
229 | for domain in sl do |
||
230 | begin |
||
231 | ini.ReadSection(domain, sl2); |
||
232 | Inc(symbolCount, sl2.Count) |
||
233 | end; |
||
234 | ini.WriteInteger('_Info_', 'TotalSymbols', symbolCount); |
||
235 | finally |
||
236 | sl.Free; |
||
237 | sl2.Free; |
||
238 | end; |
||
239 | |||
240 | ini.UpdateFile; |
||
241 | result := true; |
||
242 | finally |
||
243 | ini.Free; |
||
244 | end; |
||
245 | end; |
||
246 | |||
247 | procedure BrowseURL(WebBrowser1: TWebBrowser; url: string); |
||
248 | var |
||
249 | BrowserFlags : olevariant; |
||
250 | MyTargetFrameName : olevariant; |
||
251 | MyPostaData : olevariant; |
||
252 | MyHeaders : olevariant; |
||
253 | begin |
||
254 | { Flags: |
||
255 | Constant Value Meaning |
||
256 | NavOpenInNewWindow $01 Open the resource or file in a new window. |
||
257 | NavNoHistory $02 Do not add the resource or file to the history list. The new page replaces the current page in the list. |
||
258 | NavNoReadFromCache $04 Do not read from the disk cache for this navigation. |
||
259 | NavNoWriteToCache $08 Do not write the results of this navigation to the disk cache. |
||
260 | NavAllowAutosearch $10 If the navigation fails, the Web browser attempts to navigate common root domains (.com, .org, and so on). If this still fails, the URL is passed to a search engine. |
||
261 | } |
||
262 | BrowserFlags := $02; |
||
263 | MyTargetFrameName := null; |
||
264 | MyPostaData := null; |
||
265 | MyHeaders := null; |
||
266 | WebBrowser1.Silent := true; // no JavaScript errors |
||
267 | Webbrowser1.Navigate(url, BrowserFlags,MyTargetFrameName,MyPostaData,MyHeaders); |
||
268 | WaitForBrowser(WebBrowser1); |
||
269 | end; |
||
270 | |||
271 | procedure BrowseContent(WebBrowser1: TWebBrowser; html: string); |
||
272 | var |
||
273 | BrowserFlags : olevariant; |
||
274 | MyTargetFrameName : olevariant; |
||
275 | MyPostaData : olevariant; |
||
276 | MyHeaders : olevariant; |
||
277 | Doc: Variant; |
||
278 | begin |
||
279 | { Flags: |
||
280 | Constant Value Meaning |
||
281 | NavOpenInNewWindow $01 Open the resource or file in a new window. |
||
282 | NavNoHistory $02 Do not add the resource or file to the history list. The new page replaces the current page in the list. |
||
283 | NavNoReadFromCache $04 Do not read from the disk cache for this navigation. |
||
284 | NavNoWriteToCache $08 Do not write the results of this navigation to the disk cache. |
||
285 | NavAllowAutosearch $10 If the navigation fails, the Web browser attempts to navigate common root domains (.com, .org, and so on). If this still fails, the URL is passed to a search engine. |
||
286 | } |
||
287 | if WebBrowser1.Document = nil then |
||
288 | begin |
||
289 | BrowserFlags := $02 + $04 + $08 + $10; |
||
290 | MyTargetFrameName := null; |
||
291 | MyPostaData := null; |
||
292 | MyHeaders := null; |
||
293 | Webbrowser1.Navigate('about:blank', BrowserFlags,MyTargetFrameName,MyPostaData,MyHeaders); |
||
294 | WaitForBrowser(WebBrowser1); |
||
295 | end; |
||
296 | |||
297 | Doc := WebBrowser1.Document; |
||
298 | Doc.Clear; |
||
299 | Doc.Write(html); |
||
300 | Doc.Close; |
||
301 | WaitForBrowser(WebBrowser1); |
||
302 | end; |
||
303 | |||
304 | function IsTextHTML(s: string): boolean; |
||
305 | |||
306 | function _Tag(const tag: string): integer; |
||
307 | begin |
||
308 | result := 0; |
||
309 | if (StrIPos('<'+tag+'>', s) > 0) then Inc(result); |
||
310 | if (StrIPos('</'+tag+'>', s) > 0) then Inc(result); |
||
311 | if (StrIPos('<'+tag+' />', s) > 0) then Inc(result); |
||
312 | if (StrIPos('<'+tag+' ', s) > 0) then Inc(result); |
||
313 | end; |
||
314 | |||
315 | var |
||
316 | score: integer; |
||
317 | begin |
||
318 | score := _Tag('html') + _Tag('body') + _Tag('p') + _Tag('a') + _Tag('b') + |
||
319 | _Tag('i') + _Tag('u') + _Tag('li') + _Tag('ol') + _Tag('ul') + |
||
320 | _Tag('img') + _Tag('div') + _Tag('hr') + _Tag('code') + |
||
321 | _Tag('pre') + _Tag('blockquote') + _Tag('span'); |
||
322 | result := score >= 2; |
||
323 | end; |
||
324 | |||
325 | // Template: http://stackoverflow.com/questions/6339446/delphi-get-the-whole-word-where-the-caret-is-in-a-memo |
||
326 | function GetWordUnderCaret(AMemo: TMemo): string; |
||
327 | |||
328 | function ValidChar(c: char): boolean; |
||
329 | begin |
||
330 | result := c in ['a'..'z', 'A'..'Z', '0'..'9', '_']; |
||
331 | end; |
||
332 | |||
333 | var |
||
334 | Line : Integer; |
||
335 | Column : Integer; |
||
336 | LineText: string; |
||
337 | InitPos : Integer; |
||
338 | EndPos : Integer; |
||
339 | begin |
||
340 | //Get the caret position |
||
341 | Line := AMemo.Perform(EM_LINEFROMCHAR,AMemo.SelStart, 0) ; |
||
342 | Column := AMemo.SelStart - AMemo.Perform(EM_LINEINDEX, Line, 0) ; |
||
343 | //Validate the line number |
||
344 | if AMemo.Lines.Count-1 < Line then Exit; |
||
345 | |||
346 | //Get the text of the line |
||
347 | LineText := AMemo.Lines[Line]; |
||
348 | |||
349 | // Column zeigt auf das Zeichen LINKS vom Cursor! |
||
350 | |||
351 | InitPos := Column; |
||
352 | if not ValidChar(LineText[InitPos]) then Inc(InitPos); |
||
353 | while (InitPos-1 >= 1) and ValidChar(LineText[InitPos-1]) do Dec(InitPos); |
||
354 | |||
355 | EndPos := Column; |
||
356 | while (EndPos+1 <= Length(LineText)) and ValidChar(LineText[EndPos+1]) do Inc(EndPos); |
||
357 | |||
358 | //Get the text |
||
359 | Result := Copy(LineText, InitPos, EndPos - InitPos + 1); |
||
360 | end; |
||
361 | |||
362 | function IsValidPHPExe(const exeFile: string): boolean; |
||
363 | var |
||
364 | cont: string; |
||
365 | begin |
||
366 | cont := LoadFileToStr(exeFile); |
||
367 | result := (Pos('php://stdout', cont) >= 0) or |
||
368 | (Pos('PHP_SELF', cont) >= 0); |
||
369 | end; |
||
370 | |||
371 | end. |