OSDN Git Service

Skip comment lines beginning with a slash
[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 procedure Unload; cdecl;
51 begin
52   Ghost2File.Free;
53   Pic.Free;
54 end;
55
56 // DLL\82Ì\96¼\91O\82¨\82æ\82Ñ\83o\81[\83W\83\87\83\93\82ð\95Ô\82·\81B
57 // 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
58 // NameLen\83o\83C\83g\82ð\92´\82¦\82Ä\82Í\82È\82ç\82È\82¢\81B
59 // version\82É\82Í\82Æ\82è\82 \82¦\82¸1\82ð\95Ô\82·\82±\82Æ\81Bversion\82ÍSSTP Bottle Client\82Æ\82Ì
60 // \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É
61 // \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
62 // CanConfigure\82Í\81AConfigure\82ð\8cÄ\82Î\82ê\82Ä\82â\82é\82±\82Æ\82ª\82 \82é\82©\82Ç\82¤\82©\82ð\95Ô\82·\81B
63 function GetVersion(DLLName: PChar; NameLen: integer;
64   var Version: integer; var CanConfigure: boolean): integer; cdecl;
65 const ThisDLL = 'SVG Surface Loader Ver. 2.2';
66 begin
67   Version := 1;
68   CanConfigure := true;
69   StrLCopy(DLLName, ThisDLL, NameLen);
70   Result := Length(ThisDLL) + 1;
71 end;
72
73 function LoadDefinitionFileVer2(Ghost: String;
74   Surface: integer; Lines: TStringList; const FileName: String;
75   out Pos: integer): String;
76 var ALine, SurfaceMap: TStringList;
77     i, j, p, sur, oldpos: integer;
78     posstr: String;
79 begin
80   // \93à\95\94\8aÖ\90\94\81B\83S\81[\83X\83g\92è\8b`\83t\83@\83C\83\8b\82ð\89ð\90Í\82µ\82Ä\81A
81   // \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é
82   ALine := TStringList.Create;
83   try
84     ALine.CommaText := Lines[0];
85     if (ALine[0] <> 'GHOST') then
86       Exit;
87
88     Ghost2File.Values[Ghost] := FileName; // \8e\9f\82©\82ç\82Ì\83V\83\87\81[\83g\83J\83b\83g
89     if (ALine[1] <> Ghost) then
90     begin
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       if System.Pos('/', Lines[i]) = 1 then // \83R\83\81\83\93\83g\8ds\82ð\82Æ\82Î\82·
171         Continue;
172       ParseKeyVal(Lines[i], Key, Val);
173       if SameText(Key, 'sakura') then
174       begin
175         SakuraName := Val;
176         Ghost2File.Values[SakuraName] := FileName; //\8e\9f\82©\82ç\82Ì\83V\83\87\81[\83g\83J\83b\83g
177         if SakuraName <> Ghost then //\95Ê\83S\81[\83X\83g\82Ì\92è\8b`\83t\83@\83C\83\8b\82È\82Ì\82Å\83p\83X
178           Exit;
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   // \83S\81[\83X\83g\82ª\8c©\82Â\82©\82ç\82È\82©\82Á\82½\8c\8b\89Ê\82ð\8bL\89¯\81B
291   // \8c©\82Â\82©\82Á\82½\8fê\8d\87\82É\82Í\83t\83@\83C\83\8b\96¼\82Å\8fã\8f\91\82«\82³\82ê\82é
292   if Result = '' then
293     Ghost2File.Values[Ghost] := '*';
294
295   // \93à\95\94\8aÖ\90\94\81Bghost.txt\82ð\93Ç\82Ý\8d\9e\82Þ\81B
296   Dir := ExtractFilePath(GhostFile);
297   Ghosts := TStringList.Create;
298   try
299     Ghosts.LoadFromFile(GhostFile);
300     AGhost := TStringList.Create;
301     try
302       for i := 0 to Ghosts.Count-1 do
303       begin
304         AGhost.CommaText := Ghosts[i];
305         if AGhost[0] <> 'GHOST' then
306           Continue;
307         DefFileName := Dir + AGhost[3];
308         // \92è\8b`\83t\83@\83C\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ
309         BmpFileName := LoadDefinitionFile(Ghost, Surface,
310           DefFileName, dum);
311         if BmpFileName <> '' then
312         begin
313           Result := ExtractFilePath(DefFileName) + BmpFileName;
314           Pos := dum;
315           Break;
316         end;
317       end;
318     finally
319       AGhost.Free;
320     end;
321   finally
322     Ghosts.Free;
323   end;
324 end;
325
326 // 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
327 // H\82Å\8ew\92è\82³\82ê\82Ä\82¢\82é\83r\83b\83g\83}\83b\83v\82É\8f\91\82«\8fo\82·\82±\82Æ\81B
328 function GetImage(Ghost: PChar; Surface: integer; H: HBITMAP): integer; cdecl;
329 var Bmp: TBitmap;
330     BmpFile: String;
331     Position, x, y, nCol: integer;
332 begin
333   try
334     BmpFile := FetchBmpFileAndPosition(Ghost, Surface, Position);
335     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¢
336     begin
337       Result := 1;
338       Exit;
339     end;
340     Bmp := TBitmap.Create;
341     try
342       Bmp.Handle := H;
343       if PicFileName <> BmpFile then
344       begin
345         try
346           Pic.LoadFromFile(BmpFile);
347           PicFileName := BmpFile;
348         except
349           // \8dì\82è\92¼\82µ
350           FreeAndNil(Pic);
351           Pic := TPicture.Create;
352           PicFileName := '';
353           raise;
354         end;
355       end;
356       nCol := Pic.Width div SurfaceWidth;
357       x := SurfaceWidth * (Position mod nCol);
358       y := SurfaceHeight * (Position div nCol);
359       Bmp.Canvas.Draw(-x, -y, Pic.Graphic);
360     finally
361       Bmp.ReleaseHandle;
362       Bmp.Free;
363     end;
364     Result := 0;
365   except
366     Result := 1;
367   end;
368 end;
369
370 // \83C\83\81\81[\83W\82Ì\91å\82«\82³\82ð\95Ô\82·\81B
371 // \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
372 // \82»\82ê\82È\82ç\92P\8f\83\82É\92è\90\94\82ð\95Ô\82µ\82Ä\8d·\82µ\8ex\82¦\82È\82¢\81B
373 // \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
374 function GetImageSize(Ghost: PChar; Surface: integer;
375   var w, h: integer): integer; cdecl;
376 begin
377   w := SurfaceWidth;
378   h := SurfaceHeight;
379   Result := 0;
380 end;
381
382
383 // DLL\8cÅ\97L\82Ì\90Ý\92è\82ð\8ds\82¤\81B
384 //
385 procedure Configure; cdecl;
386 var OpenDialog: TOpenDialog;
387     Ini: TIniFile;
388 begin
389   try
390     ShowMessage('Specify SSTP Viewer''s ghost file.');
391     OpenDialog := TOpenDialog.Create(nil);
392     try
393       OpenDialog.Filter := 'Ghost Definition File(ghost.txt)|ghost.txt|' +
394        'All Files(*.*)|*.*';
395       OpenDialog.FileName := GhostFile;
396       if OpenDialog.Execute then
397       begin
398         GhostFile := OpenDialog.FileName;
399         Ini := TIniFile.Create(MyPath + ConfigFile);
400         try
401           Ini.WriteString('SVG', 'GhostFile', GhostFile);
402         finally
403           Ini.Free;
404         end;
405         Ghost2File.Clear;
406       end;
407     finally
408       OpenDialog.Free;
409     end;
410   except
411     on E: Exception do
412       ShowMessage(E.Message);
413   end;
414 end;
415
416 exports
417   Load,
418   Unload,
419   GetVersion,
420   Configure,
421   GetImage,
422   GetImageSize;
423
424 begin
425
426 end.