+{
+SSTP Bottle Surface Preview Plug-In for "SVG"
+(C)2003-2004 WinBottle Project / SSTP Bottle
+}
+
library SVG;
{$R *.res}
uses
- Windows, Classes, SysUtils, Graphics, IniFiles;
+ Windows, Classes, SysUtils, Graphics, IniFiles, Dialogs, PngImage, jpeg;
const
SurfaceWidth = 48;
var
MyPath: String;
GhostFile: String;
- Ghost2File: TStringList;
+ Ghost2File: THashedStringList;
+
+ Pic: TPicture; // \93Ç\82Ý\8eæ\82Á\82½\89æ\91\9c(*.png, *.bmp, *.jpg)
+ PicFileName: String; // \82»\82Ì\83t\83@\83C\83\8b\96¼
// 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
// \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ð
finally
Ini.Free;
end;
- Ghost2File := TStringList.Create;
+ if not FileExists(GhostFile) then
+ ShowMessage('SVG.dll Warning: Ghost file is not specified');
+ Ghost2File := THashedStringList.Create;
+ Pic := TPicture.Create;
+ PicFileName := '';
end;
// DLL\83A\83\93\83\8d\81[\83h\8e\9e\82É\8cÄ\82Î\82ê\82é\81B
-// \82½\82Ô\82ñ\82â\82é\82±\82Æ\82Í\82È\82¢\81B
procedure Unload; cdecl;
begin
Ghost2File.Free;
+ Pic.Free;
end;
// DLL\82Ì\96¼\91O\82¨\82æ\82Ñ\83o\81[\83W\83\87\83\93\82ð\95Ô\82·\81B
// CanConfigure\82Í\81AConfigure\82ð\8cÄ\82Î\82ê\82Ä\82â\82é\82±\82Æ\82ª\82 \82é\82©\82Ç\82¤\82©\82ð\95Ô\82·\81B
function GetVersion(DLLName: PChar; NameLen: integer;
var Version: integer; var CanConfigure: boolean): integer; cdecl;
-const ThisDLL = 'SVG Surface Loader';
+const ThisDLL = 'SVG Surface Loader Ver. 2.6';
begin
Version := 1;
CanConfigure := true;
Result := Length(ThisDLL) + 1;
end;
-function LoadDefinitionFile(Ghost: String;
- Surface: integer; FileName: String; out Pos: integer): String;
-var Lines, ALine, SurfaceMap: TStringList;
- i, j, p: integer;
+function LoadDefinitionFileVer2(Ghost: String;
+ Surface: integer; Lines: TStringList; const FileName: String;
+ out Pos: integer): String;
+var ALine, SurfaceMap: TStringList;
+ i, j, p, sur, oldpos: integer;
+ posstr: String;
begin
// \93à\95\94\8aÖ\90\94\81B\83S\81[\83X\83g\92è\8b`\83t\83@\83C\83\8b\82ð\89ð\90Í\82µ\82Ä\81A
// \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é
- Lines := TStringList.Create;
+ ALine := TStringList.Create;
try
- Lines.LoadFromFile(FileName);
- ALine := TStringList.Create;
+ ALine.CommaText := Lines[0];
+ if (ALine[0] <> 'GHOST') then
+ Exit;
+
+ Ghost2File.Values[Ghost] := FileName; // \8e\9f\82©\82ç\82Ì\83V\83\87\81[\83g\83J\83b\83g
+ if (ALine[1] <> Ghost) then
+ begin
+ Exit;
+ end;
+
+ // \96Ú\93I\82Ì\83S\81[\83X\83g\94\8c©
+ oldpos := 0;
+ SurfaceMap := TStringList.Create;
try
- ALine.CommaText := Lines[0];
- if (ALine[0] <> 'GHOST') or (ALine[1] <> Ghost) then
+ for i := 1 to Lines.Count-1 do
+ begin
+ SurfaceMap.CommaText := Lines[i];
+ for j := 0 to SurfaceMap.Count-1 do
+ begin
+ try
+ p := System.Pos(':', SurfaceMap[j]);
+ if p = 0 then
+ Continue;
+ sur := StrToInt(Copy(SurfaceMap[j], 1, p-1));
+ posstr := Copy(SurfaceMap[j], p+1, High(integer));
+ if posstr = '+' then
+ Pos := oldpos + 1
+ else
+ Pos := StrToInt(posstr);
+ if sur = Surface then
+ begin
+ Result := ALine[4]; // BMP\83t\83@\83C\83\8b\96¼
+ Exit;
+ end else
+ oldpos := Pos;
+ except
+ on EConvertError do; // nothing. \92P\82È\82é\83R\83\81\83\93\83g\8ds\88µ\82¢
+ end;
+ end;
+ end;
+ finally
+ SurfaceMap.Free;
+ end;
+
+ // BASIC\82Ì\8fê\8d\87\82Ì\8f\88\97\9d
+ if AnsiCompareText('BASIC', ALine[3]) = 0 then
+ begin
+ if (Surface >= 0) and (Surface <= 11) then
+ begin
+ Result := ALine[4]; // BMP\83t\83@\83C\83\8b\96¼
+ 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é
Exit;
- // \96Ú\93I\82Ì\83S\81[\83X\83g\94\8c©
+ end;
+ end;
+
+ finally
+ ALine.Free;
+ end;
+end;
- SurfaceMap := TStringList.Create;
- try
- for i := 1 to Lines.Count-1 do
+procedure ParseKeyVal(const Line: String; out Key, Val: String);
+var p: integer;
+begin
+ // Key=Value\8c`\8e®\82Ì\95¶\8e\9a\97ñ\82©\82çKey\82ÆValue\82ð\8eæ\82è\8fo\82·
+ // Value\82Í""\82Å\88Í\82ñ\82Å\82à\82æ\82¢\81BKey\82Í\8f¬\95¶\8e\9a\82É\82±\82Ì\92i\8aK\82Å\93\9d\88ê
+ p := Pos('=', Line);
+ if p > 0 then
+ begin
+ Key := AnsiLowerCase(Copy(Line, 1, p-1));
+ Val := AnsiDequotedStr(Copy(Line, p+1, High(integer)), '"');
+ end else begin
+ Key := '';
+ Val := AnsiDequotedStr(Line, '"');
+ end;
+end;
+
+procedure SplitBlocks(Lines, Blocks: TStringList);
+var
+ Str, Block: String;
+ i: integer;
+ Start: integer; // \8c»\8dÝ\92\8d\96Ú\82µ\82Ä\82¢\82é\83u\83\8d\83b\83N\82Ì\90æ\93ª\82Ì\95¶\8e\9a\83C\83\93\83f\83b\83N\83X
+ InLead: boolean; // DBCS\82ÌLeadBytes\82ð\8c©\82Ä\82¢\82é\82©\82Ç\82¤\82©\82ð\95Û\8e\9d
+begin
+ // SVG\82Ì\8ae\8ds\82ð\83u\83\8d\83b\83N\82É\95Ï\8a·
+ // \83R\83\81\83\93\83g\82ð\8eæ\82è\8aO\82µ\81A/EOF\88È\8d~\82ð\93K\90Ø\82É\96³\8e\8b\82·\82é
+ Str := Lines.Text;
+ i := 0;
+ Start := 1;
+ InLead := false;
+ while (i < Length(Str)) do
+ begin
+ Inc(i);
+ if InLead then
+ begin
+ InLead := false;
+ Continue;
+ end else if Str[i] in LeadBytes then
+ begin
+ InLead := true;
+ Continue;
+ end else
+ begin
+ if Str[i] in [',', #13, #10] then
+ begin
+ if Start < i then
begin
- SurfaceMap.CommaText := Lines[i];
- for j := 0 to SurfaceMap.Count-1 do
- begin
- try
- p := System.Pos(':', SurfaceMap[j]);
- if p = 0 then
- Continue;
- if StrToInt(Copy(SurfaceMap[j], 1, p-1)) = Surface then
- begin
- Pos := StrToInt(Copy(SurfaceMap[j], p+1, High(integer)));
- Result := ALine[4]; // BMP\83t\83@\83C\83\8b\96¼
- Exit;
- end;
- except
- on EConvertError do; // nothing. \92P\82È\82é\83R\83\81\83\93\83g\8ds\88µ\82¢
- end;
- end;
+ // \90Ø\82è\8fo\82µ
+ Block := Copy(Str, Start, i-Start);
+ if Block = '/EOF' then
+ Break
+ else if Block[1] <> '/' then // \83R\83\81\83\93\83g\82Í\96³\8e\8b
+ Blocks.Add(Block);
end;
- finally
- SurfaceMap.Free;
+ Start := i+1;
end;
+ end;
+ end;
+end;
- // BASIC\82Ì\8fê\8d\87\82Ì\8f\88\97\9d
- if AnsiCompareText('BASIC', ALine[3]) = 0 then
+function LoadDefinitionFileVer3(Ghost: String;
+ Surface: integer; Lines: TStringList; const FileName: String;
+ out Pos: integer): String;
+var i, k, smin, smax, oldsur: integer;
+ Key, Val, SurStr, PosStr, SakuraName: String;
+ Blocks, Sur2Pos: TStringList;
+begin
+ oldsur := -1;
+ Sur2Pos := TStringList.Create;
+ Blocks := TStringList.Create;
+ try
+ Lines.Delete(0);
+ SplitBlocks(Lines, Blocks);
+ for i := 0 to Blocks.Count-1 do
+ begin
+ ParseKeyVal(Blocks[i], Key, Val);
+ if Key = 'sakura' then
begin
- if (Surface >= 0) and (Surface <= 11) then
+ SakuraName := Val;
+ Ghost2File.Values[SakuraName] := FileName; //\8e\9f\82©\82ç\82Ì\83V\83\87\81[\83g\83J\83b\83g
+ if SakuraName <> Ghost then //\95Ê\83S\81[\83X\83g\82Ì\92è\8b`\83t\83@\83C\83\8b\82È\82Ì\82Å\83p\83X
begin
- Result := ALine[4]; // BMP\83t\83@\83C\83\8b\96¼
- 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é
+ Result := '';
Exit;
end;
+ end else if Key = 'surfacefile' then
+ begin
+ Result := Val;
+ end else if (Key = 'surface') or (Length(Key) = 0) then
+ begin
+ // \83T\81[\83t\83B\83X
+ if System.Pos(':', Val) <= 0 then
+ Continue;
+ SurStr := Copy(Val, 1, System.Pos(':', Val)-1);
+ PosStr := Copy(Val, System.Pos(':', Val)+1, High(integer));
+ try
+ if System.Pos('-', SurStr) > 0 then
+ begin
+ smin := StrToInt(Copy(SurStr, 1, System.Pos('-', SurStr)-1));
+ smax := StrToInt(Copy(SurStr, System.Pos('-', SurStr)+1, High(integer)));
+ end else
+ begin
+ smin := StrToInt(SurStr);
+ smax := smin;
+ end;
+ for k := smin to smax do
+ begin
+ if PosStr = '*' then
+ begin
+ Sur2Pos.Values[IntToStr(k)] := IntToStr(k);
+ oldsur := k;
+ end else if PosStr = '-2' then
+ begin
+ Sur2Pos.Values[IntToStr(k)] := '' // \92è\8b`\89ð\8f\9c
+ end else if PosStr = '+' then
+ begin
+ Inc(oldsur);
+ Sur2Pos.Values[IntToStr(k)] := IntToStr(oldsur);
+ end else if StrToInt(PosStr) >= 0 then
+ begin
+ Sur2Pos.Values[IntToStr(k)] := PosStr;
+ oldsur := StrToInt(PosStr);
+ end;
+ end;
+ except
+ Continue;
+ end;
end;
-
- finally
- ALine.Free;
end;
+ // ShowMessage(SakuraName + #13#10 + Sur2Pos.Text);
+ 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
+ Result := ''
+ else
+ begin
+ if Sur2Pos.Values[IntToStr(Surface)] <> '' then
+ Pos := StrToInt(Sur2Pos.Values[IntToStr(Surface)])
+ else
+ Result := '';
+ end;
+ finally
+ Sur2Pos.Free;
+ Blocks.Free;
+ end;
+end;
+
+function LoadDefinitionFile(Ghost: String;
+ Surface: integer; FileName: String; out Pos: integer): String;
+var Lines: TStringList;
+begin
+ Lines := TStringList.Create;
+ Lines.LoadFromFile(FileName);
+ try
+ if System.Pos('SVG3', Lines[0]) > 0 then
+ Result := LoadDefinitionFileVer3(Ghost, Surface, Lines, FileName, Pos)
+ else
+ Result := LoadDefinitionFileVer2(Ghost, Surface, Lines, FileName, Pos);
finally
Lines.Free;
end;
i, dum: integer;
Dir, DefFileName, BmpFileName: String;
begin
- if Ghost2File.Values[Ghost] <> '' then // \82·\82Å\82É\82»\82Ì\83S\81[\83X\83g\82Ì\83t\83@\83C\83\8b\82ð\8bL\89¯\82µ\82Ä\82é
+ Result := '';
+ if Ghost2File.Values[Ghost] <> '' then // \82·\82Å\82É\82»\82Ì\83S\81[\83X\83g\82É\82Â\82¢\82Ä\92²\8d¸\8dÏ\82Ý
begin
DefFileName := Ghost2File.Values[Ghost];
- BmpFileName := LoadDefinitionFile(Ghost, Surface,
- DefFileName, dum);
- if BmpFileName <> '' then
+ if DefFileName = '*' then // \82»\82Ì\83S\81[\83X\83g\82Í\92m\82ç\82È\82¢\81A\82Æ\8bL\89¯\82µ\82Ä\82¢\82é
begin
- Result := ExtractFilePath(DefFileName) + BmpFileName;
- Pos := dum;
Exit;
+ end else // \82»\82Ì\83S\81[\83X\83g\82ð\92m\82Á\82Ä\82¢\82é
+ begin
+ BmpFileName := LoadDefinitionFile(Ghost, Surface,
+ DefFileName, dum);
+ if BmpFileName <> '' then
+ begin
+ Result := ExtractFilePath(DefFileName) + BmpFileName;
+ Pos := dum;
+ Exit;
+ end;
end;
end;
+ // \83S\81[\83X\83g\82ª\8c©\82Â\82©\82ç\82È\82©\82Á\82½\8c\8b\89Ê\82ð\8bL\89¯\81B
+ // \8c©\82Â\82©\82Á\82½\8fê\8d\87\82É\82Í\83t\83@\83C\83\8b\96¼\82Å\8fã\8f\91\82«\82³\82ê\82é
+ if Result = '' then
+ Ghost2File.Values[Ghost] := '*';
+
// \93à\95\94\8aÖ\90\94\81Bghost.txt\82ð\93Ç\82Ý\8d\9e\82Þ\81B
Dir := ExtractFilePath(GhostFile);
Ghosts := TStringList.Create;
try
Ghosts.LoadFromFile(GhostFile);
- for i := 0 to Ghosts.Count-1 do
- begin
- AGhost := TStringList.Create;
- try
- AGhost.CommaText := Ghosts[i];
+ AGhost := TStringList.Create;
+ try
+ for i := 0 to Ghosts.Count-1 do
+ begin
+ AGhost.Text := StringReplace(Ghosts[i], ',', #13#10, [rfReplaceAll]);
+ if AGhost.Count = 0 then
+ Continue;
if AGhost[0] <> 'GHOST' then
Continue;
- DefFileName := Dir + AGhost[3];
+ DefFileName := Dir + StringReplace(AGhost[3], '"', '', [rfReplaceAll]);
// \92è\8b`\83t\83@\83C\83\8b\82ð\93Ç\82Ý\8d\9e\82Þ
BmpFileName := LoadDefinitionFile(Ghost, Surface,
DefFileName, dum);
if BmpFileName <> '' then
begin
- // \94\8c©!
- Ghost2File.Values[Ghost] := DefFileName; // \8e\9f\82©\82ç\82Ì\82½\82ß\82É\92è\8b`\83t\83@\83C\83\8b\96¼\82ð\8bL\89¯
Result := ExtractFilePath(DefFileName) + BmpFileName;
Pos := dum;
Break;
end;
- finally
- AGhost.Free;
end;
+ finally
+ AGhost.Free;
end;
finally
Ghosts.Free;
// 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
// H\82Å\8ew\92è\82³\82ê\82Ä\82¢\82é\83r\83b\83g\83}\83b\83v\82É\8f\91\82«\8fo\82·\82±\82Æ\81B
function GetImage(Ghost: PChar; Surface: integer; H: HBITMAP): integer; cdecl;
-var Bmp, Bmp2: TBitmap;
+var Bmp: TBitmap;
BmpFile: String;
Position, x, y, nCol: integer;
begin
Result := 1;
Exit;
end;
- except
- on Exception do // \83t\83@\83C\83\8b\82ª\8c©\82Â\82©\82Á\82Ä\82È\82¢\89Â\94\\90«\82ª\82à\82Á\82Æ\82à\8d\82\82¢
- begin
- Result := 1;
- Exit;
- end;
- end;
-
- Bmp := TBitmap.Create;
- try
- Bmp.Handle := H;
- Bmp2 := TBitmap.Create;
+ Bmp := TBitmap.Create;
try
- Bmp2.LoadFromFile(BmpFile);
- nCol := Bmp2.Width div SurfaceWidth;
+ Bmp.Handle := H;
+ if PicFileName <> BmpFile then
+ begin
+ try
+ Pic.LoadFromFile(BmpFile);
+ PicFileName := BmpFile;
+ except
+ // \8dì\82è\92¼\82µ
+ FreeAndNil(Pic);
+ Pic := TPicture.Create;
+ PicFileName := '';
+ raise;
+ end;
+ end;
+ nCol := Pic.Width div SurfaceWidth;
x := SurfaceWidth * (Position mod nCol);
y := SurfaceHeight * (Position div nCol);
- Bmp.Canvas.CopyRect(
- Rect(0, 0, Bmp.Width, Bmp.Height),
- Bmp2.Canvas,
- Rect(x, y, x+SurfaceWidth, y+SurfaceHeight)
- );
+ Bmp.Canvas.Draw(-x, -y, Pic.Graphic);
finally
- Bmp2.Free;
+ Bmp.ReleaseHandle;
+ Bmp.Free;
end;
- finally
- Bmp.ReleaseHandle;
- Bmp.Free;
+ Result := 0;
+ except
+ Result := 1;
end;
- Result := 0;
end;
// \83C\83\81\81[\83W\82Ì\91å\82«\82³\82ð\95Ô\82·\81B
// DLL\8cÅ\97L\82Ì\90Ý\92è\82ð\8ds\82¤\81B
//
procedure Configure; cdecl;
+var OpenDialog: TOpenDialog;
+ Ini: TIniFile;
begin
+ try
+ ShowMessage('Specify SSTP Viewer''s ghost file.');
+ OpenDialog := TOpenDialog.Create(nil);
+ try
+ OpenDialog.Filter := 'Ghost Definition File(ghost.txt)|ghost.txt|' +
+ 'All Files(*.*)|*.*';
+ OpenDialog.FileName := GhostFile;
+ if OpenDialog.Execute then
+ begin
+ GhostFile := OpenDialog.FileName;
+ Ini := TIniFile.Create(MyPath + ConfigFile);
+ try
+ Ini.WriteString('SVG', 'GhostFile', GhostFile);
+ finally
+ Ini.Free;
+ end;
+ Ghost2File.Clear;
+ end;
+ finally
+ OpenDialog.Free;
+ end;
+ except
+ on E: Exception do
+ ShowMessage(E.Message);
+ end;
end;
exports