mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-06 06:30:35 +02:00
* Mantis #25276, improvements for CHMCMD anchor handling, specially combined
with errorhandling. git-svn-id: trunk@26289 -
This commit is contained in:
parent
b2a4b4cfda
commit
59aa032986
@ -26,7 +26,7 @@ uses
|
|||||||
Classes, Sysutils, chmfilewriter, GetOpts;
|
Classes, Sysutils, chmfilewriter, GetOpts;
|
||||||
|
|
||||||
Const
|
Const
|
||||||
CHMCMDVersion = '2.6.0';
|
CHMCMDVersion = '2.6.1';
|
||||||
|
|
||||||
Procedure Usage;
|
Procedure Usage;
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ var
|
|||||||
|
|
||||||
procedure OnError (Project: TChmProject;errorkind:TChmProjectErrorKind;msg:String;detailevel:integer=0);
|
procedure OnError (Project: TChmProject;errorkind:TChmProjectErrorKind;msg:String;detailevel:integer=0);
|
||||||
begin
|
begin
|
||||||
if detailevel<=alloweddetaillevel then
|
if (detailevel<=alloweddetaillevel) or (errorkind < chmnote) then
|
||||||
if errorkind<>chmnone then
|
if errorkind<>chmnone then
|
||||||
writeln(ChmErrorKindText[errorkind],': ',msg)
|
writeln(ChmErrorKindText[errorkind],': ',msg)
|
||||||
else
|
else
|
||||||
@ -150,6 +150,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
OutStream := TFileStream.Create(Project.OutputFileName, fmCreate, fmOpenWrite);
|
OutStream := TFileStream.Create(Project.OutputFileName, fmCreate, fmOpenWrite);
|
||||||
Project.WriteChm(OutStream);
|
Project.WriteChm(OutStream);
|
||||||
|
if Project.ScanHtmlContents then
|
||||||
|
Project.ShowUndefinedAnchors;
|
||||||
if ishhp and GenerateXMLForHHP then
|
if ishhp and GenerateXMLForHHP then
|
||||||
begin
|
begin
|
||||||
Writeln('Generating XML ',xmlname,'.');
|
Writeln('Generating XML ',xmlname,'.');
|
||||||
|
@ -60,6 +60,7 @@ type
|
|||||||
fOtherFiles : TStrings; // Files found in a scan.
|
fOtherFiles : TStrings; // Files found in a scan.
|
||||||
fAllowedExtensions: TStringList;
|
fAllowedExtensions: TStringList;
|
||||||
fTotalFileList : TAvlTree;
|
fTotalFileList : TAvlTree;
|
||||||
|
fAnchorList : TStringList;
|
||||||
FSpareString : TStringIndex;
|
FSpareString : TStringIndex;
|
||||||
FBasePath : String; // location of the .hhp file. Needed to resolve relative paths
|
FBasePath : String; // location of the .hhp file. Needed to resolve relative paths
|
||||||
FReadmeMessage : String; // readme message
|
FReadmeMessage : String; // readme message
|
||||||
@ -75,6 +76,7 @@ type
|
|||||||
procedure ScanList(toscan,newfiles:TStrings;recursion:boolean);
|
procedure ScanList(toscan,newfiles:TStrings;recursion:boolean);
|
||||||
procedure ScanSitemap(sitemap:TChmSiteMap;newfiles:TStrings;recursion:boolean);
|
procedure ScanSitemap(sitemap:TChmSiteMap;newfiles:TStrings;recursion:boolean);
|
||||||
function FileInTotalList(const s:String):boolean;
|
function FileInTotalList(const s:String):boolean;
|
||||||
|
function SanitizeURL(const basepath, instring, localpath, localname:string; var outstring:String):Boolean;
|
||||||
public
|
public
|
||||||
constructor Create; virtual;
|
constructor Create; virtual;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -82,6 +84,7 @@ type
|
|||||||
procedure LoadFromhhp (AFileName:String;LeaveInclude:Boolean); virtual;
|
procedure LoadFromhhp (AFileName:String;LeaveInclude:Boolean); virtual;
|
||||||
procedure SaveToFile(AFileName: String); virtual;
|
procedure SaveToFile(AFileName: String); virtual;
|
||||||
procedure WriteChm(AOutStream: TStream); virtual;
|
procedure WriteChm(AOutStream: TStream); virtual;
|
||||||
|
procedure ShowUndefinedAnchors;
|
||||||
function ProjectDir: String;
|
function ProjectDir: String;
|
||||||
procedure LoadSitemaps;
|
procedure LoadSitemaps;
|
||||||
procedure AddFileWithContext(contextid:integer;filename:ansistring;contextname:ansistring='');
|
procedure AddFileWithContext(contextid:integer;filename:ansistring;contextname:ansistring='');
|
||||||
@ -126,6 +129,23 @@ implementation
|
|||||||
|
|
||||||
uses XmlCfg, CHMTypes;
|
uses XmlCfg, CHMTypes;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TFirstReference }
|
||||||
|
|
||||||
|
TFirstReference = class
|
||||||
|
public
|
||||||
|
Location: string;
|
||||||
|
constructor Create(Const ALocation: string);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TFirstReference }
|
||||||
|
|
||||||
|
constructor TFirstReference.Create(const ALocation: string);
|
||||||
|
begin
|
||||||
|
Location := ALocation;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TChmProject }
|
{ TChmProject }
|
||||||
|
|
||||||
function TChmProject.GetData(const DataName: String; out PathInChm: String; out
|
function TChmProject.GetData(const DataName: String; out PathInChm: String; out
|
||||||
@ -187,6 +207,9 @@ begin
|
|||||||
ScanHtmlContents:=False;
|
ScanHtmlContents:=False;
|
||||||
FTotalFileList:=TAvlTree.Create(@CompareStrings);
|
FTotalFileList:=TAvlTree.Create(@CompareStrings);
|
||||||
FSparestring :=TStringIndex.Create;
|
FSparestring :=TStringIndex.Create;
|
||||||
|
fAnchorList := TStringList.Create;
|
||||||
|
fAnchorList.Sorted := True;
|
||||||
|
fAnchorList.OwnsObjects := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TChmProject.Destroy;
|
destructor TChmProject.Destroy;
|
||||||
@ -206,6 +229,7 @@ begin
|
|||||||
FIndex.free;
|
FIndex.free;
|
||||||
FTocStream.Free;
|
FTocStream.Free;
|
||||||
FIndexStream.Free;
|
FIndexStream.Free;
|
||||||
|
fAnchorList.Free;
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -690,11 +714,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
const
|
const
|
||||||
protocols : array[0..2] of string = ('HTTP:','FTP:','MS-ITS:');
|
protocols : array[0..3] of string = ('HTTP:','FTP:','MS-ITS:', 'MAILTO:');
|
||||||
protocollen : array[0..2] of integer= ( 5 ,4 ,7);
|
protocollen : array[0..3] of integer= ( 5 ,4 ,7, 7);
|
||||||
|
|
||||||
function sanitizeurl(const basepath,instring:string;var outstring:String):Boolean;
|
function TChmProject.SanitizeURL(const basepath,instring,localpath,localname:string;var outstring:String):Boolean;
|
||||||
var i,j,len : integer;
|
var i,j,len : integer;
|
||||||
|
Anchor: String;
|
||||||
begin
|
begin
|
||||||
result:=true; outstring:='';
|
result:=true; outstring:='';
|
||||||
if instring='' then
|
if instring='' then
|
||||||
@ -703,6 +728,7 @@ begin
|
|||||||
len:=length(instring);
|
len:=length(instring);
|
||||||
if len=0 then
|
if len=0 then
|
||||||
exit(false);
|
exit(false);
|
||||||
|
{ Check for protocols before adding local path }
|
||||||
i:=0;
|
i:=0;
|
||||||
while (i<=high(protocols)) do
|
while (i<=high(protocols)) do
|
||||||
begin
|
begin
|
||||||
@ -710,11 +736,22 @@ begin
|
|||||||
exit(false);
|
exit(false);
|
||||||
inc(i);
|
inc(i);
|
||||||
end;
|
end;
|
||||||
outstring:=instring;
|
outstring:=localpath+instring;
|
||||||
|
|
||||||
i:=pos('#',outstring);
|
i:=pos('#',outstring);
|
||||||
if i<>0 then
|
if i<>0 then begin
|
||||||
|
if i > 1 then
|
||||||
|
Anchor := outstring
|
||||||
|
else
|
||||||
|
Anchor := localname+outstring;
|
||||||
|
j := fAnchorList.IndexOf(Anchor);
|
||||||
|
if j < 0 then begin
|
||||||
|
fAnchorList.AddObject(Anchor,TFirstReference.Create(localname));
|
||||||
|
Anchor := '(new) '+Anchor;
|
||||||
|
end;
|
||||||
|
Error(CHMNote, 'Anchor found '+Anchor+' while scanning '+localname,1);
|
||||||
delete(outstring,i,length(outstring)-i+1);
|
delete(outstring,i,length(outstring)-i+1);
|
||||||
|
end;
|
||||||
|
|
||||||
outstring:=expandfilename(StringReplace(outstring,'%20',' ',[rfReplaceAll]));// expandfilename(instring));
|
outstring:=expandfilename(StringReplace(outstring,'%20',' ',[rfReplaceAll]));// expandfilename(instring));
|
||||||
|
|
||||||
@ -737,37 +774,44 @@ procedure TChmProject.ScanList(toscan,newfiles:TStrings;recursion:boolean);
|
|||||||
var
|
var
|
||||||
localpath : string;
|
localpath : string;
|
||||||
|
|
||||||
procedure checkattributes(node:TDomNode;attributename:string;filelist :TStringList);
|
function findattribute(node:TDomNode;attributename:string):String;
|
||||||
var
|
var
|
||||||
Attributes: TDOMNamedNodeMap;
|
Attributes: TDOMNamedNodeMap;
|
||||||
atnode : TDomNode;
|
atnode : TDomNode;
|
||||||
fn : String;
|
|
||||||
n : integer;
|
n : integer;
|
||||||
begin
|
begin
|
||||||
|
Result := '';
|
||||||
if assigned(node) then
|
if assigned(node) then
|
||||||
begin
|
begin
|
||||||
Attributes:=node.Attributes;
|
Attributes:=node.Attributes;
|
||||||
if assigned(attributes) then
|
if assigned(attributes) then
|
||||||
begin
|
|
||||||
for n:=0 to attributes.length-1 do
|
for n:=0 to attributes.length-1 do
|
||||||
begin
|
begin
|
||||||
atnode :=attributes[n];
|
atnode :=attributes[n];
|
||||||
if assigned(atnode) and (uppercase(atnode.nodename)=attributename) then
|
if assigned(atnode) and (uppercase(atnode.nodename)=attributename) then
|
||||||
|
exit(atnode.nodevalue);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure checkattributes(node:TDomNode;attributename:string; const localname: string; filelist :TStringList);
|
||||||
|
var
|
||||||
|
fn : String;
|
||||||
|
val : String;
|
||||||
begin
|
begin
|
||||||
if sanitizeurl(fbasepath,localpath+atnode.nodevalue,fn) then
|
val := findattribute(node,attributename);
|
||||||
if not FileInTotalList(uppercase(fn)) then
|
if sanitizeurl(fbasepath,val,localpath,localname,fn) then
|
||||||
|
if (Length(fn) > 0) { Skip links to self using named anchors }
|
||||||
|
and not FileInTotalList(uppercase(fn)) then
|
||||||
filelist.add(fn);
|
filelist.add(fn);
|
||||||
end;
|
end;
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function scantags(prnt:TDomNode;filelist:TStringlist):TDomNode;
|
function scantags(prnt:TDomNode; const localname: string; filelist:TStringlist):TDomNode;
|
||||||
// Seach first matching tag in siblings
|
// Seach first matching tag in siblings
|
||||||
var chld: TDomNode;
|
var chld: TDomNode;
|
||||||
s : ansistring;
|
s : ansistring;
|
||||||
|
i : Integer;
|
||||||
begin
|
begin
|
||||||
result:=nil;
|
result:=nil;
|
||||||
if assigned(prnt ) then
|
if assigned(prnt ) then
|
||||||
@ -775,24 +819,39 @@ begin
|
|||||||
chld:=prnt.firstchild;
|
chld:=prnt.firstchild;
|
||||||
while assigned(chld) do
|
while assigned(chld) do
|
||||||
begin
|
begin
|
||||||
scantags(chld,filelist); // depth first.
|
scantags(chld, localname, filelist); // depth first.
|
||||||
if (chld is TDomElement) then
|
if (chld is TDomElement) then
|
||||||
begin
|
begin
|
||||||
s:=uppercase(tdomelement(chld).tagname);
|
s:=uppercase(tdomelement(chld).tagname);
|
||||||
if s='LINK' then
|
if s='LINK' then
|
||||||
begin
|
begin
|
||||||
//printattributes(chld,'');
|
//printattributes(chld,'');
|
||||||
checkattributes(chld,'HREF',filelist);
|
checkattributes(chld,'HREF',localname,filelist);
|
||||||
end;
|
end;
|
||||||
if s='IMG'then
|
if s='IMG'then
|
||||||
begin
|
begin
|
||||||
//printattributes(chld,'');
|
//printattributes(chld,'');
|
||||||
checkattributes(chld,'SRC',filelist);
|
checkattributes(chld,'SRC',localname,filelist);
|
||||||
end;
|
end;
|
||||||
if s='A'then
|
if s='A'then
|
||||||
begin
|
begin
|
||||||
//printattributes(chld,'');
|
//printattributes(chld,'');
|
||||||
checkattributes(chld,'HREF',filelist);
|
checkattributes(chld,'HREF',localname,filelist);
|
||||||
|
s := findattribute(chld,'NAME');
|
||||||
|
if s <> '' then
|
||||||
|
begin
|
||||||
|
i := fAnchorList.IndexOf(localname+'#'+s);
|
||||||
|
if i < 0 then begin
|
||||||
|
fAnchorList.Add(localname+'#'+s);
|
||||||
|
Error(ChmNote,'New Anchor with name '+s+' found while scanning '+localname,1);
|
||||||
|
end else if fAnchorList.Objects[i] = nil then
|
||||||
|
Error(chmwarning,'Duplicate anchor definitions with name '+s+' found while scanning '+localname,1)
|
||||||
|
else begin
|
||||||
|
fAnchorList.Objects[i].Free;
|
||||||
|
fAnchorList.Objects[i] := nil;
|
||||||
|
Error(ChmNote,'Anchor with name '+s+' defined while scanning '+localname,1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
chld:=chld.nextsibling;
|
chld:=chld.nextsibling;
|
||||||
@ -818,7 +877,7 @@ begin
|
|||||||
if FileInTotalList(vn2) then
|
if FileInTotalList(vn2) then
|
||||||
begin
|
begin
|
||||||
Error(ChmNote,'Found duplicate file '+vn+' while scanning '+fn,1);
|
Error(ChmNote,'Found duplicate file '+vn+' while scanning '+fn,1);
|
||||||
exit(false);
|
exit(true);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
result:=false;
|
result:=false;
|
||||||
@ -851,7 +910,7 @@ begin
|
|||||||
localpath:=extractfilepath(fn);
|
localpath:=extractfilepath(fn);
|
||||||
if (length(localpath)>0) and not (localpath[length(localpath)] in ['/','\']) then
|
if (length(localpath)>0) and not (localpath[length(localpath)] in ['/','\']) then
|
||||||
localpath:=localpath+pathsep;
|
localpath:=localpath+pathsep;
|
||||||
scantags(domdoc,localfilelist);
|
scantags(domdoc,extractfilename(fn),localfilelist);
|
||||||
for i:=0 to localFilelist.count-1 do
|
for i:=0 to localFilelist.count-1 do
|
||||||
begin
|
begin
|
||||||
s:=localfilelist[i];
|
s:=localfilelist[i];
|
||||||
@ -896,7 +955,7 @@ begin
|
|||||||
for i:=0 to it.count -1 do
|
for i:=0 to it.count -1 do
|
||||||
begin
|
begin
|
||||||
x:=it.item[i];
|
x:=it.item[i];
|
||||||
if sanitizeurl(fbasepath,x.local,S) then // sanitize, remove stuff etc.
|
if sanitizeurl(fbasepath,x.local,'','Site Map for '+x.Text,S) then // sanitize, remove stuff etc.
|
||||||
begin
|
begin
|
||||||
if not FileInTotalList(uppercase(s)) then
|
if not FileInTotalList(uppercase(s)) then
|
||||||
begin
|
begin
|
||||||
@ -1066,6 +1125,15 @@ begin
|
|||||||
Writer.Free;
|
Writer.Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TChmProject.ShowUndefinedAnchors;
|
||||||
|
var
|
||||||
|
i:Integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to fAnchorList.Count-1 do
|
||||||
|
if fAnchorList.Objects[i] <> nil then
|
||||||
|
Error(chmerror,'Anchor '+fAnchorList[i]+' undefined; first use '+TFirstReference(fAnchorList.Objects[i]).Location);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TChmProject.LoadSitemaps;
|
procedure TChmProject.LoadSitemaps;
|
||||||
// #IDXHDR (merged files) goes into the system file, and need to keep TOC sitemap around
|
// #IDXHDR (merged files) goes into the system file, and need to keep TOC sitemap around
|
||||||
begin
|
begin
|
||||||
|
Loading…
Reference in New Issue
Block a user