OSDN Git Service

・板一覧更新の処理メッセージを追加
[gikonavigoeson/gikonavi.git] / HTMLCreate.pas
1 unit HTMLCreate;
2
3 interface
4
5 uses
6         Windows, Messages, SysUtils, Classes, {Graphics,} Controls, {Forms,}
7         ComCtrls, IniFiles, ShellAPI, Math, GikoSystem,
8 {$IF Defined(DELPRO) }
9         SHDocVw,
10         MSHTML,
11 {$ELSE}
12         SHDocVw_TLB,
13         MSHTML_TLB,
14 {$IFEND}
15         {HttpApp,} YofUtils, {URLMon,} BoardGroup, {gzip,} {Dolib,}
16         {bmRegExp,} AbonUnit,   MojuUtils, Setting,
17         ExternalBoardManager, ExternalBoardPlugInMain{,}
18         {Sort,} ,GikoBayesian, {HintWindow,} ActiveX, ResPopupBrowser;
19
20 type
21
22         PResLinkRec = ^TResLinkRec;
23         TResLinkRec = record
24                 FBbs: string;
25                 FKey : string;
26         end;
27
28         TBufferedWebBrowser = class(TStringList)
29         private
30                 //! \8f\91\82«\8d\9e\82Þ\83u\83\89\83E\83U
31                 FBrowser: TWebBrowser;
32                 //! \89½\8ds\82Ü\82Å\82½\82ß\82é\82©\82Ì\83T\83C\83Y
33                 FBuffSize: Integer;
34                 //! \83u\83\89\83E\83U\82ÌIHTMLDocument2\83C\83\93\83^\83t\83F\81[\83X\82ð\95Û\8e\9d\82·\82é open\82©\82çclose\82Ì\8aÔ\82Å
35                 FBrowserDoc: OleVariant;
36         public
37                 constructor Create(Browser: TWebBrowser; BuffSize: Integer);
38                 destructor Destory;
39                 procedure Open;
40                 procedure Close;
41                 procedure Flush;
42                 function Add(const S: string): Integer; override;
43         end;
44         THTMLCreate = class(TObject)
45         private
46                 { Private \90é\8c¾ }
47                 anchorLen                       : Integer;
48                 pURLCHARs,pURLCHARe : PChar;
49                 pANCHORs, pANCHORe  : PChar;
50                 pCTAGLs,  pCTAGLe   : PChar;
51                 pCTAGUs,  pCTAGUe   : PChar;
52                 pREF_MARKSs : array[0..11] of PChar;
53                 pREF_MARKSe : array[0..11] of PChar;
54                 constructor Create;
55
56                 function AddBeProfileLink(AID : string; ANum: Integer):string ;
57                 procedure CreateUsePluginHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; var sTitle: string);
58                 procedure CreateUseSKINHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList);
59                 procedure CreateUseCSSHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList; sTitle: string );
60                 procedure CreateDefaultHTML (html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList; sTitle: string );
61                 procedure ConvertResAnchor(PRes: PResRec);
62                 procedure separateNumber(var st: String; var et: String; const Text, Separator: String);
63                 function checkComma(const s : String; var j : Integer) : boolean;
64                 function addResAnchor(PAddRes: PResRec; PResLink : PResLinkRec; dat : boolean;
65                  var s : String; j : Integer; const No: String) : string;
66         function appendResAnchor(PAddRes: PResRec; PResLink : PResLinkRec;
67              dat : boolean;     var s : String) : string;
68         function getNumberString(const str: String;var index :Integer; var dbCharlen: Boolean;
69              sLen :Integer): String;
70         function isOutsideRange(item: TThreadItem; index: Integer ): Boolean;
71         function getKeywordLink(item: TThreadItem): String;
72         function GetResString(index: Integer; const Line: String; PResLink : PResLinkRec): String;
73         function IsImageExp(const Url: String): Boolean;
74         public
75                 { Public \90é\8c¾ }
76                 procedure AddAnchorTag(PRes: PResRec);
77                 function LoadFromSkin(fileName: string; ThreadItem: TThreadItem; SizeByte: Integer): string;
78                 function SkinedRes(const skin: string; PRes: PResRec; const No: string): string;
79                 procedure ConvRes( PRes : PResRec; PResLink : PResLinkRec; DatToHTML: boolean = false); overload;
80                 procedure CreateHTML2(Browser: TWebBrowser; ThreadItem: TThreadItem; var sTitle: string);
81                 procedure CreateHTML3(var html: TStringList; ThreadItem: TThreadItem; var sTitle: string);
82                 //\83\8c\83X\83|\83b\83v\83A\83b\83v\82Ì\8dì\90¬
83                 procedure SetResPopupText(Hint :TResPopupBrowser; threadItem: TThreadItem; StNum, ToNum: Integer; Title, First: Boolean);
84                 //\83\8a\83\93\83N\82Ì\95\8e\9a\97ñ\82©\82ç\83\8c\83X\83|\83b\83v\83A\83b\83v\97p\82ÌURL\82É\95Ï\8a·\82·\82é
85                 class function GetRespopupURL(AText, AThreadURL : string): string;
86                 //\8ew\92è\82µ\82½\83p\83X\82É\83X\83L\83\93\82à\82µ\82­\82ÍCSS\82Ì\83t\83@\83C\83\8b\82Ì\83R\83s\81[\82ð\8dì\82é
87                 class procedure SkinorCSSFilesCopy(path: string);
88                 //dat\82P\8ds\82ð\83\8c\83X\82É\95ª\89ð\82·\82é
89                 class procedure DivideStrLine(Line: string; PRes: PResRec);
90         //HTML\82©\82ç\83\8a\83\93\83N\83^\83O\82ð\8dí\8f\9c\82·\82é
91                 class function DeleteLink(const s: string): string;
92         //HTML\82Ì\83{\83f\83B\82É\8b\96\82³\82ê\82é\95\8e\9a\97ñ\82É\92u\8a·\82·\82é
93         class function RepHtml(const s: string): string;
94         //\83\8c\83X\83G\83f\83B\83^\82Ì\83v\83\8c\83r\83\85\81[\97pHTML\82ð\8dì\90¬\82·\82é
95         class function CreatePreviewHTML(const Title: string; const No: string;
96                 const Mail: string; const Namae: string; const Body: string ) : string;
97         end;
98
99 var
100         HTMLCreater: THTMLCreate;
101
102 implementation
103
104 uses
105     Trip, AbonInfo;
106
107 const
108         URL_CHAR: string = '0123456789'
109                                                                          + 'abcdefghijklmnopqrstuvwxyz'
110                                                                          + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
111                                                                          + '#$%&()*+,-./:;=?@[]^_`{|}~!''\';
112         ANCHOR_REF      = 'href=';
113         CLOSE_TAGAL = '</a>';
114         CLOSE_TAGAU = '</A>';
115         RES_REF                 = '&gt;&gt;';
116         REF_MARK: array[0..11] of string = ('sssp://', 'http://', 'ttp://', 'tp://',
117                                                                          'ms-help://','p://', 'https://', 'ttps://',
118                                                                          'www.', 'ftp://','news://','rtsp://');
119
120 constructor THTMLCreate.Create;
121 var
122         j : Integer;
123 begin
124         // + 3 \82Í 'href="' ('"'\82Â\82«)\82È\82Ç\82Ì\83o\83\8a\83G\81[\83V\83\87\83\93\82É\97]\97T\82ð\8e\9d\82½\82¹\82é\82½\82ß
125         anchorLen := Length( ANCHOR_REF ) + 3;
126         pANCHORs  := PChar(ANCHOR_REF);
127         pANCHORe  := pANCHORs + Length(ANCHOR_REF);
128         pURLCHARs := PChar(URL_CHAR);
129         pURLCHARe := pURLCHARs + Length(URL_CHAR);
130         pCTAGLs   := PChar(CLOSE_TAGAL);
131         pCTAGLe   := pCTAGLs + 4;
132         pCTAGUs   := PChar(CLOSE_TAGAU);
133         pCTAGUe   := pCTAGUs + 4;
134         for j := 0 to 11 do begin
135                 pREF_MARKSs[j] := PChar(REF_MARK[j]);
136                 pREF_MARKSe[j] := pREF_MARKSs[j] + Length(REF_MARK[j]);
137         end;
138 end;
139 // \83X\83L\83\93\82ð\93Ç\82Ý\8d\9e\82Ý\81A\92l\82ð\92u\8a·\82·\82é
140 function THTMLCreate.LoadFromSkin(
141         fileName: string;
142         ThreadItem: TThreadItem;
143         SizeByte: Integer
144 ): string;
145 var
146         Skin: TStringList;
147 begin
148
149         Skin := TStringList.Create;
150         try
151                 if FileExists( fileName ) then begin
152                         Skin.LoadFromFile( fileName );
153
154                         // \82â\82è\82©\82½\82ª\8bê\82µ\82¢\82¯\82Ç\81A\83I\83v\83V\83\87\83\93\83_\83C\83A\83\8d\83O\82Ì\83v\83\8c\83r\83\85\81[\97p try
155                         try
156                                 if ThreadItem.ParentBoard <> nil then
157                                         if ThreadItem.ParentBoard.ParentCategory <> nil then
158                                                 CustomStringReplace( Skin, '<BBSNAME/>', ThreadItem.ParentBoard.ParentCategory.ParenTBBS.Title);
159                                         CustomStringReplace( Skin, '<THREADURL/>', ThreadItem.URL);
160                         except end;
161                         CustomStringReplace( Skin, '<BOARDNAME/>', ThreadItem.ParentBoard.Title);
162                         CustomStringReplace( Skin, '<BOARDURL/>', ThreadItem.ParentBoard.URL);
163                         CustomStringReplace( Skin, '<THREADNAME/>', ThreadItem.Title);
164                         CustomStringReplace( Skin, '<SKINPATH/>', GikoSys.Setting.CSSFileName);
165                         CustomStringReplace( Skin, '<GETRESCOUNT/>', IntToStr( ThreadItem.Count - ThreadItem.NewResCount ));
166                         CustomStringReplace( Skin, '<NEWRESCOUNT/>', IntToStr( ThreadItem.NewResCount ));
167                         CustomStringReplace( Skin, '<ALLRESCOUNT/>', IntToStr( ThreadItem.Count ));
168
169                         CustomStringReplace( Skin, '<NEWDATE/>',FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate));
170                         CustomStringReplace( Skin, '<SIZEKB/>', IntToStr( Floor( SizeByte / 1024 ) ));
171                         CustomStringReplace( Skin, '<SIZE/>', IntToStr( SizeByte ));
172
173                         //----- \82Æ\82è\82 \82¦\82¸\82©\82¿\82ã\81`\82µ\82á\8cÝ\8a·\97p\81B\83R\83\81\83\93\83g\83A\83E\83g\82µ\82Ä\82à\82æ\82µ
174                         // \82â\82è\82©\82½\82ª\8bê\82µ\82¢\82¯\82Ç\81A\83I\83v\83V\83\87\83\93\83_\83C\83A\83\8d\83O\82Ì\83v\83\8c\83r\83\85\81[\97p try
175                         if GikoSys.Setting.UseKatjushaType then begin
176                                 try
177                                         if ThreadItem.ParentBoard <> nil then
178                                                 if ThreadItem.ParentBoard.ParentCategory <> nil then
179                                                         CustomStringReplace( Skin, '&BBSNAME', ThreadItem.ParentBoard.ParentCategory.ParenTBBS.Title);
180                                                 CustomStringReplace( Skin, '&THREADURL', ThreadItem.URL);
181                                 except end;
182                                 CustomStringReplace( Skin, '&BOARDNAME', ThreadItem.ParentBoard.Title);
183                                 CustomStringReplace( Skin, '&BOARDURL', ThreadItem.ParentBoard.URL);
184                                 CustomStringReplace( Skin, '&THREADNAME', ThreadItem.Title);
185                                 CustomStringReplace( Skin, '&SKINPATH', GikoSys.Setting.CSSFileName);
186                                 CustomStringReplace( Skin, '&GETRESCOUNT', IntToStr( ThreadItem.NewReceive - 1 ));
187                                 CustomStringReplace( Skin, '&NEWRESCOUNT', IntToStr( ThreadItem.NewResCount ));
188                                 CustomStringReplace( Skin, '&ALLRESCOUNT', IntToStr( ThreadItem.AllResCount ));
189
190                                 CustomStringReplace( Skin, '&NEWDATE', FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate));
191                                 CustomStringReplace( Skin, '&SIZEKB', IntToStr( Floor( SizeByte / 1024 ) ));
192                                 CustomStringReplace( Skin, '&SIZE', IntToStr( SizeByte ));
193                         end
194                         //----- \82±\82±\82Ü\82Å
195                 end;
196                 Result := Skin.Text;
197         finally
198                 Skin.Free;
199         end;
200 end;
201
202 // \83\8c\83X\82Ì\92l\82ð\92u\8a·\82·\82é
203 function THTMLCreate.SkinedRes(
204         const skin: string;
205         PRes: PResRec;
206         const No: string
207 ): string;
208 const
209         FORMT_NAME = '<b>%s</b>';
210         FORMT_NUM  = '<a href="menu:%s" name="%s">%s</a>';
211         FORMT_MAILNAME  = '<a href="mailto:%s"><b>%s</b></a>';
212 var
213         spamminess      : Extended;
214 {$IFDEF SPAM_FILTER_ENABLED}
215         wordCount               : TWordCount;
216 {$ENDIF}
217 begin
218 {$IFDEF SPAM_FILTER_ENABLED}
219         wordCount := TWordCount.Create;
220         try
221                 spamminess := Floor( GikoSys.SpamParse(
222                         Res.FName + '<>' + Res.FMailTo + '<>' + Res.FBody, wordCount ) * 100 );
223 {$ELSE}
224         spamminess := 0;
225 {$ENDIF}
226                 Result := CustomStringReplace( skin, '<SPAMMINESS/>', FloatToStr( spamminess ) );
227                 Result := CustomStringReplace( Result, '<NONSPAMMINESS/>', FloatToStr( 100 - spamminess ) );
228                 Result := CustomStringReplace( Result, '<MAIL/>', PRes.FMailTo);
229                 Result := CustomStringReplace( Result, '<DATE/>', PRes.FDateTime);
230                 Result := CustomStringReplace( Result, '<PLAINNUMBER/>', No);
231                 Result := CustomStringReplace( Result, '<NAME/>',
232                         Format(FORMT_NAME, [PRes.FName]));
233                 Result := CustomStringReplace( Result, '<NUMBER/>',
234                         Format(FORMT_NUM, [No, No, No]));
235                 Result := CustomStringReplace( Result, '<MAILNAME/>',
236                         Format(FORMT_MAILNAME,[PRes.FMailTo, PRes.FName]));
237                 Result := CustomStringReplace( Result, '<MESSAGE/>', PRes.FBody);
238
239                 //----- \82©\82¿\82ã\81`\82µ\82á\8cÝ\8a·\97p\81B\83R\83\81\83\93\83g\83A\83E\83g\82µ\82Ä\82à\82æ\82µ
240                 if GikoSys.Setting.UseKatjushaType then begin
241                         Result := CustomStringReplace( Result, '&NUMBER',
242                                 '<a href="menu:' + No + '" name="' + No + '">' + No + '</a>');
243                         Result := CustomStringReplace( Result, '&PLAINNUMBER', No);
244                         Result := CustomStringReplace( Result, '&NAME', '<b>' + PRes.FName + '</b>');
245                         Result := CustomStringReplace( Result, '&MAILNAME',
246                                 '<a href="mailto:' + PRes.FMailTo + '"><b>' + PRes.FName + '</b></a>');
247                         Result := CustomStringReplace( Result, '&MAIL', PRes.FMailTo);
248                         Result := CustomStringReplace( Result, '&DATE', PRes.FDateTime);
249                         Result := CustomStringReplace( Result, '&MESSAGE', PRes.FBody);
250                         Result := CustomStringReplace( Result, '&SPAMMINESS', FloatToStr( spamminess ) );
251                         Result := CustomStringReplace( Result, '&NONSPAMMINESS', FloatToStr( 100 - spamminess ) );
252                 end;
253                 //----- \82±\82±\82Ü\82Å
254 {$IFDEF SPAM_FILTER_ENABLED}
255         finally
256                 wordCount.Free;
257         end;
258 {$ENDIF}
259
260 end;
261 (*************************************************************************
262  *http://\82Ì\95\8e\9a\97ñ\82ðanchor\83^\83O\95t\82«\82É\82·\82é\81B
263  *************************************************************************)
264 procedure THTMLCreate.AddAnchorTag(PRes: PResRec);
265 const
266         _HEAD : array[0..11] of String =
267                 ('', '', 'h', 'ht', '', 'htt', '', 'h', 'http://', '', '', '');
268     EMOTICONS: String = 'sssp://img.2ch.net/';
269 var
270         url: string;
271         href: string;
272         i, j, b: Integer;
273         tmp: Integer;
274         idx, idx2: Integer;
275         pos : PChar;
276         pp, pe : PChar;
277         s : String;
278         len : Integer;
279     urllen: Integer;
280 begin
281         s := PRes.FBody;
282         PRes.FBody := '';
283
284         //while True do begin
285         repeat
286                 idx  := MaxInt;
287                 idx2 := MaxInt;
288                 pp := PChar(s);
289                 pe := pp + Length(s);
290
291                 for j := 0 to 11 do begin
292                         pos := AnsiStrPosEx(pp, pe, pREF_MARKSs[j], pREF_MARKSe[j]);
293                         if pos <> nil then begin
294                                 tmp := pos - pp + 1;
295                                 idx := Min(tmp, idx);
296                                 if idx = tmp then idx2 := j;   //\82Ç\82Ì\83}\81[\83N\82Å\88ø\82Á\82©\82©\82Á\82½\82©\82ð\95Û\91
297                         end;
298                 end;
299
300                 if idx = MaxInt then begin
301                         //\83\8a\83\93\83N\82ª\96³\82¢\82æ\81B
302                         len := Length(PRes.FBody);
303                         SetLength(PRes.FBody, Length(s) + len);
304                         Move(pp^, PRes.FBody[len + 1], Length(s));
305                 end else begin
306                         if (idx > anchorLen) and
307                                 (AnsiStrPosEx(pp + idx - 1 - anchorLen, pp + idx, pANCHORs, pANCHORe) <> nil) then begin
308                                 //\8aù\82É\83\8a\83\93\83N\83^\83O\82ª\82Â\82¢\82Ä\82¢\82é\82Á\82Û\82¢\82Æ\82«\82Í\83\80\83V
309                                 //</a></A>\82ð\92T\82·\81A\8f¬\95\8e\9a\82Å\8c©\82Â\82©\82ç\82È\82¯\82ê\82Î\91å\95\8e\9a\82Å\8c\9f\8dõ
310                                 pos := AnsiStrPosEx(pp + idx, pe, pCTAGLs, pCTAGLe);
311                                 if pos = nil then
312                                         pos := AnsiStrPosEx(pp + idx, pe, pCTAGUs, pCTAGUe);
313                                 if pos = nil then
314                                         b := Length(REF_MARK[idx2])
315                                 else
316                                         b := pos - (pp  + idx) + 1;
317
318                                 len := Length(PRes.FBody);
319                                 SetLength(PRes.FBody, len + idx + b );
320                                 Move(pp^, PRes.FBody[len + 1], idx + b);
321                                 Delete(s, 1, idx + b);
322                         end else begin
323                                 pp      := PChar(s);
324                                 len     := Length(PRes.FBody);
325                                 SetLength(PRes.FBody, len + idx - 1);
326                                 Move(pp^, PRes.FBody[len + 1], idx - 1);
327
328                                 Delete(s, 1, idx - 1);
329                                 b := Length( s ) + 1;
330                                 pp      := PChar(s);
331                                 for i := 1 to b do begin
332                                         //\82P\83o\83C\83g\95\8e\9a\82ÅURL\82É\8eg\82¦\82È\82¢\95\8e\9a\82È\82ç
333                                         if (AnsiStrPosEx(pURLCHARs, pURLCHARe, pp, pp + 1) = nil) then begin
334                                                 url := Copy(s, 1, i - 1);
335                                                 Delete(s, 1, i - 1);
336                         urllen := Length(url);
337                         if (AnsiPos(REF_MARK[0], url) = 1) then
338                             href := 'http' + Copy(url, 5, urllen - 4)
339                         else
340                             href := Format('%s%s', [_HEAD[idx2], url]);
341
342                         if (GikoSys.Setting.IconImageDisplay = True) and
343                            (AnsiPos(EMOTICONS, url) = 1) and (IsImageExp(url) = True) then
344                             PRes.FBody := Format('%s<img src="%s" title="%s">', [PRes.FBody, href, url])
345                         else
346                             PRes.FBody
347                                 := Format('%s<a href="%s" target="_blank">%s</a>', [PRes.FBody, href, url]);
348                                                 Break;
349                                         end;
350                                         //\88ê\95\8e\9a\90i\82ß\82é\81B
351                                         Inc(pp);
352                                 end;
353                         end;
354                 end;
355         until idx = MaxInt;
356 end;
357
358 function THTMLCreate.IsImageExp(const Url: String): Boolean;
359 var
360     urllen: Integer;
361 begin
362     urllen := Length(Url);
363     if (AnsiPos('.gif', Url) = urllen - 3) then
364         Result := True
365     else if (AnsiPos('.png', Url) = urllen - 3) then
366         Result := True
367     else if (AnsiPos('.jpg', Url) = urllen - 3) then
368         Result := True
369     else if (AnsiPos('.jpeg', Url) = urllen - 4) then
370         Result := True
371     else
372         Result := False;
373 end;
374
375 //\88ø\90\94\81AAID\81F\91Î\8fÛ\82Æ\82È\82é\93ú\95tID\95\8e\9a\97ñ\81AANum:\83\8c\83X\94Ô AURL\81F\82»\82Ì\83X\83\8c\83b\83h\82ÌURL
376 function THTMLCreate.AddBeProfileLink(AID : string; ANum: Integer):string ;
377 const
378         BE_MARK : string = 'BE:';
379 var
380         p : integer;
381         BNum, BMark : string;
382 begin
383         p := AnsiPos(BE_MARK, AnsiUpperCase(AID));
384         if p > 0 then begin
385                 BNum := Copy(AID, p, Length(AID));
386                 AID := Copy(AID, 1, p - 1);
387                 p := AnsiPos('-', BNum);
388                 if p > 0 then begin
389                         BMark := '?' + Trim(Copy(BNum, p + 1, Length(BNum)));
390                         BNum := Copy(BNum, 1, p - 1);
391                 end;
392                 BNum := Trim(BNum);
393                 Result := AID + ' <a href="'  + BNum + '/' + IntToStr(ANum)
394                         + '" target=_blank>' + BMark + '</a>';
395         end else
396                 Result := AID;
397 end;
398 //! \83\8c\83X\83A\83\93\83J\81[\82Ì\83\8c\83X\94Ô\8d\86\82ð\95ª\8a\84\82·\82é
399 // Text = '1-9' -> st =  '1'; et = '9'
400 // Text = '10'  -> st = '10'; et = '10'
401 procedure THTMLCreate.separateNumber(var st: String; var et: String; const Text:String; const Separator: String);
402 var
403         p : Integer;
404 begin
405         p := Pos(Separator,Text);
406         if (p > 0 ) then begin
407                 st := Copy(Text, 1, p - 1);
408                 et := Copy(Text, p + Length(Separator), Length(Text));
409         end else begin
410                 st := Text;
411                 et := Text;
412         end;
413 end;
414 //! \83\8c\83X\83A\83\93\83J\81[\82ª\8ew\82µ\82Ä\82¢\82é\83\8c\83X\94Ô\8d\86\82Ì\95\8e\9a\97ñ\82ð\8eæ\93¾\82·\82é
415 function THTMLCreate.getNumberString(
416     const str: String;
417     var index :Integer; var dbCharlen: Boolean; sLen :Integer)
418 : String;
419 const
420         SN      = '0123456789';
421 var
422     ch : String;
423     sw : Boolean;
424 begin
425     Result := '';
426     sw := False;
427     while (index <= sLen) do begin
428         if (ByteType(str, index) = mbSingleByte) then begin
429             //1byte\95\8e\9a
430             ch := str[index];
431             Inc(index);
432             dbCharlen := false;
433         end else begin
434             //2byte\95\8e\9a
435             ch := ZenToHan(Copy(str, index, 2));
436             Inc(index, 2);
437             dbCharlen := true;
438         end;
439
440         if System.Pos(ch, SN) > 0 then begin
441             Result := Result + ch;
442         end else if (ch = '-') then begin
443             if sw then break;
444             if Result = '' then break;
445             Result := Result + ch;
446             sw := true;
447         end else begin
448             break;
449         end;
450     end;
451 end;
452
453 procedure THTMLCreate.ConvRes( PRes : PResRec; PResLink : PResLinkRec; DatToHTML: boolean = false);
454 const
455         GT      = '&gt;';
456         //\8c\9f\8dõ\91Î\8fÛ\82Ì\95\8e\9a\97ñ\8cS
457         TOKEN : array[0..5] of string = (GT+GT, GT, '\81\84\81\84', '\81\84', '<a ', '<A ');
458 var
459         i : integer;
460         s : string;
461         No: string;
462         pos, pmin : integer;
463         j : integer;
464         db : boolean;
465         rink : string;
466 begin
467         //s \82É\96{\95\82ð\91S\95\94\93ü\82ê\82é
468         s        :=     PRes.FBody;
469         //\8c\8b\89Ê\82ð\83N\83\8a\83A
470         PRes.FBody       :=     '';
471
472         //
473         while Length(s) > 2 do begin
474                 pmin := Length(s) + 1;
475                 i       := Length(token);
476                 for j := 0 to 5 do begin
477                         pos := AnsiPos(TOKEN[j], s);
478                         if pos <> 0 then begin
479                                 if pos < pmin then begin
480                                         //\82Ç\82ê\82Å\83q\83b\83g\82µ\82½\82©\95Û\91
481                                         i := j;
482                                         //\8dÅ\8f¬\92l\82ð\8dX\90V
483                                         pmin := pos;
484                                 end;
485                         end;
486                 end;
487
488                 //\83q\83b\83g\82µ\82½\95\8e\9a\97ñ\82Ì\88ê\82Â\8eè\91O\82Ü\82Å\8c\8b\89Ê\82É\83R\83s\81[
489                 PRes.FBody := PRes.FBody + Copy(s, 1, pmin - 1);
490                 Delete(s, 1, pmin - 1);
491
492                 if i = 6 then begin
493                         //\83q\83b\83g\82È\82µ
494                 end else if (i = 4) or (i = 5) then begin
495                         //'<a ' or '<A' \82Å\83q\83b\83g '</a>' or '</A>' \82Ü\82Å\83R\83s\81[
496                         pmin := AnsiPos('</a>' , s);
497                         pos := AnsiPos('</A>' , s);
498                         if (pmin <> 0) and (pos <> 0) then begin
499                                 if (pmin > pos) then begin
500                                         pmin := pos;
501                                 end;
502                         end else if (pos <> 0) then begin
503                                 pmin := pos;
504                         end;
505                         rink := Copy(s, 1, pmin + 3);
506                         PRes.FBody := PRes.FBody + rink;
507                         Delete(s, 1, pmin + 3);
508
509                         pmin := Length(rink);
510                         i       := Length(TOKEN);
511                         for j := 0 to 3 do begin
512                                 pos := AnsiPos(TOKEN[j], rink);
513                                 if pos <> 0 then begin
514                                         if pos < pmin then begin
515                                                 //\82Ç\82ê\82Å\83q\83b\83g\82µ\82½\82©\95Û\91
516                                                 i := j;
517                                                 //\8dÅ\8f¬\92l\82ð\8dX\90V
518                                                 pmin := pos;
519                                         end;
520                                 end;
521                         end;
522                         // \83\8c\83X\83A\83\93\83J\81[\82ª\8aÜ\82Ü\82ê\82Ä\82¢\82½\82ç,\82ª\91±\82­\8cÀ\82è\83A\83\93\83J\81[\82Æ\82µ\82Ä\88µ\82¤
523                         if i <= 3 then begin
524                 appendResAnchor(PRes, PResLink, DatToHTML, s );
525                         end;
526                 end else begin
527                         //\89½\82©\82µ\82ç\8c©\82Â\82©\82Á\82½\83p\83^\81[\83\93
528                         j := Length(TOKEN[i]) + 1;
529                         db := false;
530                 No := getNumberString(s, j, db, Length(s) );
531                         //\8fI\92[\82Ü\82Å\8ds\82Á\82Ä\82Ì\8fI\97¹\82©\83`\83F\83b\83N
532                         if j <= Length(s) then begin
533                                 if db then j := j - 2
534                                 else j := j - 1;
535                         end;
536                         addResAnchor(PRes, PResLink, DatToHTML, s, j, No);
537
538             // , \82ª\91±\82­\8cÀ\82è\83\8c\83X\83A\83\93\83J\81[\82Æ\82µ\82Ä\8f\88\97\9d\82·\82é
539             appendResAnchor(PRes, PResLink, DatToHTML, s );
540                 end;
541         end;
542         if Length(s) > 0 then begin
543                 PRes.FBody := PRes.FBody + s;
544         end;
545 end;
546 function THTMLCreate.checkComma(
547         const s : String;
548         var j : Integer
549 ) : boolean;
550 var
551         bType : TMbcsByteType;
552 begin
553         Result := false;
554         if (Length(s) > 0) then begin
555                 bType := ByteType(s, j);
556                 if ((bType = mbSingleByte) and (s[j] = ',') or
557                         ((bType = mbLeadByte) and (ZenToHan(Copy(s, j ,2)) = ','))) then begin
558                         Result := true;
559                         if (bType = mbSingleByte) then
560                                 Inc(j)
561                         else
562                                 Inc(j, 2);
563                 end;
564         end;
565 end;
566 function THTMLCreate.appendResAnchor(
567         PAddRes: PResRec; PResLink : PResLinkRec; dat : boolean;
568         var s : String) : string;
569 var
570     No{, ch, oc}: String;
571     len, j : Integer;
572     cm, {sw,} db : Boolean;
573
574 begin
575     No := '';
576     j := 1;
577     cm := checkComma(s, j);
578     len := Length(s);
579     while cm do begin
580         db := false;
581         No := getNumberString(s, j, db, len );
582
583         //\8fI\92[\82Ü\82Å\8ds\82Á\82Ä\82Ì\8fI\97¹\82©\83`\83F\83b\83N
584         if j <= len then begin
585             if db then j := j - 2
586             else j := j - 1;
587         end;
588         addResAnchor(PAddRes, PResLink, dat, s, j, No);
589         j := 1;
590         len := Length(s);
591         cm := checkComma(s, j);
592     end;
593 end;
594
595 function THTMLCreate.addResAnchor(
596         PAddRes: PResRec; PResLink : PResLinkRec; dat : boolean;
597         var s : String; j : Integer; const No: String) : string;
598 const
599         FORMAT_LINK = '<a href="../test/read.cgi?bbs=%s&key=%s&st=%s&to=%s&nofirst=true" target="_blank">';
600 var
601         st,et : string;
602 begin
603
604         //\89½\82à\90\94\8e\9a\82ª\8c©\82Â\82©\82ç\82È\82¢\82Æ\82«
605         if No = '' then begin
606                 PAddRes.FBody := PAddRes.FBody + Copy(s, 1, j - 1);
607         end else begin
608                 separateNumber(st, et, No, '-');
609
610                 if not dat then begin
611                         PAddRes.FBody := PAddRes.FBody +
612                                 Format(FORMAT_LINK, [PResLink.FBbs, PResLink.FKey, st, et]);
613                 end else begin
614                         PAddRes.FBody := PAddRes.FBody + Format('<a href="#%s">', [st]);
615                 end;
616                 PAddRes.FBody := PAddRes.FBody + Copy(s, 1, j - 1) + '</a>';
617         end;
618         Delete(s, 1, j - 1);
619 end;
620
621
622 procedure THTMLCreate.ConvertResAnchor(PRes: PResRec);
623 const
624         _HEAD : string = '<a href="../';
625         _TAIL : string = ' target="_blank">';
626         _ST: string = '&st=';
627         _TO: string = '&to=';
628         _STA: string = '&START=';
629         _END: string = '&END=';
630 var
631         i, j, k: Integer;
632     hpos, qpos : Integer;
633         tmp: string;
634         res: string;
635 begin
636         res := PRes.FBody;
637         PRes.FBody := '';
638         i := AnsiPos(_HEAD, res);
639         while i <> 0 do begin
640                 PRes.FBody := PRes.FBody + Copy(res, 1, i -1);
641                 Delete(res, 1, i - 1);
642                 j := AnsiPos(_TAIL, res);
643                 if j = 0 then begin
644                         PRes.FBody := PRes.FBody + res;
645                         Exit;
646                 end;
647                 tmp := Copy(res, 1, j - 1);
648                 Delete(res, 1, j + 16);
649                 if (AnsiPos(_ST, tmp) <> 0) and (AnsiPos(_TO, tmp) <> 0) then begin
650                         Delete(tmp, 1, AnsiPos(_ST, tmp) + 3);
651                         Delete(tmp, AnsiPos(_TO, tmp), Length(tmp));
652                         PRes.FBody := PRes.FBody + '<a href="#' + tmp + '">';
653                 end else if (AnsiPos(_STA, tmp) <> 0) and (AnsiPos(_END, tmp) <> 0) then begin
654                         Delete(tmp, 1, AnsiPos(_STA, tmp) + 6);
655                         Delete(tmp, AnsiPos(_END, tmp), Length(tmp));
656                         PRes.FBody := PRes.FBody + '<a href="#' + tmp + '">';
657                 end else begin
658                         k := LastDelimiter('/', tmp);
659                         Delete(tmp, 1, k);
660             hpos := AnsiPos('-', tmp);
661             qpos := AnsiPos('"', tmp);
662             if ( (hpos > 0) and (qpos > 0) ) then begin
663                 if ( qpos < hpos ) then begin
664                     Delete(tmp, qpos, Length(tmp));
665                 end else begin
666                     Delete(tmp, hpos, Length(tmp));
667                 end;
668             end else begin
669                 if ( qpos > 0 ) then begin
670                     Delete(tmp, qpos, Length(tmp));
671                 end else if ( qpos > 0 ) then begin
672                     Delete(tmp, hpos, Length(tmp));
673                 end;
674             end;
675
676                         PRes.FBody := PRes.FBody + '<a href="#' + tmp + '">';
677                 end;
678                 i := AnsiPos(_HEAD, res);
679         end;
680         PRes.FBody := PRes.FBody + res;
681
682 end;
683 //Plugin\82ð\97\98\97p\82·\82éBoard\82Ì\83X\83\8c\83b\83h\82ÌHTML\82ð\8dì\90¬\82µ\82Ädoc\82É\8f\91\82«\8d\9e\82Þ
684 procedure THTMLCreate.CreateUsePluginHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; var sTitle: string);
685 var
686         i: integer;
687         NewReceiveNo: Integer;
688         boardPlugIn : TBoardPlugIn;
689         UserOptionalStyle: string;
690 begin
691         //===== \83v\83\89\83O\83C\83\93\82É\82æ\82é\95\\8e¦
692         boardPlugIn             := ThreadItem.ParentBoard.BoardPlugIn;
693         NewReceiveNo    := ThreadItem.NewReceive;
694         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
695         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
696         html.add(boardPlugIn.GetHeader( DWORD( threadItem ),
697                 '<style type="text/css">body {' + UserOptionalStyle + '}</style>' ));
698         html.Add('<p id="idSearch"></p>');
699         html.Flush;
700         
701         for i := 0 to threadItem.Count - 1 do begin
702                 // 1 \82Í\95K\82¸\95\\8e¦
703                 if i <> 0 then begin
704                         // \95\\8e¦\94Í\88Í\82ð\8cÀ\92è
705             if (isOutsideRange(ThreadItem, i)) then begin
706                 Continue;
707             end;
708                 end;
709
710                 // \90V\92\85\83}\81[\83N
711                 if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
712                         try
713                                 if GikoSys.Setting.UseSkin then begin
714                                         if FileExists( GikoSys.GetSkinNewmarkFileName ) then
715                                                 html.Add( LoadFromSkin( GikoSys.GetSkinNewmarkFileName, ThreadItem, ThreadItem.Size ))
716                                         else
717                                                 html.Add( '<a name="new"></a>');
718                                 end else if GikoSys.Setting.UseCSS then begin
719                                         html.Add('<a name="new"></a><div class="new">\90V\92\85\83\8c\83X <span class="newdate">' + FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate) + '</span></div>');
720                                 end else begin
721                                         html.Add('</dl>');
722                                         html.Add('<a name="new"></a>');
723                                         html.Add('<table width="100%" bgcolor="#3333CC" cellpadding="0" cellspacing="1"><tr><td align="center" bgcolor="#6666FF" valign="middle"><font size="-1" color="#ffffff"><b>\90V\92\85\83\8c\83X ' + FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate) + '</b></font></td></tr></table>');
724                                         html.Add('<dl>');
725                                 end;
726                         except
727                                 html.Add( '<a name="new"></a>');
728                         end;
729                 end;
730
731                 // \83\8c\83X
732                 html.Add( boardPlugIn.GetRes( DWORD( threadItem ), i + 1 ));
733
734                 if ThreadItem.Kokomade = (i + 1) then begin
735                         // \82±\82±\82Ü\82Å\93Ç\82ñ\82¾
736                         try
737                                 if GikoSys.Setting.UseSkin then begin
738                                         if FileExists( GikoSys.GetSkinBookmarkFileName ) then
739                                                 html.Add( LoadFromSkin( GikoSys.GetSkinBookmarkFileName, ThreadItem, ThreadItem.Size ))
740                                         else
741                                                 html.Add( '<a name="koko"></a>');
742                                 end else if GikoSys.Setting.UseCSS then begin
743                                         html.Add('<a name="koko"></a><div class="koko">\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</div>');
744                                 end else begin
745                                         html.Add('</dl>');
746                                         html.Add('<a name="koko"></a><table width="100%" bgcolor="#55AA55" cellpadding="0" cellspacing="1"><tr><td align="center" bgcolor="#77CC77" valign="middle"><font size="-1" color="#ffffff"><b>\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</b></font></td></tr></table>');
747                                         html.Add('<dl>');
748                                 end;
749                         except
750                                 html.Add('<a name="koko"></a>');
751                         end;
752                 end;
753         end;
754
755
756         // \83X\83L\83\93(\83t\83b\83^)
757         html.Add( boardPlugIn.GetFooter( DWORD( threadItem ), '<a name="bottom"></a>' ));
758 end;
759
760
761 procedure THTMLCreate.CreateUseSKINHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList);
762 const
763         KOKO_TAG = '<a name="koko"></a>';
764         NEW_TAG = '<a name="new"></a>';
765 var
766         i: integer;
767         NewReceiveNo: Integer;
768         Res: TResRec;
769         UserOptionalStyle: string;
770         SkinHeader: string;
771         SkinNewRes: string;
772         SkinRes: string;
773         ThreadName : string;
774         ResLink :TResLinkRec;
775 begin
776         NewReceiveNo := ThreadItem.NewReceive;
777         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
778         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
779         ThreadName := ChangeFileExt(ThreadItem.FileName, '');
780         ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
781         ResLink.FKey := ThreadName;
782         // \83X\83L\83\93\82Ì\90Ý\92è
783         try
784                 SkinHeader := LoadFromSkin( GikoSys.GetSkinHeaderFileName, ThreadItem, ThreadItem.Size);
785                 if Length( UserOptionalStyle ) > 0 then
786                         SkinHeader := CustomStringReplace( SkinHeader, '</head>',
787                                 '<style type="text/css">body {' + UserOptionalStyle + '}</style></head>');
788                 html.Add( SkinHeader );
789         except
790         end;
791
792         SkinNewRes := LoadFromSkin( GikoSys.GetSkinNewResFileName, ThreadItem, ThreadItem.Size);
793         SkinRes := LoadFromSkin( GikoSys.GetSkinResFileName, ThreadItem, ThreadItem.Size );
794
795         html.Add('<p id="idSearch"></p>'#13#10'<a name="top"></a>');
796         html.Flush;
797
798         for i := 0 to ReadList.Count - 1 do begin
799                 // 1 \82Í\95K\82¸\95\\8e¦
800                 if i <> 0 then begin
801                         // \95\\8e¦\94Í\88Í\82ð\8cÀ\92è
802             if (isOutsideRange(ThreadItem, i)) then begin
803                 Continue;
804             end;
805                 end;
806
807                 // \90V\92\85\83}\81[\83N
808                 if (NewReceiveNo = i + 1) or ((NewReceiveNo = 0) and (i = 0)) then begin
809                         if FileExists( GikoSys.GetSkinNewmarkFileName ) then
810                                 html.Add( LoadFromSkin( GikoSys.GetSkinNewmarkFileName, ThreadItem, ThreadItem.Size ))
811                         else
812                                 html.Add( NEW_TAG );
813                 end;
814
815                 if (Trim(ReadList[i]) <> '') then begin
816                         DivideStrLine(ReadList[i], @Res);
817             AddAnchorTag(@Res);
818             ConvRes(@Res, @ResLink);
819             Res.FDateTime := AddBeProfileLink(Res.FDateTime, i + 1);
820
821             if NewReceiveNo <= (i + 1) then
822                 // \90V\92\85\83\8c\83X
823                 html.Add(SkinedRes(SkinNewRes, @Res, IntToStr(i + 1)))
824             else
825                 // \92Ê\8fí\82Ì\83\8c\83X
826                 html.Add(SkinedRes(SkinRes, @Res, IntToStr(i + 1)));
827                 end;
828
829                 if ThreadItem.Kokomade = (i + 1) then begin
830                         // \82±\82±\82Ü\82Å\93Ç\82ñ\82¾
831                         if FileExists( GikoSys.GetSkinBookmarkFileName ) then
832                                 html.Add( LoadFromSkin( GikoSys.GetSkinBookmarkFileName, ThreadItem, ThreadItem.Size ))
833                         else
834                                 html.Add( KOKO_TAG );
835                 end;
836         end;
837     html.Add(getKeywordLink(ThreadItem));
838         html.Add('<a name="bottom"></a>');
839         // \83X\83L\83\93(\83t\83b\83^)
840         html.Add( LoadFromSkin( GikoSys.GetSkinFooterFileName, ThreadItem, ThreadItem.Size ) );
841 end;
842
843 procedure THTMLCreate.CreateUseCSSHTML(html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList; sTitle: string );
844 const
845         FORMAT_NOMAIL  = '<a name="%s"></a><div class="header"><span class="no"><a href="menu:%s">%s</a></span>'
846                                         + '<span class="name_label"> \96¼\91O\81F </span> <span class="name"><b>%s</b></span>'
847                                         + '<span class="date_label"> \93\8a\8de\93ú\81F</span> <span class="date">%s</span></div>'
848                                         + '<div class="mes">%s</div>';
849
850         FORMAT_SHOWMAIL = '<a name="%s"></a><div class="header"><span class="no"><a href="menu:%s">%s</a></span>'
851                                         + '<span class="name_label"> \96¼\91O\81F </span><a class="name_mail" href="mailto:%s">'
852                                         + '<b>%s</b></a><span class="mail"> [%s]</span><span class="date_label"> \93\8a\8de\93ú\81F</span>'
853                                         + '<span class="date"> %s</span></div><div class="mes">%s</div>';
854
855         FORMAT_NOSHOW = '<a name="%s"></a><div class="header"><span class="no"><a href="menu:%s">%s</a></span>'
856                                         + '<span class="name_label"> \96¼\91O\81F </span><a class="name_mail" href="mailto:%s">'
857                                         + '<b>%s</b></a><span class="date_label"> \93\8a\8de\93ú\81F</span><span class="date"> %s</span></div>'
858                                         + '<div class="mes">%s</div>';
859 var
860         i: integer;
861         No: string;
862         CSSFileName: string;
863         NewReceiveNo: Integer;
864         Res: TResRec;
865         UserOptionalStyle: string;
866         ThreadName :String;
867         ResLink :TResLinkRec;
868 begin
869         NewReceiveNo := ThreadItem.NewReceive;
870         ThreadName := ChangeFileExt(ThreadItem.FileName, '');
871         ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
872         ResLink.FKey := ThreadName;
873         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
874         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
875         CSSFileName := GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName;
876         if GikoSys.Setting.UseCSS and FileExists(CSSFileName) then begin
877                 //CSS\8eg\97p
878                 html.Add('<html><head>');
879                 html.Add('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
880                 html.Add('<title>' + sTitle + '</title>');
881                 html.Add('<link rel="stylesheet" href="'+CSSFileName+'" type="text/css">');
882                 if Length( UserOptionalStyle ) > 0 then
883                         html.Add('<style type="text/css">body {' + UserOptionalStyle + '}</style>');
884                 html.Add('</head>'#13#10'<body>');
885                 html.Add('<a name="top"></a>'#13#10'<p id="idSearch"></p>');
886                 html.Add('<div class="title">' + sTitle + '</div>');
887                 html.Flush;
888                 for i := 0 to ReadList.Count - 1 do begin
889                         // 1 \82Í\95K\82¸\95\\8e¦
890                         if i <> 0 then begin
891                         // \95\\8e¦\94Í\88Í\82ð\8cÀ\92è
892                 if (isOutsideRange(ThreadItem, i)) then begin
893                     Continue;
894                 end;
895                         end;
896
897                         if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
898                                 html.Add('<a name="new"></a><div class="new">\90V\92\85\83\8c\83X <span class="newdate">' + FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate) + '</span></div>');
899                         end;
900
901                         if (Trim(ReadList[i]) <> '') then begin
902                                 No := IntToStr(i + 1);
903                                 DivideStrLine(ReadList[i], @Res);
904                 AddAnchorTag(@Res);
905                 ConvRes(@Res, @ResLink);
906                 Res.FDateTime := AddBeProfileLink(Res.FDateTime, i + 1);
907                 if Res.FMailTo = '' then
908                     html.Add(Format(FORMAT_NOMAIL, [No, No, No, Res.FName, Res.FDateTime, Res.FBody]))
909                 else if GikoSys.Setting.ShowMail then
910                     html.Add(Format(FORMAT_SHOWMAIL, [No, No, No, Res.FMailTo, Res.FName, Res.FMailTo, Res.FDateTime, Res.FBody]))
911                 else
912                     html.Add(Format(FORMAT_NOSHOW, [No, No, No, Res.FMailTo, Res.FName, Res.FDateTime, Res.FBody]));
913             end;
914                         if ThreadItem.Kokomade = (i + 1) then begin
915                                 html.Add('<a name="koko"></a><div class="koko">\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</div>');
916                         end;
917
918                 end;
919         html.Add(getKeywordLink(ThreadItem));
920                 html.Add('<a name="bottom"></a>');
921                 html.Add('<a name="last"></a>');
922                 html.Add('</body></html>');
923         end;
924 end;
925
926 procedure THTMLCreate.CreateDefaultHTML (html:TBufferedWebBrowser; ThreadItem: TThreadItem; ReadList: TStringList; sTitle: string );
927 var
928         i: integer;
929         NewReceiveNo: Integer;
930         ThreadName: String;
931         ResLink : TResLinkRec;
932 begin
933         NewReceiveNo := ThreadItem.NewReceive;
934         ThreadName := ChangeFileExt(ThreadItem.FileName, '');
935         ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
936         ResLink.FKey := ThreadName;
937         html.Add('<html><head>');
938         html.Add('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
939         html.Add('<title>' + sTitle + '</title></head>');
940         html.Add('<body TEXT="#000000" BGCOLOR="#EFEFEF" link="#0000FF" alink="#FF0000" vlink="#660099">');
941         html.Add('<a name="top"></a>');
942         html.Add('<font size=+1 color="#FF0000">' + sTitle + '</font>');
943         html.Add('<dl>');
944         html.Add('<p id="idSearch"></p>');
945         html.Flush;
946         for i := 0 to ReadList.Count - 1 do begin
947                 // 1 \82Í\95K\82¸\95\\8e¦
948                 if i <> 0 then begin
949                         // \95\\8e¦\94Í\88Í\82ð\8cÀ\92è
950             if (isOutsideRange(ThreadItem, i)) then begin
951                 Continue;
952             end;
953                 end;
954
955                 if (NewReceiveNo = (i + 1)) or ((NewReceiveNo = 0) and (i = 0)) then begin
956                         html.Add('</dl>');
957                         html.Add('<a name="new"></a>');
958                         html.Add('<table width="100%" bgcolor="#3333CC" cellpadding="0" cellspacing="1"><tr><td align="center" bgcolor="#6666FF" valign="middle"><font size="-1" color="#ffffff"><b>\90V\92\85\83\8c\83X ' + FormatDateTime('yyyy/mm/dd(ddd) hh:mm', ThreadItem.RoundDate) + '</b></font></td></tr></table>');
959                         html.Add('<dl>');
960                 end;
961
962                 if (Trim(ReadList[i]) <> '') then begin
963             html.Add(GetResString(i, ReadList[i], @ResLink));
964         end;
965                 if ThreadItem.Kokomade = (i + 1) then begin
966                         html.Add('</dl>');
967                         html.Add('<a name="koko"></a><table width="100%" bgcolor="#55AA55" cellpadding="0" cellspacing="1"><tr><td align="center" bgcolor="#77CC77" valign="middle"><font size="-1" color="#ffffff"><b>\83R\83R\82Ü\82Å\93Ç\82ñ\82¾</b></font></td></tr></table>');
968                         html.Add('<dl>');
969                 end;
970         end;
971     html.Add(getKeywordLink(ThreadItem));
972         html.Add('</dl>'#13#10'<a name="bottom"></a>'#13#10'</body></html>');
973 end;
974 function THTMLCreate.GetResString(index: Integer; const Line: String; PResLink : PResLinkRec): String;
975 var
976     No : String;
977     Res: TResRec;
978 begin
979     No := IntToStr(index + 1);
980     DivideStrLine(Line, @Res);
981     Res.FBody := DeleteLink(Res.FBody);
982     AddAnchorTag(@Res);
983     ConvRes(@Res, PResLink);
984     Res.FDateTime := AddBeProfileLink(Res.FDateTime, index + 1);
985     if Res.FMailTo = '' then
986         Result := '<a name="' + No + '"></a><dt><a href="menu:' + No + '">' + No + '</a> \96¼\91O\81F<font color="forestgreen"><b> ' + Res.FName + ' </b></font> \93\8a\8de\93ú\81F <span class="date">' + Res.FDateTime+ '</span><br><dd>' + Res.Fbody + ' <br><br><br>'#13#10
987     else if GikoSys.Setting.ShowMail then
988         Result := '<a name="' + No + '"></a><dt><a href="menu:' + No + '">' + No + '</a> \96¼\91O\81F<a href="mailto:' + Res.FMailTo + '"><b> ' + Res.FName + ' </B></a> [' + Res.FMailTo + '] \93\8a\8de\93ú\81F <span class="date">' + Res.FDateTime+ '</span><br><dd>' + Res.Fbody + ' <br><br><br>'#13#10
989     else
990         Result := '<a name="' + No + '"></a><dt><a href="menu:' + No + '">' + No + '</a> \96¼\91O\81F<a href="mailto:' + Res.FMailTo + '"><b> ' + Res.FName + ' </B></a> \93\8a\8de\93ú\81F <span class="date">' + Res.FDateTime+ '</span><br><dd>' + Res.Fbody + ' <br><br><br>'#13#10;
991 end;
992 procedure THTMLCreate.CreateHTML2(Browser: TWebBrowser; ThreadItem: TThreadItem; var sTitle: string);
993 var
994         ReadList: TStringList;
995         CSSFileName: string;
996         FileName: string;
997         Res: TResRec;
998         body : TBufferedWebBrowser;
999     ThreadInfo: TAbonThread;
1000 {$IFDEF DEBUG}
1001         st, rt: Cardinal;
1002 {$ENDIF}
1003 begin
1004 {$IFDEF DEBUG}
1005         Writeln('Create HTML');
1006         st := GetTickCount;
1007 {$ENDIF}
1008         if ThreadItem <> nil then begin
1009                 body := TBufferedWebBrowser.Create(Browser, 100);
1010                 try
1011                         body.Open;
1012                         if ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
1013                                 CreateUsePluginHTML(body, ThreadItem, sTitle);
1014                         end else begin
1015                                 ShortDayNames[1] := '\93ú';               ShortDayNames[2] := '\8c\8e';
1016                                 ShortDayNames[3] := '\89Î';               ShortDayNames[4] := '\90\85';
1017                                 ShortDayNames[5] := '\96Ø';               ShortDayNames[6] := '\8bà';
1018                                 ShortDayNames[7] := '\93y';
1019
1020                                 ReadList := TStringList.Create;
1021                                 try
1022                                         if ThreadItem.IsLogFile then begin
1023                         ThreadInfo := TAbonThread.Create;
1024                         ThreadInfo.Is2ch  := ThreadItem.ParentBoard.Is2ch;
1025                         ThreadInfo.Board  := ThreadItem.ParentBoard.BBSID;
1026                         ThreadInfo.Thread := ChangeFileExt(ThreadItem.FileName, '');
1027                                                 ReadList.BeginUpdate;
1028                                                 FileName := ThreadItem.GetThreadFileName;
1029                                                 ReadList.LoadFromFile(FileName);
1030                                                 ReadList.EndUpdate;
1031                                                 GikoSys.FAbon.IndividualAbon(ReadList, ChangeFileExt(FileName,'.NG'));
1032                                                 GikoSys.FAbon.Execute(ReadList, ThreadInfo);            //       \82 \82Ú\81`\82ñ\82µ\82Ä
1033                                                 GikoSys.FSelectResFilter.Execute(ReadList, ThreadInfo); //\83\8c\83X\82Ì\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\82·\82é
1034                                                 if ThreadItem.Title = '' then begin
1035                                                         DivideStrLine(ReadList[0], @Res);
1036                                                         sTitle := Res.FTitle;
1037                                                 end else
1038                                                         sTitle := ThreadItem.Title;
1039                         ThreadInfo.Free;
1040                                         end else begin
1041                                                 sTitle := CustomStringReplace(ThreadItem.Title, '\81\97\81M', ',');
1042                                         end;
1043                                         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1044                                         CSSFileName := GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName;
1045                                         if GikoSys.Setting.UseSkin then begin
1046                                                 CreateUseSKINHTML(body, ThreadItem, ReadList);
1047                                         end else if GikoSys.Setting.UseCSS and FileExists(CSSFileName) then begin
1048                                                 CreateUseCSSHTML(body, ThreadItem, ReadList, sTitle);
1049                                         end else begin
1050                                                 CreateDefaultHTML(body, ThreadItem, ReadList, sTitle);
1051                                         end;
1052                                 finally
1053                                         ReadList.Free;
1054                                 end;
1055                         end;
1056                 finally
1057                         body.Close;
1058                         body.Free;
1059                 end;
1060         end;
1061 {$IFDEF DEBUG}
1062         rt := GetTickCount - st;
1063         Writeln('Done.');
1064         Writeln(IntToStr(rt) + ' ms');
1065 {$ENDIF}
1066 end;
1067
1068 procedure THTMLCreate.CreateHTML3(var html: TStringList; ThreadItem: TThreadItem; var sTitle: string);
1069 var
1070         i: integer;
1071         No: string;
1072         //bufList : TStringList;
1073         ReadList: TStringList;
1074 //      SaveList: TStringList;
1075         CSSFileName: string;
1076         BBSID: string;
1077         FileName: string;
1078         Res: TResRec;
1079         boardPlugIn : TBoardPlugIn;
1080
1081         UserOptionalStyle: string;
1082         SkinHeader: string;
1083         SkinRes: string;
1084         tmp, tmp1: string;
1085         ThreadName: String;
1086         ResLink : TResLinkRec;
1087     ThreadInfo: TAbonThread;
1088
1089         function LoadSkin( fileName: string ): string;
1090         begin
1091                 Result := LoadFromSkin( fileName, ThreadItem, ThreadItem.Size );
1092         end;
1093         function ReplaceRes( skin: string ): string;
1094         begin
1095                 Result := SkinedRes( skin, @Res, No );
1096         end;
1097
1098 begin
1099         if ThreadItem <> nil then begin
1100                 CSSFileName := GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName;
1101                 ThreadName := ChangeFileExt(ThreadItem.FileName, '');
1102                 ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
1103                 ResLink.FKey := ThreadName;
1104                 html.Clear;
1105                 html.BeginUpdate;
1106                 //if ThreadItem.IsBoardPlugInAvailable then begin
1107                 if ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
1108                         //===== \83v\83\89\83O\83C\83\93\82É\82æ\82é\95\\8e¦
1109                         //boardPlugIn           := ThreadItem.BoardPlugIn;
1110                         boardPlugIn             := ThreadItem.ParentBoard.BoardPlugIn;
1111                         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1112                         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
1113                         try
1114                                 // \95\8e\9a\83R\81[\83h\82Í\83v\83\89\83O\83C\83\93\82É\94C\82¹\82é
1115                                 // \83w\83b\83_
1116                                 tmp := boardPlugIn.GetHeader( DWORD( threadItem ),
1117                                         '<style type="text/css">body {' + UserOptionalStyle + '}</style>' );
1118                                 //\90â\91Î\8eQ\8fÆ\82©\82ç\91\8a\91Î\8eQ\8fÆ\82Ö
1119                                 if GikoSys.Setting.UseSkin then begin
1120                                         tmp1 := './' + GikoSys.Setting.CSSFileName;
1121                                         tmp1 := CustomStringReplace(tmp1, GikoSys.GetConfigDir, '');
1122                                         tmp1 := CustomStringReplace(tmp1, '\', '/');
1123                                         tmp := CustomStringReplace(tmp, ExtractFilePath(GikoSys.Setting.CSSFileName),  tmp1);
1124                                 end else if GikoSys.Setting.UseCSS then begin
1125                                         tmp1 := './' + CSSFileName;
1126                                         tmp1 := CustomStringReplace(tmp1, GikoSys.GetConfigDir, '');
1127                                         tmp1 := CustomStringReplace(tmp1, '\', '/');
1128                                         tmp := CustomStringReplace(tmp, CSSFileName,  tmp1);
1129                                 end;
1130                                 html.Append( tmp );
1131
1132                                 for i := 0 to threadItem.Count - 1 do begin
1133
1134                                         // \83\8c\83X
1135                                         Res.FBody := boardPlugIn.GetRes( DWORD( threadItem ), i + 1 );
1136                                         ConvertResAnchor(@Res);
1137                                         html.Append( Res.FBody );
1138
1139                                 end;
1140                                 // \83X\83L\83\93(\83t\83b\83^)
1141                                 html.Append( boardPlugIn.GetFooter( DWORD( threadItem ), '<a name="bottom"></a>' ) );
1142                         finally
1143                         end;
1144                         html.EndUpdate;
1145                         //Exit;
1146                 end else begin
1147                         ShortDayNames[1] := '\93ú';               ShortDayNames[2] := '\8c\8e';
1148                         ShortDayNames[3] := '\89Î';               ShortDayNames[4] := '\90\85';
1149                         ShortDayNames[5] := '\96Ø';               ShortDayNames[6] := '\8bà';
1150                         ShortDayNames[7] := '\93y';
1151                         BBSID := ThreadItem.ParentBoard.BBSID;
1152                         ReadList := TStringList.Create;
1153                         try
1154                                 if ThreadItem.IsLogFile then begin
1155                     ThreadInfo := TAbonThread.Create;
1156                     ThreadInfo.Is2ch  := ThreadItem.ParentBoard.Is2ch;
1157                     ThreadInfo.Board  := ThreadItem.ParentBoard.BBSID;
1158                     ThreadInfo.Thread := ChangeFileExt(ThreadItem.FileName, '');
1159                                         FileName := ThreadItem.GetThreadFileName;
1160                                         ReadList.LoadFromFile(FileName);
1161                                         GikoSys.FAbon.IndividualAbon(ReadList, ChangeFileExt(FileName,'.NG'));
1162                                         GikoSys.FAbon.Execute(ReadList, ThreadInfo);            //       \82 \82Ú\81`\82ñ\82µ\82Ä
1163                                         GikoSys.FSelectResFilter.Execute(ReadList, ThreadInfo); //\83\8c\83X\82Ì\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\82·\82é
1164                                         DivideStrLine(ReadList[0], @Res);
1165                                         //Res.FTitle := CustomStringReplace(Res.FTitle, '\81\97\81M', ',');
1166                                         sTitle := Res.FTitle;
1167                     ThreadInfo.Free;
1168                                 end else begin
1169                                         sTitle := CustomStringReplace(ThreadItem.Title, '\81\97\81M', ',');
1170                                 end;
1171                                 try
1172                                         // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1173                                         UserOptionalStyle := GikoSys.SetUserOptionalStyle;
1174
1175                                         if GikoSys.Setting.UseSkin then begin
1176                                                 // \83X\83L\83\93\8eg\97p
1177                                                 // \83X\83L\83\93\82Ì\90Ý\92è
1178                                                 try
1179                                                         SkinHeader := LoadSkin( GikoSys.GetSkinHeaderFileName );
1180                                                         if Length( UserOptionalStyle ) > 0 then
1181                                                                 SkinHeader := CustomStringReplace( SkinHeader, '</head>',
1182                                                                         '<style type="text/css">body {' + UserOptionalStyle + '}</style></head>');
1183                                                         //\90â\91Î\8eQ\8fÆ\82©\82ç\91\8a\91Î\8eQ\8fÆ\82Ö
1184                                                         tmp1 := './' + GikoSys.Setting.CSSFileName;
1185                                                         tmp1 := CustomStringReplace(tmp1, GikoSys.GetConfigDir, '');
1186                                                         tmp1 := CustomStringReplace(tmp1, '\', '/');
1187                                                         SkinHeader := CustomStringReplace(SkinHeader, ExtractFilePath(GikoSys.Setting.CSSFileName),  tmp1);
1188                                                         html.Append( SkinHeader );
1189                                                 except
1190                                                 end;
1191                                                 try
1192                                                         SkinRes := LoadSkin( GikoSys.GetSkinResFileName );
1193                                                 except
1194                                                 end;
1195                                                 html.Append('<a name="top"></a>');
1196                                                 for i := 0 to ReadList.Count - 1 do begin
1197                                                         if (Trim(ReadList[i]) <> '') then begin
1198                                                                 No := IntToStr(i + 1);
1199
1200                                                                 DivideStrLine(ReadList[i], @Res);
1201                                                                 AddAnchorTag(@Res);
1202                                                                 ConvRes(@Res, @ResLink, true);
1203                                                                 ConvertResAnchor(@Res);
1204
1205                                                                 try
1206                                                                         html.Append( ReplaceRes( SkinRes ) );
1207                                                                 except
1208                                                                 end;
1209                                                         end;
1210
1211                                                 end;
1212                                                 html.Append('<a name="bottom"></a>');
1213                                                 // \83X\83L\83\93(\83t\83b\83^)
1214                                                 try
1215                                                         html.Append( LoadSkin( GikoSys.GetSkinFooterFileName ) );
1216                                                 except
1217                                                 end;
1218                                         end else if GikoSys.Setting.UseCSS and FileExists(CSSFileName) then begin
1219                                                 //CSS\8eg\97p
1220                                                 //CSSFileName := GetAppDir + CSS_FILE_NAME;
1221                                                 html.Append('<html><head>');
1222                                                 html.Append('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
1223                                                 html.Append('<title>' + sTitle + '</title>');
1224                                                 //\90â\91Î\8eQ\8fÆ\82©\82ç\91\8a\91Î\8eQ\8fÆ\82Ö
1225                                                 tmp1 := './' + CSSFileName;
1226                                                 tmp1 := CustomStringReplace(tmp1, GikoSys.GetConfigDir, '');
1227                                                 tmp1 := CustomStringReplace(tmp1, '\', '/');
1228
1229                                                 html.Append('<link rel="stylesheet" href="'+tmp1+'" type="text/css">');
1230                                                 if Length( UserOptionalStyle ) > 0 then
1231                                                         html.Append('<style type="text/css">body {' + UserOptionalStyle + '}</style>');
1232                                                 html.Append('</head>');
1233                                                 html.Append('<body>');
1234                                                 html.Append('<a name="top"></a>');
1235                                                 html.Append('<div class="title">' + sTitle + '</div>');
1236                                                 for i := 0 to ReadList.Count - 1 do begin
1237                                                         if (Trim(ReadList[i]) <> '') then begin
1238                                                                 No := IntToStr(i + 1);
1239                                                                 DivideStrLine(ReadList[i], @Res);
1240                                                                 AddAnchorTag(@Res);
1241                                                                 ConvRes(@Res, @ResLink, true);
1242                                                                 ConvertResAnchor(@Res);
1243                                                                 if Res.FMailTo = '' then
1244                                                                         html.Append('<a name="' + No + '"></a>'
1245                                                                                                         + '<div class="header"><span class="no"><a href="menu:' + No + '">' + No + '</a></span> '
1246                                                                                                         + '<span class="name_label">\96¼\91O\81F</span> '
1247                                                                                                         + '<span class="name"><b>' + Res.FName + '</b></span> '
1248                                                                                                         + '<span class="date_label">\93\8a\8de\93ú\81F</span> '
1249                                                                                                         + '<span class="date">' + Res.FDateTime+ '</span></div>'
1250                                                                                                                                                                                                 + '<div class="mes">' + Res.FBody + ' </div>')
1251                                                                 else if GikoSys.Setting.ShowMail then
1252                                                                         html.Append('<a name="' + No + '"></a>'
1253                                                                                                         + '<div class="header"><span class="no"><a href="menu:' + No + '">' + No + '</a></span>'
1254                                                                                                                                                                                                 + '<span class="name_label"> \96¼\91O\81F </span>'
1255                                                                                                         + '<a class="name_mail" href="mailto:' + Res.FMailTo + '">'
1256                                                                                                         + '<b>' + Res.FName + '</b></a><span class="mail"> [' + Res.FMailTo + ']</span>'
1257                                                                                                         + '<span class="date_label"> \93\8a\8de\93ú\81F</span>'
1258                                                                                                         + '<span class="date"> ' + Res.FDateTime+ '</span></div>'
1259                                                                                                         + '<div class="mes">' + Res.FBody + ' </div>')
1260                                                                 else
1261                                                                         html.Append('<a name="' + No + '"></a>'
1262                                                                                                         + '<div class="header"><span class="no"><a href="menu:' + No + '">' + No + '</a></span>'
1263                                                                                                         + '<span class="name_label"> \96¼\91O\81F </span>'
1264                                                                                                         + '<a class="name_mail" href="mailto:' + Res.FMailTo + '">'
1265                                                                                                         + '<b>' + Res.FName + '</b></a>'
1266                                                                                                         + '<span class="date_label"> \93\8a\8de\93ú\81F</span>'
1267                                                                                                         + '<span class="date"> ' + Res.FDateTime+ '</span></div>'
1268                                                                                                                                                                                                 + '<div class="mes">' + Res.FBody + ' </div>');
1269                                                         end;
1270                                                 end;
1271                                                 html.Append('<a name="bottom"></a>');
1272                                                 html.Append('<a name="last"></a>');
1273                                                 html.Append('</body></html>');
1274                                         end else begin
1275                                                 //CSS\94ñ\8eg\97p
1276                                                 html.Append('<html><head>');
1277                                                 html.Append('<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">');
1278                                                 html.Append('<title>' + sTitle + '</title></head>');
1279                                                 html.Append('<body TEXT="#000000" BGCOLOR="#EFEFEF" link="#0000FF" alink="#FF0000" vlink="#660099">');
1280                                                 html.Append('<a name="top"></a>');
1281                                                 html.Append('<font size=+1 color="#FF0000">' + sTitle + '</font>');
1282                                                 html.Append('<dl>');
1283                                                 for i := 0 to ReadList.Count - 1 do begin
1284                                                         if (Trim(ReadList[i]) <> '') then begin
1285                                                                 No := IntToStr(i + 1);
1286                                                                 DivideStrLine(ReadList[i], @Res);
1287                                                                 AddAnchorTag(@Res);
1288                                                                 ConvRes(@Res, @ResLink, true);
1289                                                                 ConvertResAnchor(@Res);
1290                                                                 if Res.FMailTo = '' then
1291                                                                         html.Append('<a name="' + No + '"></a><dt><a href="menu:' + No + '">' + No + '</a> \96¼\91O\81F<font color="forestgreen"><b> ' + Res.FName + ' </b></font> \93\8a\8de\93ú\81F ' + Res.FDateTime+ '<br><dd>' + Res.Fbody + ' <br><br><br>')
1292                                                                 else if GikoSys.Setting.ShowMail then
1293                                                                         html.Append('<a name="' + No + '"></a><dt><a href="menu:' + No + '">' + No + '</a> \96¼\91O\81F<a href="mailto:' + Res.FMailTo + '"><b> ' + Res.FName + ' </B></a> [' + Res.FMailTo + '] \93\8a\8de\93ú\81F ' + Res.FDateTime+ '<br><dd>' + Res.Fbody + ' <br><br><br>')
1294                                                                 else
1295                                                                         html.Append('<a name="' + No + '"></a><dt><a href="menu:' + No + '">' + No + '</a> \96¼\91O\81F<a href="mailto:' + Res.FMailTo + '"><b> ' + Res.FName + ' </B></a> \93\8a\8de\93ú\81F ' + Res.FDateTime+ '<br><dd>' + Res.Fbody + ' <br><br><br>');
1296                                                         end;
1297                                                 end;
1298                                                 html.Append('</dl>');
1299                                                 html.Append('<a name="bottom"></a>');
1300                                                 html.Append('</body></html>');
1301                                         end;
1302                                 finally
1303                                         html.EndUpdate;
1304                                 end;
1305                         finally
1306                                 ReadList.Free;
1307                         end;
1308                 end;
1309         end;
1310 end;
1311
1312 procedure THTMLCreate.SetResPopupText(Hint : TResPopupBrowser; threadItem: TThreadItem; StNum, ToNum: Integer; Title, First: Boolean);
1313 var
1314         i: Integer;
1315         tmp: string;
1316         FileName: string;
1317         Line: Integer;
1318
1319         wkInt: Integer;
1320
1321     boardPlugIn : TBoardPlugIn;
1322     Html: TStringList;
1323         ResLink : TResLinkRec;
1324     ThreadInfo: TAbonThread;
1325 begin
1326
1327     Html := TStringList.Create;
1328         try
1329                 if StNum > ToNum then begin
1330                         wkInt := StNum;
1331                         StNum := ToNum;
1332                         ToNum := wkInt;
1333                 end;
1334
1335                 //\8dÅ\91å10\83\8c\83X\82Ü\82Å\95\\8e¦
1336                 if StNum + MAX_POPUP_RES < ToNum then
1337                         ToNum := StNum + MAX_POPUP_RES;
1338
1339         Hint.Title := '';
1340         Hint.RawDocument := '';
1341         Hint.Thread := nil;
1342
1343                 //\83^\83C\83g\83\8b\95\\8e¦
1344                 if Title then
1345                                 if ThreadItem <> nil then
1346                                         Hint.Title := ThreadItem.Title;
1347
1348         if ThreadItem <> nil then begin
1349             ThreadInfo := TAbonThread.Create;
1350             Hint.Thread := ThreadItem;
1351             ResLink.FBbs := ThreadItem.ParentBoard.BBSID;
1352             ResLink.FKey := ChangeFileExt(ThreadItem.FileName, '');
1353             //if ThreadItem.IsBoardPlugInAvailable then begin
1354             if ThreadItem.ParentBoard.IsBoardPlugInAvailable then begin
1355                 //===== \83v\83\89\83O\83C\83\93\82É\82æ\82é\95\\8e¦
1356                 //boardPlugIn           := ThreadItem.BoardPlugIn;
1357                 boardPlugIn             := ThreadItem.ParentBoard.BoardPlugIn;
1358
1359                 // \83t\83H\83\93\83g\82â\83T\83C\83Y\82Ì\90Ý\92è
1360                 // \95\8e\9a\83R\81[\83h\82Í\83v\83\89\83O\83C\83\93\82É\94C\82¹\82é
1361                 for i := StNum to ToNum do begin
1362                     Line := i;
1363                                         //\82±\82±\82Å\82Q\82¿\82á\82ñ\82Ë\82é\82Ìdat\82Ì\8c`\8e®\82Å\82P\8ds\93Ç\82Ý\8d\9e\82ß\82ê\82Î¥¥¥\81B\81«\93Ç\82ß\82é\82æ\82¤\82É\82È\82Á\82½
1364                                         tmp := boardPlugIn.GetDat( DWORD( threadItem ), i );
1365                     if (tmp <> '') And ( not GikoSys.FAbon.CheckAbonPopupRes(tmp, ThreadInfo) And( not GikoSys.FAbon.CheckIndividualAbonList(line))) then begin
1366                         Html.Add(GetResString(Line-1, tmp, @ResLink));
1367                                         end;
1368                                 end;
1369                         end else begin
1370                 ThreadInfo.Is2ch  := ThreadItem.ParentBoard.Is2ch;
1371                 ThreadInfo.Board  := ThreadItem.ParentBoard.BBSID;
1372                 ThreadInfo.Thread := ChangeFileExt(ThreadItem.FileName, '');
1373                                 for i := StNum to ToNum do begin
1374                                         Line := i;
1375                                         FileName := ThreadItem.FilePath;
1376                                         tmp := GikoSys.ReadThreadFile(FileName, Line);
1377                                         if (tmp <> '') And ( not GikoSys.FAbon.CheckAbonPopupRes(tmp, ThreadInfo) And( not GikoSys.FAbon.CheckIndividualAbonList(line))) then begin
1378                                                 Html.Add(GetResString(Line-1, tmp, @ResLink));
1379                                         end;
1380                                 end;
1381                         end;
1382             if (Html.Count > 0) then begin
1383                 Hint.RawDocument := '<DL>' + Html.Text + '</DL>';
1384             end;
1385             ThreadInfo.Free;
1386                 end;
1387         finally
1388         Html.Free;
1389         end;
1390 end;
1391
1392 //\83\8a\83\93\83N\82Ì\95\8e\9a\97ñ\82©\82ç\83\8c\83X\83|\83b\83v\83A\83b\83v\97p\82ÌURL\82É\95Ï\8a·\82·\82é
1393 class function THTMLCreate.GetRespopupURL(AText, AThreadURL : string): string;
1394 var
1395         wkInt: Integer;
1396 begin
1397         Result := '';
1398         if Pos('about:blank..', AText) = 1 then begin
1399                 wkInt := LastDelimiter( '/', AThreadURL );
1400                 if Pos( '?', Copy( AThreadURL, wkInt, MaxInt ) ) = 0 then begin
1401                         // Thread.URL \82Í PATH_INFO \93n\82µ
1402                         Result := Copy( AThreadURL, 1,  LastDelimiter( '/', AThreadURL ) );
1403                         wkInt := LastDelimiter( '/', AText );
1404                         if Pos( '?', Copy( AText, wkInt, MaxInt ) ) = 0 then
1405                                 // Text \82à PATH_INFO \93n\82µ
1406                                 Result := Result + Copy( AText, LastDelimiter( '/', AText ) + 1, MaxInt )
1407                         else
1408                                 // Text \82Í QUERY_STRING \93n\82µ
1409                                 Result := Result + Copy( AText, LastDelimiter( '?', AText ) + 1, MaxInt );
1410                 end else begin
1411                         // Thread.URL \82Í QUERY_STRING \93n\82µ
1412                         Result := Copy( AThreadURL, 1,  LastDelimiter( '?', AThreadURL ) );
1413                         wkInt := LastDelimiter( '/', AText );
1414                         if Pos( '?', Copy( AText, wkInt, MaxInt ) ) = 0 then begin
1415                                 // Text \82Í PATH_INFO \93n\82µ
1416                                 // URL \82É\94Â\82Æ\83L\81[\82ª\91«\82ç\82È\82¢\82Ì\82Å Text \82©\82ç\92¸\91Õ\82·\82é
1417                                 wkInt := LastDelimiter( '/', Copy( AText, 1, wkInt - 1 ) );
1418                                 wkInt := LastDelimiter( '/', Copy( AText, 1, wkInt - 1 ) );
1419                                 Result := Copy( Result, 1, Length( Result ) - 1 ) + Copy( AText, wkInt, MaxInt );
1420                         end else begin
1421                                 // Text \82à QUERY_STRING \93n\82µ
1422                                 Result := Result + Copy( AText, LastDelimiter( '?', AText ) + 1, MaxInt )
1423                         end;
1424                 end;
1425         end else if Pos('about:blank/bbs/', AText) = 1 then begin
1426                 //\82µ\82½\82ç\82ÎJBBS\82Ì\8ed\95Ï\82Ì\8bz\8eû
1427                 AText := CustomStringReplace(AText, 'about:blank/bbs/', 'about:blank../../bbs/');
1428                 Result := GetRespopupURL(AText, AThreadURL);
1429         end else begin
1430                 Result := AText;
1431         end;
1432
1433 end;
1434 //\8ew\92è\82µ\82½\83p\83X\82É\83X\83L\83\93\82à\82µ\82­\82ÍCSS\82Ì\83t\83@\83C\83\8b\82Ì\83R\83s\81[\82ð\8dì\82é
1435 class procedure THTMLCreate.SkinorCSSFilesCopy(path: string);
1436 var
1437         tmp, tmpD, tmpF: string;
1438         current: string;
1439         dirs: TStringList;
1440         files: TStringList;
1441         i, j: Integer;
1442 begin
1443         if GikoSys.Setting.UseSkin then begin
1444                 current := ExtractFilePath(GikoSys.GetSkinDir);
1445                 tmp := GikoSys.Setting.CSSFileName;
1446         end else if GikoSys.Setting.UseCSS then begin
1447                 current := ExtractFilePath(GikoSys.GetStyleSheetDir);
1448                 tmp := ExtractFilePath(GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName);
1449         end else begin
1450         Exit;
1451     end;
1452         dirs := TStringList.Create;
1453         try
1454                 dirs.Add(tmp);
1455                 if tmp <> current then begin
1456                         GikoSys.GetDirectoryList(current, '*.*', dirs, true);
1457                         for i := 0 to dirs.Count - 1 do begin
1458                                 files := TStringList.Create;
1459                                 try
1460                                         files.BeginUpdate;
1461                                         gikoSys.GetFileList(dirs[i], '*.*', files, true);
1462                                         files.EndUpdate;
1463                                         tmpD := CustomStringReplace(dirs[i], GikoSys.GetConfigDir, path);
1464                                         if (AnsiPos(dirs[i], tmp) <> 0) and not (DirectoryExists(tmpD)) then
1465                                                 ForceDirectories(tmpD);
1466
1467                                         if(dirs[i] = tmp) and (dirs[i] <> current) then begin
1468                                                 for j := 0 to files.Count - 1 do begin
1469                                                         tmpF := CustomStringReplace(files[j], GikoSys.GetConfigDir, path);
1470                                                         if not FileExists(tmpF) then begin
1471                                                                 CopyFile(PChar(files[j]), PChar(tmpF),True);
1472                                                         end;
1473                                                 end;
1474                                         end;
1475                                 finally
1476                                         files.Free;
1477                                 end;
1478                         end;
1479                 end else begin
1480                         tmpD := CustomStringReplace(dirs[0], GikoSys.GetConfigDir, path);
1481                         if not DirectoryExists(tmpD) then
1482                                 ForceDirectories(tmpD);
1483                         tmpF := CustomStringReplace(GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName
1484                                         , GikoSys.GetConfigDir, path);
1485                         if not FileExists(tmpF) then begin
1486                                 CopyFile(PChar(GikoSys.GetStyleSheetDir + GikoSys.Setting.CSSFileName)
1487                                         , PChar(tmpF), True);
1488                         end;
1489                 end;
1490         finally
1491                 dirs.Free;
1492         end;
1493 end;
1494 {!
1495 \brief dat\83t\83@\83C\83\8b\82Ì\88ê\83\89\83C\83\93\82ð\95ª\89ð
1496 \param Line dat\83t\83@\83C\83\8b\82ð\8d\\90¬\82·\82é 1 \8ds
1497 \return     \83\8c\83X\8fî\95ñ
1498 }
1499 class procedure THTMLCreate.DivideStrLine(Line: string; PRes: PResRec);
1500 const
1501         delimiter = '<>';
1502 var
1503         pds, pde : PChar;
1504         pss, pse : PChar;
1505         ppos : PChar;
1506 begin
1507         //\8cÅ\92è
1508         PRes.FType := glt2chNew;
1509
1510         pss := PChar(Line);
1511         pse := pss + Length(Line);
1512         pds := PChar(delimiter);
1513         pde := pds + Length(delimiter);
1514
1515         ppos := AnsiStrPosEx(pss, pse, pds, pde);
1516         if (ppos = nil) then begin
1517                 Line := CustomStringReplace(Line, '<>', '&lt;&gt;');
1518                 Line := CustomStringReplace(Line, ',', '<>');
1519                 Line := CustomStringReplace(Line, '\81\97\81M', ',');
1520         end;
1521         //Trim\82µ\82Ä\82Í\82¢\82¯\82È\82¢\8bC\82ª\82·\82é\81@by\82à\82\82ã
1522         PRes.FName := MojuUtils.RemoveToken(Line, delimiter);
1523         PRes.FMailTo := MojuUtils.RemoveToken(Line, delimiter);
1524         PRes.FDateTime := MojuUtils.RemoveToken(Line, delimiter);
1525         PRes.FBody := MojuUtils.RemoveToken(Line, delimiter);
1526         //\82Q\82¿\82á\82ñ\82Ë\82é\82Æ\82©\82¾\82Æ\81A\96{\95\82Ì\90æ\93ª\82É\82P\82Â\94¼\8ap\8bó\94\92\82ª\93ü\82Á\82Ä\82¢\82é\82Ì\82Å\8dí\8f\9c\82·\82é
1527         //\91¼\82Ì\8cf\8e¦\94Â\82Å\81A\83\8c\83X\8e©\91Ì\82Ì\8bó\94\92\82©\82à\82µ\82ê\82È\82¢\82¯\82Ç\82»\82ê\82Í\92ú\82ß\82é
1528         PRes.FBody := TrimLeft(PRes.FBody);
1529         //\8bó\82¾\82Æ\96â\91è\82ª\8bN\82«\82é\82©\82ç\81A\8bó\94\92\82ð\90Ý\92è\82·\82é
1530         if PRes.FBody = '' then
1531                 PRes.FBody := '&nbsp;';
1532
1533         PRes.FTitle := MojuUtils.RemoveToken(Line, delimiter);
1534 end;
1535
1536 {!
1537 \brief HTML \82©\82ç\83A\83\93\83J\81[\83^\83O\82ð\8dí\8f\9c
1538 \param s \8c³\82É\82È\82é HTML
1539 \return  \83A\83\93\83J\81[\83^\83O\82ª\8dí\8f\9c\82³\82ê\82½ HTML
1540 }
1541 class function THTMLCreate.DeleteLink(const s: string): string;
1542 var
1543         s1: string;
1544     mark: string;
1545         idx: Integer;
1546 begin
1547     mark := '<a href="';
1548     Result := '';
1549     s1 := s;
1550     idx := AnsiPos(mark, s1);
1551     while idx <> 0 do begin
1552         Result := Result + Copy(s1, 1, idx - 1);
1553         Delete(s1, 1, idx);
1554         // \83^\83O\82Ì\83G\83\93\83h\82ð\92T\82·
1555         idx := AnsiPos('">', s1);
1556         if idx <> 0 then begin
1557             Delete(s1, 1, idx + 1);
1558         end;
1559         // </a> \82Ü\82Å
1560         idx := AnsiPos('</a>', s1);
1561         if idx <> 0 then begin
1562             Result := Result + Copy(s1, 1, idx - 1);
1563             Delete(s1, 1, idx + 3);
1564         end;
1565         idx := AnsiPos(mark, s1);
1566     end;
1567
1568     Result := Result + s1;
1569 end;
1570 {
1571 \brief  HTML\89»\82Ì\82½\82ß\82Ì\92u\8a·
1572 \param  s   \8c³\82É\82È\82é\95\8e\9a\97ñ
1573 \return HTML\82ÌinnerText\82Æ\82µ\82Ä\82ä\82é\82³\82ê\82é\95\8e\9a\97ñ
1574 }
1575 class function THTMLCreate.RepHtml(const s: string): string;
1576 begin
1577 //      s := StringReplace(s, '&', '&amp;', [rfReplaceAll]);
1578     Result := s;
1579         Result := CustomStringReplace(Result, '<', '&lt;');
1580         Result := CustomStringReplace(Result, '>', '&gt;');
1581 //      s := StringReplace(s, ' ', '&nbsp;', [rfReplaceAll]);   //\8ed\97l\95Ï\8dX\82É\82æ\82è&nbsp;\8eg\97p\95s\89Â
1582         Result := CustomStringReplace(Result, '"', '&quot;');
1583 end;
1584 {
1585 \brief  \83\8c\83X\83G\83f\83B\83^\82Å\82Ì\83v\83\8c\83r\83\85\81[\97pHTML\8dì\90¬
1586 \param  Title   \83X\83\8c\83b\83h\83^\83C\83g\83\8b
1587 \param  No  \83\8c\83X\94Ô\8d\86
1588 \param  Mail    \83\81\81[\83\8b\97\93
1589 \param  Name    \96¼\91O\97\93
1590 \param  Body    \96{\95
1591 \return \83v\83\8c\83r\83\85\81[\97pHTML
1592 }
1593 class function THTMLCreate.CreatePreviewHTML(
1594         const Title: string;
1595         const No: string;
1596         const Mail: string;
1597         const Namae: string;
1598         const Body: string
1599 ) : string;
1600 var
1601     posTrip : Integer;
1602     tripOrigin : string;
1603     NameWithTrip: string;
1604     DateTime: string;
1605 begin
1606         Result := '<HTML><HEAD>'#13#10
1607                         + '<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">'#13#10
1608                         + '<TITLE>' + title + '</TITLE>'#13#10
1609                         + '</HEAD>'#13#10
1610                         + '<BODY text="#000000" bgcolor="#EFEFEF" link="#0000FF" alink="#FF0000" vlink="#660099">'#13#10
1611                         + '<FONT COLOR="#FF0000">' + title + '</FONT>'#13#10
1612                         + '<DL>'#13#10;
1613
1614         DateTime := FormatDateTime('yyyy/mm/dd(aaa) hh:nn', Now());
1615
1616     NameWithTrip := Namae;
1617     posTrip := AnsiPos( '#', Namae );
1618     if posTrip > 0 then begin
1619         tripOrigin := Copy( Namae, posTrip + 1, Length( Namae ) );
1620         NameWithTrip := Copy( Namae, 1, posTrip - 1 ) + '</B> \81\9f' +
1621                     get_2ch_trip( PChar( tripOrigin ) ) + '<B>';
1622     end;
1623     if Mail = '' then begin
1624         Result := Result + '<DT>' + No + ' \81F <FONT color="forestgreen"><B>' + NameWithTrip
1625                  + '</B></FONT> \81F ' + DateTime+ '<BR><DD>' + Body + '<BR><BR><BR>' + #13#10
1626     end else begin
1627                 Result := Result + '<DT>' + No + ' \81F <A href="mailto:' + Mail + '"><B>' + NameWithTrip
1628                  + '</B></A> [' + Mail + ']\81F ' + DateTime+ '<BR><DD>' + Body + '<BR><BR><BR>' + #13#10;
1629     end;
1630         Result := Result + '</BODY></HTML>';
1631
1632 end;
1633 {
1634 \brief  \95\\8e¦\94Í\88Í\8aO\83\8c\83X\94Ô\8d\86\94»\92è\8f\88\97\9d
1635 \param  item    \95\\8e¦\83X\83\8c\83b\83h
1636 \param  index   \83\8c\83X\94Ô\8d\86
1637 \return ture:\95\\8e¦\94Í\88Í\8aO false:\95\\8e¦\94Í\88Í\93à
1638 }
1639 function THTMLCreate.isOutsideRange( item: TThreadItem; index: Integer ): Boolean;
1640 begin
1641     Result := False;
1642     // \95\\8e¦\94Í\88Í\82ð\8cÀ\92è
1643     case GikoSys.ResRange of
1644     Ord( grrKoko ):
1645         if item.Kokomade > (index + 1) then
1646             Result := True;
1647     Ord( grrNew ):
1648         if item.NewReceive > (index + 1) then
1649             Result := True;
1650     10..65535:
1651         if (GikoSys.Setting.HeadResCount) < (index + 1)  then begin
1652             if (item.Count - index) > GikoSys.ResRange then begin
1653                 Result := True;
1654             end;
1655         end;
1656     end;
1657 end;
1658 constructor TBufferedWebBrowser.Create(Browser: TWebBrowser; BuffSize: Integer);
1659 begin
1660         inherited Create;
1661         Self.Sorted := False;
1662         if (Browser = nil) then
1663                 Raise  Exception.Create('Browser is NULL');
1664         FBrowser := Browser;
1665
1666         // \83o\83b\83t\83@\82·\82é\8ds\90\94\82ð
1667         if (BuffSize < 0) then begin
1668                 FBuffSize := 100;
1669         end else begin
1670                 FBuffSize := BuffSize;
1671         end;
1672         Self.Capacity := FBuffSize + 10;
1673 end;
1674 procedure TBufferedWebBrowser.Open;
1675 begin
1676         FBrowserDoc := FBrowser.ControlInterface.Document;
1677         FBrowserDoc.open;
1678         FBrowserDoc.charset := 'Shift_JIS';
1679 end;
1680 procedure TBufferedWebBrowser.Close;
1681 begin
1682         Self.Flush;
1683         try
1684                 FBrowserDoc.Close;
1685         except
1686         end;
1687         FBrowser := nil;
1688 end;
1689 function TBufferedWebBrowser.Add(const S: string): Integer;
1690 begin
1691         Result := inherited Add(TrimRight(s));
1692         if (Self.Count > FBuffSize) then begin
1693                 FBrowserDoc.Write(Self.Text);
1694                 Self.Clear;
1695         end;
1696 end;
1697 procedure TBufferedWebBrowser.Flush ;
1698 begin
1699         if (Self.Count > 0) then begin
1700                 FBrowserDoc.Write(Self.Text);
1701                 Self.Clear;
1702         end;
1703 end;
1704 destructor TBufferedWebBrowser.Destory;
1705 begin
1706         try
1707                 if (FBrowserDoc <> 0) then begin
1708                         FBrowserDoc.close;
1709                         FBrowserDoc := 0;
1710                 end;
1711         except
1712         end;
1713         inherited;
1714 end;
1715 //! \8aÖ\98A\83L\81[\83\8f\81[\83h\83\8a\83\93\83N\8fo\97Í
1716 function THTMLCreate.getKeywordLink(item: TThreadItem): String;
1717 const
1718     PARA_URL = 'http://p2.2ch.io/getf.cgi?';
1719 begin
1720     Result := '';
1721     if (GikoSys.Setting.AddKeywordLink) and (item.ParentBoard.Is2ch) then begin
1722         Result := '<p><span id="keyword"><a href="' + PARA_URL
1723             + item.URL + '" target="_blank">\8aÖ\98A\83L\81[\83\8f\81[\83h</a></span></p>';
1724     end;
1725 end;
1726 initialization
1727          HTMLCreater := THTMLCreate.Create;
1728
1729 finalization
1730         if HTMLCreater <> nil then begin
1731                 FreeAndNil(HTMLCreater);
1732         end;
1733
1734 end.