OSDN Git Service

6af7074d745dc3742fea9ca084e427d5e264aeb1
[winbottle/svg-dll.git] / SVG.dpr
1 {
2 SSTP Bottle Surface Preview Plug-In for "SVG"
3 (C)2003 naru, Mikage Sawatari / SSTP Bottle
4 }
5
6 library SVG;
7
8 {$R *.res}
9
10 uses
11   Windows, Classes, SysUtils, Graphics, IniFiles, Dialogs, PngImage, jpeg;
12
13 const
14   SurfaceWidth  = 48;
15   SurfaceHeight = 64;
16   ConfigFile = 'SVG.ini';
17
18 var
19   MyPath: String;
20   GhostFile: String;
21   Ghost2File: TStringList;
22
23   Pic: TPicture;       // \93Ç\82Ý\8eæ\82Á\82½\89æ\91\9c(*.png, *.bmp, *.jpg)
24   PicFileName: String; // \82»\82Ì\83t\83@\83C\83\8b\96¼
25
26 // DLL\83\8d\81[\83h\8e\9e\81A\82¨\82æ\82ÑDLL\8dÄ\8f\89\8aú\89»\8e\9e\82É\8cÄ\82Î\82ê\82é\81B
27 // \93Ç\82Ý\8d\9e\82Ü\82ê\82½\89æ\91\9c\82Í\81ABottle Client\91¤\82Å\81u\83T\81[\83t\83B\83X\8dÄ\93Ç\82Ý\8d\9e\82Ý\81v\82ð
28 // \96¾\8e¦\93I\82É\8ew\92è\82³\82ê\82È\82¢\8cÀ\82è\82Í Bottle Client \91¤\82Å\83L\83\83\83b\83V\83\85\82³\82ê\82é\82Ì\82Å\81A
29 // DLL\82Å\89æ\91\9c\82Ì\83L\83\83\83b\83V\83\85\82È\82Ç\82ð\8dl\82¦\82é\95K\97v\82Í\8aî\96{\93I\82É\82È\82¢\81B
30 // \82Æ\82Í\82¢\82¦\83T\81[\83t\83B\83X\92è\8b`\83t\83@\83C\83\8b\82È\82Ç\82ð\90æ\82É\89ð\90Í\82µ\82Ä\82¨\82­\95K\97v\82ª\82 \82é\82È\82ç\81A
31 // \82±\82±\82Å\93Ç\82Ý\8d\9e\82ñ\82Å\82¨\82­\82Æ\97Ç\82¢\81BPath\82ÉDLL\82Ì\83p\83X\82ª\93n\82³\82ê\82é\81B
32 procedure Load(Path: PChar); cdecl;
33 var Ini: TIniFile;
34 begin
35   MyPath := Path;
36   Ini := TIniFile.Create(MyPath + ConfigFile);
37   try
38     GhostFile := Ini.ReadString('SVG', 'GhostFile', '');
39   finally
40     Ini.Free;
41   end;
42   if not FileExists(GhostFile) then
43     ShowMessage('SVG.dll Warning: Ghost file is not specified');
44   Ghost2File := TStringList.Create;
45   Pic := TPicture.Create;
46   PicFileName := '';
47 end;
48
49 // DLL\83A\83\93\83\8d\81[\83h\8e\9e\82É\8cÄ\82Î\82ê\82é\81B
50 // \82½\82Ô\82ñ\82â\82é\82±\82Æ\82Í\82È\82¢\81B
51 procedure Unload; cdecl;
52 begin
53   Ghost2File.Free;
54   Pic.Free;
55 end;
56
57 // DLL\82Ì\96¼\91O\82¨\82æ\82Ñ\83o\81[\83W\83\87\83\93\82ð\95Ô\82·\81B
58 // DLLName\82É\82ÍDLL\82Ì\96¼\8fÌ\82â\8dì\8eÒ\81ADLL\96{\91Ì\82Ì\83o\81[\83W\83\87\83\93\82È\82Ç\82ð\82ð\8aÈ\8c\89\82É\8ew\92è\82·\82é\81B
59 // NameLen\83o\83C\83g\82ð\92´\82¦\82Ä\82Í\82È\82ç\82È\82¢\81B
60 // version\82É\82Í\82Æ\82è\82 \82¦\82¸1\82ð\95Ô\82·\82±\82Æ\81Bversion\82ÍSSTP Bottle Client\82Æ\82Ì
61 // \92Ê\90M\82Ì\83C\83\93\83^\81[\83t\83F\81[\83X\82Ì\83o\81[\83W\83\87\83\93\82Å\82 \82Á\82ÄDLL\82Ì\83o\81[\83W\83\87\83\93\82Æ\82©\82Å\82Í\82È\82¢\82±\82Æ\82É
62 // \92\8d\88Ó(Bottle Client\82ÍDLL\82Ì\83o\81[\83W\83\87\83\93\94Ô\8d\86\82È\82¼\8b»\96¡\82È\82¢\82Ì\82Å)\81B
63 // CanConfigure\82Í\81AConfigure\82ð\8cÄ\82Î\82ê\82Ä\82â\82é\82±\82Æ\82ª\82 \82é\82©\82Ç\82¤\82©\82ð\95Ô\82·\81B
64 function GetVersion(DLLName: PChar; NameLen: integer;
65   var Version: integer; var CanConfigure: boolean): integer; cdecl;
66 const ThisDLL = 'SVG Surface Loader Ver. 2.2';
67 begin
68   Version := 1;
69   CanConfigure := true;
70   StrLCopy(DLLName, ThisDLL, NameLen);
71   Result := Length(ThisDLL) + 1;
72 end;
73
74 function LoadDefinitionFileVer2(Ghost: String;
75   Surface: integer; Lines: TStringList; const FileName: String;
76   out Pos: integer): String;
77 var ALine, SurfaceMap: TStringList;
78     i, j, p, sur, oldpos: integer;
79     posstr: String;
80 begin
81   // \93à\95\94\8aÖ\90\94\81B\83S\81[\83X\83g\92è\8b`\83t\83@\83C\83\8b\82ð\89ð\90Í\82µ\82Ä\81A
82   // \96Ú\93I\82Ì\83S\81[\83X\83g\82Ì\8aÜ\82Ü\82ê\82½\83t\83@\83C\83\8b\82©\82Ç\82¤\82©\94»\92f\82·\82é
83   ALine := TStringList.Create;
84   try
85     ALine.CommaText := Lines[0];
86     if (ALine[0] <> 'GHOST') then
87       Exit;
88     if (ALine[1] <> Ghost) then
89     begin
90       Ghost2File.Values[Ghost] := FileName; // \8e\9f\82©\82ç\82Ì\83V\83\87\81[\83g\83J\83b\83g
91       Exit;
92     end;
93
94     // \96Ú\93I\82Ì\83S\81[\83X\83g\94­\8c©
95     oldpos := 0;
96     SurfaceMap := TStringList.Create;
97     try
98       for i := 1 to Lines.Count-1 do
99       begin
100         SurfaceMap.CommaText := Lines[i];
101         for j := 0 to SurfaceMap.Count-1 do
102         begin
103           try
104             p := System.Pos(':', SurfaceMap[j]);
105             if p = 0 then
106               Continue;
107             sur := StrToInt(Copy(SurfaceMap[j], 1, p-1));
108             posstr := Copy(SurfaceMap[j], p+1, High(integer));
109             if posstr = '+' then
110               Pos := oldpos + 1
111             else
112               Pos := StrToInt(posstr);
113             if sur = Surface then
114             begin
115               Result := ALine[4]; // BMP\83t\83@\83C\83\8b\96¼
116               Exit;
117             end else
118               oldpos := Pos;
119           except
120             on EConvertError do; // nothing. \92P\82È\82é\83R\83\81\83\93\83g\8ds\88µ\82¢
121           end;
122         end;
123       end;
124     finally
125       SurfaceMap.Free;
126     end;
127
128     // BASIC\82Ì\8fê\8d\87\82Ì\8f\88\97\9d
129     if AnsiCompareText('BASIC', ALine[3]) = 0 then
130     begin
131       if (Surface >= 0) and (Surface <= 11) then
132       begin
133         Result := ALine[4]; // BMP\83t\83@\83C\83\8b\96¼
134         Pos := Surface; // BASIC\82Ì\8fê\8d\87\82Í\88Ê\92u\82Æ\83T\81[\83t\83B\83X\94Ô\8d\86\82ª\88ê\91Î\88ê\91Î\89\9e\82µ\82Ä\82¢\82é
135         Exit;
136       end;
137     end;
138
139   finally
140     ALine.Free;
141   end;
142 end;
143
144 procedure ParseKeyVal(const Line: String; out Key, Val: String);
145 var p: integer;
146 begin
147   p := Pos('=', Line);
148   if p > 0 then
149   begin
150     Key := Copy(Line, 1, p-1);
151     Val := AnsiDequotedStr(Copy(Line, p+1, High(integer)), '"');
152   end else begin
153     Key := '';
154     Val := Line;
155   end;
156 end;
157
158 function LoadDefinitionFileVer3(Ghost: String;
159   Surface: integer; Lines: TStringList; const FileName: String;
160   out Pos: integer): String;
161 var i, j, k, smin, smax, oldsur: integer;
162     Key, Val, SurStr, PosStr, SakuraName: String;
163     Dat, Sur2Pos: TStringList;
164 begin
165   oldsur := -1;
166   Sur2Pos := TStringList.Create;
167   try
168     for i := 1 to Lines.Count-1 do // 1\8ds\96Ú\82Í"SVG"\82Ì\95\8e\9a\97ñ
169     begin
170       ParseKeyVal(Lines[i], Key, Val);
171       if SameText(Key, 'sakura') then
172       begin
173         SakuraName := Val;
174         if SakuraName <> Ghost then //\95Ê\83S\81[\83X\83g\82Ì\92è\8b`\83t\83@\83C\83\8b\82È\82Ì\82Å\83p\83X
175         begin
176           Ghost2File.Values[SakuraName] := FileName; //\8e\9f\82©\82ç\82Ì\83V\83\87\81[\83g\83J\83b\83g
177           Exit;
178         end;
179       end else if SameText(Key, 'surfacefile') then
180       begin
181         Result := Val;
182       end else if SameText(Key, 'surface') or (Length(Key) = 0) then
183       begin
184         // \83T\81[\83t\83B\83X
185         Dat := TStringList.Create;
186         try
187           Dat.CommaText := Val;
188           for j := 0 to Dat.Count-1 do
189           begin
190             if System.Pos(':', Dat[j]) <= 0 then
191               Continue;
192             SurStr := Copy(Dat[j], 1, System.Pos(':', Dat[j])-1);
193             PosStr := Copy(Dat[j], System.Pos(':', Dat[j])+1, High(integer));
194             try
195               if System.Pos('-', SurStr) > 0 then
196               begin
197                 smin := StrToInt(Copy(SurStr, 1, System.Pos('-', SurStr)-1));
198                 smax := StrToInt(Copy(SurStr, System.Pos('-', SurStr)+1, High(integer)));
199               end else
200               begin
201                 smin := StrToInt(SurStr);
202                 smax := smin;
203               end;
204               for k := smin to smax do
205               begin
206                 if PosStr = '*' then
207                 begin
208                   Sur2Pos.Values[IntToStr(k)] := IntToStr(k);
209                   oldsur := k;
210                 end else if PosStr = '-2' then
211                 begin
212                   Sur2Pos.Values[IntToStr(k)] := '' // \92è\8b`\89ð\8f\9c
213                 end else if PosStr = '+' then
214                 begin
215                   Inc(oldsur);
216                   Sur2Pos.Values[IntToStr(k)] := IntToStr(oldsur);
217                 end else if StrToInt(PosStr) >= 0 then
218                 begin
219                   Sur2Pos.Values[IntToStr(k)] := PosStr;
220                   oldsur := StrToInt(PosStr);
221                 end;
222               end;
223             except
224               Continue;
225             end;
226           end;
227         finally
228           Dat.Free;
229         end;
230       end;
231     end;
232     // ShowMessage(Sur2Pos.Text);
233     if SakuraName <> Ghost then //sakura=??\82Ì\8ew\92è\82ª\94²\82¯\82Ä\82¢\82é\92è\8b`\83t\83@\83C\83\8b\82Ì\8fê\8d\87
234       Result := ''
235     else
236     begin
237       if Sur2Pos.Values[IntToStr(Surface)] <> '' then
238         Pos := StrToInt(Sur2Pos.Values[IntToStr(Surface)])
239       else
240         Result := '';
241     end;
242   finally
243     Sur2Pos.Free;
244   end;
245 end;
246
247
248 function LoadDefinitionFile(Ghost: String;
249   Surface: integer; FileName: String; out Pos: integer): String;
250 var Lines: TStringList;
251 begin
252   Lines := TStringList.Create;
253   Lines.LoadFromFile(FileName);
254   try
255     if System.Pos('SVG3', Lines[0]) > 0 then
256       Result := LoadDefinitionFileVer3(Ghost, Surface, Lines, FileName, Pos)
257     else
258       Result := LoadDefinitionFileVer2(Ghost, Surface, Lines, FileName, Pos);
259   finally
260     Lines.Free;
261   end;
262 end;
263
264 function FetchBmpFileAndPosition(Ghost: String;
265   Surface: integer; out Pos: integer): String;
266 var Ghosts, AGhost: TStringList;
267     i, dum: integer;
268     Dir, DefFileName, BmpFileName: String;
269 begin
270   Result := '';
271   if Ghost2File.Values[Ghost] <> '' then // \82·\82Å\82É\82»\82Ì\83S\81[\83X\83g\82É\82Â\82¢\82Ä\92²\8d¸\8dÏ\82Ý
272   begin
273     DefFileName := Ghost2File.Values[Ghost];
274     if DefFileName = '*' then // \82»\82Ì\83S\81[\83X\83g\82Í\92m\82ç\82È\82¢\81A\82Æ\8bL\89¯\82µ\82Ä\82¢\82é
275     begin
276       Exit;
277     end else // \82»\82Ì\83S\81[\83X\83g\82ð\92m\82Á\82Ä\82¢\82é
278     begin
279       BmpFileName := LoadDefinitionFile(Ghost, Surface,
280         DefFileName, dum);
281       if BmpFileName <> '' then
282       begin
283         Result := ExtractFilePath(DefFileName) + BmpFileName;
284         Pos := dum;
285         Exit;
286       end;
287     end;
288   end;
289
290   // \93à\95\94\8aÖ\90\94\81Bghost.txt\82ð\93Ç\82Ý\8d\9e\82Þ\81B
291   Dir := ExtractFilePath(GhostFile);
292   Ghosts := TStringList.Create;
293   try
294     Ghosts.LoadFromFile(GhostFile);
295     AGhost := TStringList.Create;
296     try
297       for i := 0 to Ghosts.Count-1 do
298       begin
299         AGhost.CommaText := Ghosts[i];
300         if AGhost[0] <> 'GHOST' then
301           Continue;
302         DefFileName := Dir + AGhost[3];
303         // \92è\8b`\83t\83@\83C\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ
304         BmpFileName := LoadDefinitionFile(Ghost, Surface,
305           DefFileName, dum);
306         if BmpFileName <> '' then
307         begin
308           Result := ExtractFilePath(DefFileName) + BmpFileName;
309           Pos := dum;
310           Break;
311         end;
312       end;
313     finally
314       AGhost.Free;
315     end;
316   finally
317     Ghosts.Free;
318   end;
319   if Result = '' then
320     Ghost2File.Values[Ghost] := '*'; // \83S\81[\83X\83g\82ª\8c©\82Â\82©\82ç\82È\82©\82Á\82½\8c\8b\89Ê\82ð\8bL\89¯
321 end;
322
323 // Ghost\82Å\8ew\92è\82³\82ê\82é\83S\81[\83X\83g\82ÌSurface\94Ô\82Ì\83T\81[\83t\83B\83X\83C\83\81\81[\83W\82ð\8eÀ\8dÛ\82É\93Ç\82Ý\8fo\82·\81B
324 // H\82Å\8ew\92è\82³\82ê\82Ä\82¢\82é\83r\83b\83g\83}\83b\83v\82É\8f\91\82«\8fo\82·\82±\82Æ\81B
325 function GetImage(Ghost: PChar; Surface: integer; H: HBITMAP): integer; cdecl;
326 var Bmp: TBitmap;
327     BmpFile: String;
328     Position, x, y, nCol: integer;
329 begin
330   try
331     BmpFile := FetchBmpFileAndPosition(Ghost, Surface, Position);
332     if BmpFile = '' then // \82»\82Ì\82æ\82¤\82È\83S\81[\83X\83g\82Ì\82»\82Ì\82æ\82¤\82È\83T\81[\83t\83B\83X\82Í\8c©\82Â\82©\82ç\82È\82¢
333     begin
334       Result := 1;
335       Exit;
336     end;
337     Bmp := TBitmap.Create;
338     try
339       Bmp.Handle := H;
340       if PicFileName <> BmpFile then
341       begin
342         try
343           Pic.LoadFromFile(BmpFile);
344           PicFileName := BmpFile;
345         except
346           // \8dì\82è\92¼\82µ
347           FreeAndNil(Pic);
348           Pic := TPicture.Create;
349           PicFileName := '';
350           raise;
351         end;
352       end;
353       nCol := Pic.Width div SurfaceWidth;
354       x := SurfaceWidth * (Position mod nCol);
355       y := SurfaceHeight * (Position div nCol);
356       Bmp.Canvas.Draw(-x, -y, Pic.Graphic);
357     finally
358       Bmp.ReleaseHandle;
359       Bmp.Free;
360     end;
361     Result := 0;
362   except
363     Result := 1;
364   end;
365 end;
366
367 // \83C\83\81\81[\83W\82Ì\91å\82«\82³\82ð\95Ô\82·\81B
368 // \91å\92ï\82Ì\8fê\8d\87\83C\83\81\81[\83W\82Ì\91å\82«\82³\82Í\82à\82Æ\82©\82ç\95ª\82©\82Á\82Ä\82¢\82é\82Æ\8ev\82¤\82Ì\82Å\81A
369 // \82»\82ê\82È\82ç\92P\8f\83\82É\92è\90\94\82ð\95Ô\82µ\82Ä\8d·\82µ\8ex\82¦\82È\82¢\81B
370 // \83C\83\81\81[\83W\82Ì\91å\82«\82³\82ª\83S\81[\83X\83g\82â\83T\81[\83t\83B\83X\94Ô\8d\86\82É\82æ\82Á\82Ä\95Ï\82í\82é\82È\82ç\82»\82Ì\82æ\82¤\82É\81B
371 function GetImageSize(Ghost: PChar; Surface: integer;
372   var w, h: integer): integer; cdecl;
373 begin
374   w := SurfaceWidth;
375   h := SurfaceHeight;
376   Result := 0;
377 end;
378
379
380 // DLL\8cÅ\97L\82Ì\90Ý\92è\82ð\8ds\82¤\81B
381 //
382 procedure Configure; cdecl;
383 var OpenDialog: TOpenDialog;
384     Ini: TIniFile;
385 begin
386   try
387     ShowMessage('Specify SSTP Viewer''s ghost file.');
388     OpenDialog := TOpenDialog.Create(nil);
389     try
390       OpenDialog.Filter := 'Ghost Definition File(ghost.txt)|ghost.txt|' +
391        'All Files(*.*)|*.*';
392       OpenDialog.FileName := GhostFile;
393       if OpenDialog.Execute then
394       begin
395         GhostFile := OpenDialog.FileName;
396         Ini := TIniFile.Create(MyPath + ConfigFile);
397         try
398           Ini.WriteString('SVG', 'GhostFile', GhostFile);
399         finally
400           Ini.Free;
401         end;
402         Ghost2File.Clear;
403       end;
404     finally
405       OpenDialog.Free;
406     end;
407   except
408     on E: Exception do
409       ShowMessage(E.Message);
410   end;
411 end;
412
413 exports
414   Load,
415   Unload,
416   GetVersion,
417   Configure,
418   GetImage,
419   GetImageSize;
420
421 begin
422
423 end.