xmlread.pp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583
  1. {
  2. $Id$
  3. This file is part of the Free Component Library
  4. XML reading routines.
  5. Copyright (c) 1999-2000 by Sebastian Guenther, [email protected]
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit XMLRead;
  13. {$MODE objfpc}
  14. {$H+}
  15. interface
  16. {off $DEFINE MEM_CHECK}
  17. uses
  18. {$IFDEF MEM_CHECK}MemCheck,{$ENDIF}
  19. SysUtils, Classes, DOM;
  20. type
  21. EXMLReadError = class(Exception);
  22. procedure ReadXMLFile(var ADoc: TXMLDocument; const AFilename: String); overload;
  23. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: File); overload;
  24. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream); overload;
  25. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String); overload;
  26. procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String); overload;
  27. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File); overload;
  28. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream); overload;
  29. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String); overload;
  30. procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String); overload;
  31. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File); overload;
  32. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream); overload;
  33. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String); overload;
  34. // =======================================================
  35. implementation
  36. const
  37. Letter = ['A'..'Z', 'a'..'z'];
  38. Digit = ['0'..'9'];
  39. PubidChars: set of Char = [' ', #13, #10, 'a'..'z', 'A'..'Z', '0'..'9',
  40. '-', '''', '(', ')', '+', ',', '.', '/', ':', '=', '?', ';', '!', '*',
  41. '#', '@', '$', '_', '%'];
  42. WhitespaceChars: set of Char = [#9, #10, #13, ' '];
  43. NmToken: set of Char = Letter + Digit + ['.', '-', '_', ':'];
  44. function ComparePChar(p1, p2: PChar): boolean;
  45. begin
  46. if p1<>p2 then begin
  47. if (p1<>nil) and (p2<>nil) then begin
  48. while true do begin
  49. if (p1^=p2^) then begin
  50. if p1^<>#0 then begin
  51. inc(p1);
  52. inc(p2);
  53. end else begin
  54. Result:=true;
  55. exit;
  56. end;
  57. end else begin
  58. Result:=false;
  59. exit;
  60. end;
  61. end;
  62. Result:=true;
  63. end else begin
  64. Result:=false;
  65. end;
  66. end else begin
  67. Result:=true;
  68. end;
  69. end;
  70. function CompareLPChar(p1, p2: PChar; Max: integer): boolean;
  71. begin
  72. if p1<>p2 then begin
  73. if (p1<>nil) and (p2<>nil) then begin
  74. while Max>0 do begin
  75. if (p1^=p2^) then begin
  76. if (p1^<>#0) then begin
  77. inc(p1);
  78. inc(p2);
  79. dec(Max);
  80. end else begin
  81. Result:=true;
  82. exit;
  83. end;
  84. end else begin
  85. Result:=false;
  86. exit;
  87. end;
  88. end;
  89. Result:=true;
  90. end else begin
  91. Result:=false;
  92. end;
  93. end else begin
  94. Result:=true;
  95. end;
  96. end;
  97. function CompareIPChar(p1, p2: PChar): boolean;
  98. begin
  99. if p1<>p2 then begin
  100. if (p1<>nil) and (p2<>nil) then begin
  101. while true do begin
  102. if (p1^=p2^) or (upcase(p1^)=upcase(p2^)) then begin
  103. if p1^<>#0 then begin
  104. inc(p1);
  105. inc(p2);
  106. end else begin
  107. Result:=true;
  108. exit;
  109. end;
  110. end else begin
  111. Result:=false;
  112. exit;
  113. end;
  114. end;
  115. Result:=true;
  116. end else begin
  117. Result:=false;
  118. end;
  119. end else begin
  120. Result:=true;
  121. end;
  122. end;
  123. function CompareLIPChar(p1, p2: PChar; Max: integer): boolean;
  124. begin
  125. if p1<>p2 then begin
  126. if (p1<>nil) and (p2<>nil) then begin
  127. while Max>0 do begin
  128. if (p1^=p2^) or (upcase(p1^)=upcase(p2^)) then begin
  129. if (p1^<>#0) then begin
  130. inc(p1);
  131. inc(p2);
  132. dec(Max);
  133. end else begin
  134. Result:=true;
  135. exit;
  136. end;
  137. end else begin
  138. Result:=false;
  139. exit;
  140. end;
  141. end;
  142. Result:=true;
  143. end else begin
  144. Result:=false;
  145. end;
  146. end else begin
  147. Result:=true;
  148. end;
  149. end;
  150. type
  151. TXMLReaderDocument = class(TXMLDocument)
  152. public
  153. procedure SetDocType(ADocType: TDOMDocumentType);
  154. end;
  155. TXMLReaderDocumentType = class(TDOMDocumentType)
  156. public
  157. constructor Create(ADocument: TXMLReaderDocument);
  158. property Name: DOMString read FNodeName write FNodeName;
  159. end;
  160. TSetOfChar = set of Char;
  161. TXMLReader = class
  162. protected
  163. buf, BufStart: PChar;
  164. Filename: String;
  165. procedure RaiseExc(const descr: String);
  166. function SkipWhitespace: Boolean;
  167. procedure ExpectWhitespace;
  168. procedure ExpectString(const s: String);
  169. function CheckFor(s: PChar): Boolean;
  170. function CheckForChar(c: Char): Boolean;
  171. procedure SkipString(const ValidChars: TSetOfChar);
  172. function GetString(const ValidChars: TSetOfChar): String;
  173. function GetString(BufPos: PChar; Len: integer): String;
  174. function CheckName: Boolean;
  175. function GetName(var s: String): Boolean;
  176. function ExpectName: String; // [5]
  177. procedure SkipName;
  178. procedure ExpectAttValue(attr: TDOMAttr); // [10]
  179. function ExpectPubidLiteral: String; // [12]
  180. procedure SkipPubidLiteral;
  181. function ParseComment(AOwner: TDOMNode): Boolean; // [15]
  182. function ParsePI: Boolean; // [16]
  183. procedure ExpectProlog; // [22]
  184. function ParseEq: Boolean; // [25]
  185. procedure ExpectEq;
  186. procedure ParseMisc(AOwner: TDOMNode); // [27]
  187. function ParseMarkupDecl: Boolean; // [29]
  188. function ParseCharData(AOwner: TDOMNode): Boolean; // [14]
  189. function ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
  190. function ParseElement(AOwner: TDOMNode): Boolean; // [39]
  191. procedure ExpectElement(AOwner: TDOMNode);
  192. function ParseReference(AOwner: TDOMNode): Boolean; // [67]
  193. procedure ExpectReference(AOwner: TDOMNode);
  194. function ParsePEReference: Boolean; // [69]
  195. function ParseExternalID: Boolean; // [75]
  196. procedure ExpectExternalID;
  197. function ParseEncodingDecl: String; // [80]
  198. procedure SkipEncodingDecl;
  199. procedure ResolveEntities(RootNode: TDOMNode);
  200. public
  201. doc: TDOMDocument;
  202. procedure ProcessXML(ABuf: PChar; const AFilename: String); // [1]
  203. procedure ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
  204. procedure ProcessDTD(ABuf: PChar; const AFilename: String); // ([29])
  205. end;
  206. { TXMLReaderDocument }
  207. procedure TXMLReaderDocument.SetDocType(ADocType: TDOMDocumentType);
  208. begin
  209. FDocType := ADocType;
  210. end;
  211. constructor TXMLReaderDocumentType.Create(ADocument: TXMLReaderDocument);
  212. begin
  213. inherited Create(ADocument);
  214. end;
  215. procedure TXMLReader.RaiseExc(const descr: String);
  216. var
  217. apos: PChar;
  218. x, y: Integer;
  219. begin
  220. // find out the line in which the error occured
  221. apos := BufStart;
  222. x := 1;
  223. y := 1;
  224. while apos < buf do begin
  225. if apos[0] = #10 then begin
  226. Inc(y);
  227. x := 1;
  228. end else
  229. Inc(x);
  230. Inc(apos);
  231. end;
  232. raise EXMLReadError.Create('In ' + Filename + ' (line ' + IntToStr(y) + ' pos ' +
  233. IntToStr(x) + '): ' + descr);
  234. end;
  235. function TXMLReader.SkipWhitespace: Boolean;
  236. begin
  237. Result := False;
  238. while buf[0] in WhitespaceChars do
  239. begin
  240. Inc(buf);
  241. Result := True;
  242. end;
  243. end;
  244. procedure TXMLReader.ExpectWhitespace;
  245. begin
  246. if not SkipWhitespace then
  247. RaiseExc('Expected whitespace');
  248. end;
  249. procedure TXMLReader.ExpectString(const s: String);
  250. procedure RaiseStringNotFound;
  251. var
  252. s2: PChar;
  253. s3: String;
  254. begin
  255. GetMem(s2, Length(s) + 1);
  256. StrLCopy(s2, buf, Length(s));
  257. s3 := StrPas(s2);
  258. FreeMem(s2);
  259. RaiseExc('Expected "' + s + '", found "' + s3 + '"');
  260. end;
  261. var
  262. i: Integer;
  263. begin
  264. for i := 1 to Length(s) do
  265. if buf[i - 1] <> s[i] then begin
  266. RaiseStringNotFound;
  267. end;
  268. Inc(buf, Length(s));
  269. end;
  270. function TXMLReader.CheckFor(s: PChar): Boolean;
  271. begin
  272. if buf[0] <> #0 then begin
  273. if (buf[0]=s[0]) and (CompareLPChar(buf, s, StrLen(s))) then begin
  274. Inc(buf, StrLen(s));
  275. Result := True;
  276. end else
  277. Result := False;
  278. end else begin
  279. Result := False;
  280. end;
  281. end;
  282. function TXMLReader.CheckForChar(c: Char): Boolean;
  283. begin
  284. if (buf[0]=c) and (c<>#0) then begin
  285. inc(buf);
  286. Result:=true;
  287. end else begin
  288. Result:=false;
  289. end;
  290. end;
  291. procedure TXMLReader.SkipString(const ValidChars: TSetOfChar);
  292. begin
  293. while buf[0] in ValidChars do begin
  294. Inc(buf);
  295. end;
  296. end;
  297. function TXMLReader.GetString(const ValidChars: TSetOfChar): String;
  298. var
  299. OldBuf: PChar;
  300. i, len: integer;
  301. begin
  302. OldBuf:=Buf;
  303. while buf[0] in ValidChars do begin
  304. Inc(buf);
  305. end;
  306. len:=buf-OldBuf;
  307. SetLength(Result, Len);
  308. for i:=1 to len do begin
  309. Result[i]:=OldBuf[0];
  310. inc(OldBuf);
  311. end;
  312. end;
  313. function TXMLReader.GetString(BufPos: PChar; Len: integer): string;
  314. var i: integer;
  315. begin
  316. SetLength(Result,Len);
  317. for i:=1 to Len do begin
  318. Result[i]:=BufPos[0];
  319. inc(BufPos);
  320. end;
  321. end;
  322. {$IFDEF FPC}
  323. {$IFNDEF VER1_0}
  324. {$DEFINE UsesFPCWidestrings}
  325. {$ENDIF}
  326. {$ENDIF}
  327. {$IFDEF UsesFPCWidestrings}
  328. {procedure SimpleWide2AnsiMove(source:pwidechar;dest:pchar;len:sizeint);
  329. var
  330. i : sizeint;
  331. begin
  332. for i:=1 to len do
  333. begin
  334. if word(source^)<256 then
  335. dest^:=char(word(source^))
  336. else
  337. dest^:='?';
  338. inc(dest);
  339. inc(source);
  340. end;
  341. end;
  342. procedure SimpleAnsi2WideMove(source:pchar;dest:pwidechar;len:sizeint);
  343. var
  344. i : sizeint;
  345. begin
  346. for i:=1 to len do
  347. begin
  348. dest^:=widechar(byte(source^));
  349. inc(dest);
  350. inc(source);
  351. end;
  352. end;
  353. }
  354. {$ENDIF}
  355. procedure TXMLReader.ProcessXML(ABuf: PChar; const AFilename: String); // [1]
  356. {$IFDEF UsesFPCWidestrings}
  357. var
  358. OldWideStringManager,MyWideStringManager : TWideStringManager;
  359. {$ENDIF}
  360. begin
  361. buf := ABuf;
  362. BufStart := ABuf;
  363. Filename := AFilename;
  364. {$IFDEF UsesFPCWidestrings}
  365. GetWideStringManager(MyWideStringManager);
  366. MyWideStringManager.Wide2AnsiMoveProc:=@defaultWide2AnsiMove;
  367. MyWideStringManager.Ansi2WideMoveProc:=@defaultAnsi2WideMove;
  368. SetWideStringManager(MyWideStringManager, OldWideStringManager);
  369. try
  370. {$ENDIF}
  371. doc := TXMLReaderDocument.Create;
  372. ExpectProlog;
  373. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML A');{$ENDIF}
  374. ExpectElement(doc);
  375. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML B');{$ENDIF}
  376. ParseMisc(doc);
  377. {$IFDEF UsesFPCWidestrings}
  378. finally
  379. SetWideStringManager(OldWideStringManager);
  380. end;
  381. {$ENDIF}
  382. if buf[0] <> #0 then
  383. RaiseExc('Text after end of document element found');
  384. end;
  385. procedure TXMLReader.ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
  386. {$IFDEF UsesFPCWidestrings}
  387. var
  388. OldWideStringManager: TWideStringManager;
  389. {$ENDIF}
  390. begin
  391. buf := ABuf;
  392. BufStart := ABuf;
  393. Filename := AFilename;
  394. {$IFDEF UsesFPCWidestrings}
  395. SetWideStringManager(WideStringManager, OldWideStringManager);
  396. try
  397. {$ENDIF}
  398. SkipWhitespace;
  399. while ParseCharData(AOwner) or ParseCDSect(AOwner) or ParsePI or
  400. ParseComment(AOwner) or ParseElement(AOwner) or
  401. ParseReference(AOwner) do
  402. SkipWhitespace;
  403. {$IFDEF UsesFPCWidestrings}
  404. finally
  405. SetWideStringManager(OldWideStringManager);
  406. end;
  407. {$ENDIF}
  408. end;
  409. function TXMLReader.CheckName: Boolean;
  410. var OldBuf: PChar;
  411. begin
  412. if not (buf[0] in (Letter + ['_', ':'])) then begin
  413. Result := False;
  414. exit;
  415. end;
  416. OldBuf := buf;
  417. Inc(buf);
  418. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  419. buf := OldBuf;
  420. Result := True;
  421. end;
  422. function TXMLReader.GetName(var s: String): Boolean; // [5]
  423. var OldBuf: PChar;
  424. begin
  425. if not (buf[0] in (Letter + ['_', ':'])) then begin
  426. SetLength(s, 0);
  427. Result := False;
  428. exit;
  429. end;
  430. OldBuf := buf;
  431. Inc(buf);
  432. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  433. s := GetString(OldBuf,buf-OldBuf);
  434. Result := True;
  435. end;
  436. function TXMLReader.ExpectName: String; // [5]
  437. procedure RaiseNameNotFound;
  438. begin
  439. RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
  440. end;
  441. var OldBuf: PChar;
  442. begin
  443. if not (buf[0] in (Letter + ['_', ':'])) then
  444. RaiseNameNotFound;
  445. OldBuf := buf;
  446. Inc(buf);
  447. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  448. Result:=GetString(OldBuf,buf-OldBuf);
  449. end;
  450. procedure TXMLReader.SkipName;
  451. procedure RaiseSkipNameNotFound;
  452. begin
  453. RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
  454. end;
  455. begin
  456. if not (buf[0] in (Letter + ['_', ':'])) then
  457. RaiseSkipNameNotFound;
  458. Inc(buf);
  459. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  460. end;
  461. procedure TXMLReader.ExpectAttValue(attr: TDOMAttr); // [10]
  462. var
  463. OldBuf: PChar;
  464. procedure FlushStringBuffer;
  465. var
  466. s: String;
  467. begin
  468. if OldBuf<>buf then begin
  469. s := GetString(OldBuf,buf-OldBuf);
  470. OldBuf := buf;
  471. attr.AppendChild(doc.CreateTextNode(s));
  472. SetLength(s, 0);
  473. end;
  474. end;
  475. var
  476. StrDel: char;
  477. begin
  478. if (buf[0] <> '''') and (buf[0] <> '"') then
  479. RaiseExc('Expected quotation marks');
  480. StrDel:=buf[0];
  481. Inc(buf);
  482. OldBuf := buf;
  483. while (buf[0]<>StrDel) and (buf[0]<>#0) do begin
  484. if buf[0] <> '&' then begin
  485. Inc(buf);
  486. end else
  487. begin
  488. if OldBuf<>buf then FlushStringBuffer;
  489. ParseReference(attr);
  490. OldBuf := buf;
  491. end;
  492. end;
  493. if OldBuf<>buf then FlushStringBuffer;
  494. inc(buf);
  495. ResolveEntities(Attr);
  496. end;
  497. function TXMLReader.ExpectPubidLiteral: String;
  498. begin
  499. SetLength(Result, 0);
  500. if CheckForChar('''') then begin
  501. SkipString(PubidChars - ['''']);
  502. ExpectString('''');
  503. end else if CheckForChar('"') then begin
  504. SkipString(PubidChars - ['"']);
  505. ExpectString('"');
  506. end else
  507. RaiseExc('Expected quotation marks');
  508. end;
  509. procedure TXMLReader.SkipPubidLiteral;
  510. begin
  511. if CheckForChar('''') then begin
  512. SkipString(PubidChars - ['''']);
  513. ExpectString('''');
  514. end else if CheckForChar('"') then begin
  515. SkipString(PubidChars - ['"']);
  516. ExpectString('"');
  517. end else
  518. RaiseExc('Expected quotation marks');
  519. end;
  520. function TXMLReader.ParseComment(AOwner: TDOMNode): Boolean; // [15]
  521. var
  522. comment: String;
  523. OldBuf: PChar;
  524. begin
  525. if CheckFor('<!--') then begin
  526. OldBuf := buf;
  527. while (buf[0] <> #0) and (buf[1] <> #0) and
  528. ((buf[0] <> '-') or (buf[1] <> '-')) do begin
  529. Inc(buf);
  530. end;
  531. comment:=GetString(OldBuf,buf-OldBuf);
  532. AOwner.AppendChild(doc.CreateComment(comment));
  533. ExpectString('-->');
  534. Result := True;
  535. end else
  536. Result := False;
  537. end;
  538. function TXMLReader.ParsePI: Boolean; // [16]
  539. begin
  540. if CheckFor('<?') then begin
  541. if CompareLIPChar(buf,'XML ',4) then
  542. RaiseExc('"<?xml" processing instruction not allowed here');
  543. SkipName;
  544. if SkipWhitespace then
  545. while (buf[0] <> #0) and (buf[1] <> #0) and not
  546. ((buf[0] = '?') and (buf[1] = '>')) do Inc(buf);
  547. ExpectString('?>');
  548. Result := True;
  549. end else
  550. Result := False;
  551. end;
  552. procedure TXMLReader.ExpectProlog; // [22]
  553. procedure ParseVersionNum;
  554. begin
  555. if doc.InheritsFrom(TXMLDocument) then
  556. TXMLDocument(doc).XMLVersion :=
  557. GetString(['a'..'z', 'A'..'Z', '0'..'9', '_', '.', ':', '-']);
  558. end;
  559. procedure ParseDoctypeDecls;
  560. begin
  561. repeat
  562. SkipWhitespace;
  563. until not (ParseMarkupDecl or ParsePEReference);
  564. ExpectString(']');
  565. end;
  566. var
  567. DocType: TXMLReaderDocumentType;
  568. begin
  569. if CheckFor('<?xml') then
  570. begin
  571. // '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
  572. // VersionInfo: S 'version' Eq (' VersionNum ' | " VersionNum ")
  573. SkipWhitespace;
  574. ExpectString('version');
  575. ParseEq;
  576. if buf[0] = '''' then
  577. begin
  578. Inc(buf);
  579. ParseVersionNum;
  580. ExpectString('''');
  581. end else if buf[0] = '"' then
  582. begin
  583. Inc(buf);
  584. ParseVersionNum;
  585. ExpectString('"');
  586. end else
  587. RaiseExc('Expected single or double quotation mark');
  588. // EncodingDecl?
  589. SkipEncodingDecl;
  590. // SDDecl?
  591. SkipWhitespace;
  592. if CheckFor('standalone') then
  593. begin
  594. ExpectEq;
  595. if buf[0] = '''' then
  596. begin
  597. Inc(buf);
  598. if not (CheckFor('yes''') or CheckFor('no''')) then
  599. RaiseExc('Expected ''yes'' or ''no''');
  600. end else if buf[0] = '''' then
  601. begin
  602. Inc(buf);
  603. if not (CheckFor('yes"') or CheckFor('no"')) then
  604. RaiseExc('Expected "yes" or "no"');
  605. end;
  606. SkipWhitespace;
  607. end;
  608. ExpectString('?>');
  609. end;
  610. // Check for "Misc*"
  611. ParseMisc(doc);
  612. // Check for "(doctypedecl Misc*)?" [28]
  613. if CheckFor('<!DOCTYPE') then
  614. begin
  615. DocType := TXMLReaderDocumentType.Create(doc as TXMLReaderDocument);
  616. if doc.InheritsFrom(TXMLReaderDocument) then
  617. TXMLReaderDocument(doc).SetDocType(DocType);
  618. SkipWhitespace;
  619. DocType.Name := ExpectName;
  620. SkipWhitespace;
  621. if CheckForChar('[') then
  622. begin
  623. ParseDoctypeDecls;
  624. SkipWhitespace;
  625. ExpectString('>');
  626. end else if not CheckForChar('>') then
  627. begin
  628. ParseExternalID;
  629. SkipWhitespace;
  630. if CheckForChar('[') then
  631. begin
  632. ParseDoctypeDecls;
  633. SkipWhitespace;
  634. end;
  635. ExpectString('>');
  636. end;
  637. ParseMisc(doc);
  638. end;
  639. end;
  640. function TXMLReader.ParseEq: Boolean; // [25]
  641. var
  642. savedbuf: PChar;
  643. begin
  644. savedbuf := buf;
  645. SkipWhitespace;
  646. if buf[0] = '=' then begin
  647. Inc(buf);
  648. SkipWhitespace;
  649. Result := True;
  650. end else begin
  651. buf := savedbuf;
  652. Result := False;
  653. end;
  654. end;
  655. procedure TXMLReader.ExpectEq;
  656. begin
  657. if not ParseEq then
  658. RaiseExc('Expected "="');
  659. end;
  660. // Parse "Misc*":
  661. // Misc ::= Comment | PI | S
  662. procedure TXMLReader.ParseMisc(AOwner: TDOMNode); // [27]
  663. begin
  664. repeat
  665. SkipWhitespace;
  666. until not (ParseComment(AOwner) or ParsePI);
  667. end;
  668. function TXMLReader.ParseMarkupDecl: Boolean; // [29]
  669. function ParseElementDecl: Boolean; // [45]
  670. procedure ExpectChoiceOrSeq; // [49], [50]
  671. procedure ExpectCP; // [48]
  672. begin
  673. if CheckForChar('(') then
  674. ExpectChoiceOrSeq
  675. else
  676. SkipName;
  677. if CheckForChar('?') then
  678. else if CheckForChar('*') then
  679. else if CheckForChar('+') then;
  680. end;
  681. var
  682. delimiter: Char;
  683. begin
  684. SkipWhitespace;
  685. ExpectCP;
  686. SkipWhitespace;
  687. delimiter := #0;
  688. while not CheckForChar(')') do begin
  689. if delimiter = #0 then begin
  690. if (buf[0] = '|') or (buf[0] = ',') then
  691. delimiter := buf[0]
  692. else
  693. RaiseExc('Expected "|" or ","');
  694. Inc(buf);
  695. end else
  696. ExpectString(delimiter);
  697. SkipWhitespace;
  698. ExpectCP;
  699. end;
  700. end;
  701. begin
  702. if CheckFor('<!ELEMENT') then begin
  703. ExpectWhitespace;
  704. SkipName;
  705. ExpectWhitespace;
  706. // Get contentspec [46]
  707. if CheckFor('EMPTY') then
  708. else if CheckFor('ANY') then
  709. else if CheckForChar('(') then begin
  710. SkipWhitespace;
  711. if CheckFor('#PCDATA') then begin
  712. // Parse Mixed section [51]
  713. SkipWhitespace;
  714. if not CheckForChar(')') then
  715. repeat
  716. ExpectString('|');
  717. SkipWhitespace;
  718. SkipName;
  719. until CheckFor(')*');
  720. end else begin
  721. // Parse Children section [47]
  722. ExpectChoiceOrSeq;
  723. if CheckForChar('?') then
  724. else if CheckForChar('*') then
  725. else if CheckForChar('+') then;
  726. end;
  727. end else
  728. RaiseExc('Invalid content specification');
  729. SkipWhitespace;
  730. ExpectString('>');
  731. Result := True;
  732. end else
  733. Result := False;
  734. end;
  735. function ParseAttlistDecl: Boolean; // [52]
  736. var
  737. attr: TDOMAttr;
  738. begin
  739. if CheckFor('<!ATTLIST') then begin
  740. ExpectWhitespace;
  741. SkipName;
  742. SkipWhitespace;
  743. while not CheckForChar('>') do begin
  744. SkipName;
  745. ExpectWhitespace;
  746. // Get AttType [54], [55], [56]
  747. if CheckFor('CDATA') then
  748. else if CheckFor('ID') then
  749. else if CheckFor('IDREF') then
  750. else if CheckFor('IDREFS') then
  751. else if CheckFor('ENTITTY') then
  752. else if CheckFor('ENTITIES') then
  753. else if CheckFor('NMTOKEN') then
  754. else if CheckFor('NMTOKENS') then
  755. else if CheckFor('NOTATION') then begin // [57], [58]
  756. ExpectWhitespace;
  757. ExpectString('(');
  758. SkipWhitespace;
  759. SkipName;
  760. SkipWhitespace;
  761. while not CheckForChar(')') do begin
  762. ExpectString('|');
  763. SkipWhitespace;
  764. SkipName;
  765. SkipWhitespace;
  766. end;
  767. end else if CheckForChar('(') then begin // [59]
  768. SkipWhitespace;
  769. SkipString(Nmtoken);
  770. SkipWhitespace;
  771. while not CheckForChar(')') do begin
  772. ExpectString('|');
  773. SkipWhitespace;
  774. SkipString(Nmtoken);
  775. SkipWhitespace;
  776. end;
  777. end else
  778. RaiseExc('Invalid tokenized type');
  779. ExpectWhitespace;
  780. // Get DefaultDecl [60]
  781. if CheckFor('#REQUIRED') then
  782. else if CheckFor('#IMPLIED') then
  783. else begin
  784. if CheckFor('#FIXED') then
  785. SkipWhitespace;
  786. attr := doc.CreateAttribute('');
  787. ExpectAttValue(attr);
  788. end;
  789. SkipWhitespace;
  790. end;
  791. Result := True;
  792. end else
  793. Result := False;
  794. end;
  795. function ParseEntityDecl: Boolean; // [70]
  796. var
  797. NewEntity: TDOMEntity;
  798. function ParseEntityValue: Boolean; // [9]
  799. var
  800. strdel: Char;
  801. begin
  802. if (buf[0] <> '''') and (buf[0] <> '"') then begin
  803. Result := False;
  804. exit;
  805. end;
  806. strdel := buf[0];
  807. Inc(buf);
  808. while not CheckForChar(strdel) do
  809. if ParsePEReference then
  810. else if ParseReference(NewEntity) then
  811. else begin
  812. Inc(buf); // Normal haracter
  813. end;
  814. Result := True;
  815. end;
  816. begin
  817. if CheckFor('<!ENTITY') then begin
  818. ExpectWhitespace;
  819. if CheckForChar('%') then begin // [72]
  820. ExpectWhitespace;
  821. NewEntity := doc.CreateEntity(ExpectName);
  822. ExpectWhitespace;
  823. // Get PEDef [74]
  824. if ParseEntityValue then
  825. else if ParseExternalID then
  826. else
  827. RaiseExc('Expected entity value or external ID');
  828. end else begin // [71]
  829. NewEntity := doc.CreateEntity(ExpectName);
  830. ExpectWhitespace;
  831. // Get EntityDef [73]
  832. if ParseEntityValue then
  833. else begin
  834. ExpectExternalID;
  835. // Get NDataDecl [76]
  836. ExpectWhitespace;
  837. ExpectString('NDATA');
  838. ExpectWhitespace;
  839. SkipName;
  840. end;
  841. end;
  842. SkipWhitespace;
  843. ExpectString('>');
  844. Result := True;
  845. end else
  846. Result := False;
  847. end;
  848. function ParseNotationDecl: Boolean; // [82]
  849. begin
  850. if CheckFor('<!NOTATION') then begin
  851. ExpectWhitespace;
  852. SkipName;
  853. ExpectWhitespace;
  854. if ParseExternalID then
  855. else if CheckFor('PUBLIC') then begin // [83]
  856. ExpectWhitespace;
  857. SkipPubidLiteral;
  858. end else
  859. RaiseExc('Expected external or public ID');
  860. SkipWhitespace;
  861. ExpectString('>');
  862. Result := True;
  863. end else
  864. Result := False;
  865. end;
  866. begin
  867. Result := False;
  868. while ParseElementDecl or ParseAttlistDecl or ParseEntityDecl or
  869. ParseNotationDecl or ParsePI or ParseComment(doc) or SkipWhitespace do
  870. Result := True;
  871. end;
  872. procedure TXMLReader.ProcessDTD(ABuf: PChar; const AFilename: String);
  873. begin
  874. buf := ABuf;
  875. BufStart := ABuf;
  876. Filename := AFilename;
  877. doc := TXMLReaderDocument.Create;
  878. ParseMarkupDecl;
  879. {
  880. if buf[0] <> #0 then begin
  881. DebugLn('=== Unparsed: ===');
  882. //DebugLn(buf);
  883. DebugLn(StrLen(buf), ' chars');
  884. end;
  885. }
  886. end;
  887. function TXMLReader.ParseCharData(AOwner: TDOMNode): Boolean; // [14]
  888. var
  889. p: PChar;
  890. DataLen: integer;
  891. OldBuf: PChar;
  892. begin
  893. OldBuf := buf;
  894. while not (buf[0] in [#0, '<', '&']) do
  895. begin
  896. Inc(buf);
  897. end;
  898. DataLen:=buf-OldBuf;
  899. if DataLen > 0 then
  900. begin
  901. // Check if chardata has non-whitespace content
  902. p:=OldBuf;
  903. while (p<buf) and (p[0] in WhitespaceChars) do
  904. inc(p);
  905. if p<buf then
  906. AOwner.AppendChild(doc.CreateTextNode(GetString(OldBuf,DataLen)));
  907. Result := True;
  908. end
  909. else
  910. Result := False;
  911. end;
  912. function TXMLReader.ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
  913. var
  914. OldBuf: PChar;
  915. begin
  916. if CheckFor('<![CDATA[') then
  917. begin
  918. OldBuf := buf;
  919. while not CheckFor(']]>') do
  920. begin
  921. Inc(buf);
  922. end;
  923. AOwner.AppendChild(doc.CreateCDATASection(GetString(OldBuf,buf-OldBuf-3))); { Copy CDATA, discarding terminator }
  924. Result := True;
  925. end
  926. else
  927. Result := False;
  928. end;
  929. function TXMLReader.ParseElement(AOwner: TDOMNode): Boolean; // [39] [40] [44]
  930. var
  931. NewElem: TDOMElement;
  932. procedure CreateNameElement;
  933. var
  934. IsEmpty: Boolean;
  935. attr: TDOMAttr;
  936. name: string;
  937. begin
  938. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement A');{$ENDIF}
  939. GetName(name);
  940. NewElem := doc.CreateElement(name);
  941. AOwner.AppendChild(NewElem);
  942. SkipWhitespace;
  943. IsEmpty := False;
  944. while True do
  945. begin
  946. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement E');{$ENDIF}
  947. if CheckFor('/>') then
  948. begin
  949. IsEmpty := True;
  950. break;
  951. end;
  952. if CheckForChar('>') then
  953. break;
  954. // Get Attribute [41]
  955. attr := doc.CreateAttribute(ExpectName);
  956. NewElem.Attributes.SetNamedItem(attr);
  957. ExpectEq;
  958. ExpectAttValue(attr);
  959. SkipWhitespace;
  960. end;
  961. if not IsEmpty then
  962. begin
  963. // Get content
  964. SkipWhitespace;
  965. while ParseCharData(NewElem) or ParseCDSect(NewElem) or ParsePI or
  966. ParseComment(NewElem) or ParseElement(NewElem) or
  967. ParseReference(NewElem) do;
  968. // Get ETag [42]
  969. ExpectString('</');
  970. if ExpectName <> name then
  971. RaiseExc('Unmatching element end tag (expected "</' + name + '>")');
  972. SkipWhitespace;
  973. ExpectString('>');
  974. end;
  975. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement END');{$ENDIF}
  976. ResolveEntities(NewElem);
  977. end;
  978. var
  979. OldBuf: PChar;
  980. begin
  981. OldBuf := Buf;
  982. if CheckForChar('<') then
  983. begin
  984. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement A');{$ENDIF}
  985. if not CheckName then
  986. begin
  987. Buf := OldBuf;
  988. Result := False;
  989. end else begin
  990. CreateNameElement;
  991. Result := True;
  992. end;
  993. end else
  994. Result := False;
  995. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement END');{$ENDIF}
  996. end;
  997. procedure TXMLReader.ExpectElement(AOwner: TDOMNode);
  998. begin
  999. if not ParseElement(AOwner) then
  1000. RaiseExc('Expected element');
  1001. end;
  1002. function TXMLReader.ParsePEReference: Boolean; // [69]
  1003. begin
  1004. if CheckForChar('%') then begin
  1005. SkipName;
  1006. ExpectString(';');
  1007. Result := True;
  1008. end else
  1009. Result := False;
  1010. end;
  1011. function TXMLReader.ParseReference(AOwner: TDOMNode): Boolean; // [67] [68]
  1012. begin
  1013. if not CheckForChar('&') then begin
  1014. Result := False;
  1015. exit;
  1016. end;
  1017. if CheckForChar('#') then begin // Test for CharRef [66]
  1018. if CheckForChar('x') then begin
  1019. // !!!: there must be at least one digit
  1020. while buf[0] in ['0'..'9', 'a'..'f', 'A'..'F'] do Inc(buf);
  1021. end else
  1022. // !!!: there must be at least one digit
  1023. while buf[0] in ['0'..'9'] do Inc(buf);
  1024. end else
  1025. AOwner.AppendChild(doc.CreateEntityReference(ExpectName));
  1026. ExpectString(';');
  1027. Result := True;
  1028. end;
  1029. procedure TXMLReader.ExpectReference(AOwner: TDOMNode);
  1030. begin
  1031. if not ParseReference(AOwner) then
  1032. RaiseExc('Expected reference ("&Name;" or "%Name;")');
  1033. end;
  1034. function TXMLReader.ParseExternalID: Boolean; // [75]
  1035. function GetSystemLiteral: String;
  1036. var
  1037. OldBuf: PChar;
  1038. begin
  1039. if buf[0] = '''' then begin
  1040. Inc(buf);
  1041. OldBuf := buf;
  1042. while (buf[0] <> '''') and (buf[0] <> #0) do begin
  1043. Inc(buf);
  1044. end;
  1045. Result := GetString(OldBuf,buf-OldBuf);
  1046. ExpectString('''');
  1047. end else if buf[0] = '"' then begin
  1048. Inc(buf);
  1049. OldBuf := buf;
  1050. while (buf[0] <> '"') and (buf[0] <> #0) do begin
  1051. Inc(buf);
  1052. end;
  1053. Result := GetString(OldBuf,buf-OldBuf);
  1054. ExpectString('"');
  1055. end else
  1056. Result:='';
  1057. end;
  1058. procedure SkipSystemLiteral;
  1059. begin
  1060. if buf[0] = '''' then begin
  1061. Inc(buf);
  1062. while (buf[0] <> '''') and (buf[0] <> #0) do begin
  1063. Inc(buf);
  1064. end;
  1065. ExpectString('''');
  1066. end else if buf[0] = '"' then begin
  1067. Inc(buf);
  1068. while (buf[0] <> '"') and (buf[0] <> #0) do begin
  1069. Inc(buf);
  1070. end;
  1071. ExpectString('"');
  1072. end;
  1073. end;
  1074. begin
  1075. if CheckFor('SYSTEM') then begin
  1076. ExpectWhitespace;
  1077. SkipSystemLiteral;
  1078. Result := True;
  1079. end else if CheckFor('PUBLIC') then begin
  1080. ExpectWhitespace;
  1081. SkipPubidLiteral;
  1082. ExpectWhitespace;
  1083. SkipSystemLiteral;
  1084. Result := True;
  1085. end else
  1086. Result := False;
  1087. end;
  1088. procedure TXMLReader.ExpectExternalID;
  1089. begin
  1090. if not ParseExternalID then
  1091. RaiseExc('Expected external ID');
  1092. end;
  1093. function TXMLReader.ParseEncodingDecl: String; // [80]
  1094. function ParseEncName: String;
  1095. var OldBuf: PChar;
  1096. begin
  1097. if not (buf[0] in ['A'..'Z', 'a'..'z']) then
  1098. RaiseExc('Expected character (A-Z, a-z)');
  1099. OldBuf := buf;
  1100. Inc(buf);
  1101. SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
  1102. Result := GetString(OldBuf,buf-OldBuf);
  1103. end;
  1104. begin
  1105. SetLength(Result, 0);
  1106. SkipWhitespace;
  1107. if CheckFor('encoding') then begin
  1108. ExpectEq;
  1109. if buf[0] = '''' then begin
  1110. Inc(buf);
  1111. Result := ParseEncName;
  1112. ExpectString('''');
  1113. end else if buf[0] = '"' then begin
  1114. Inc(buf);
  1115. Result := ParseEncName;
  1116. ExpectString('"');
  1117. end;
  1118. end;
  1119. end;
  1120. procedure TXMLReader.SkipEncodingDecl;
  1121. procedure ParseEncName;
  1122. begin
  1123. if not (buf[0] in ['A'..'Z', 'a'..'z']) then
  1124. RaiseExc('Expected character (A-Z, a-z)');
  1125. Inc(buf);
  1126. SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
  1127. end;
  1128. begin
  1129. SkipWhitespace;
  1130. if CheckFor('encoding') then begin
  1131. ExpectEq;
  1132. if buf[0] = '''' then begin
  1133. Inc(buf);
  1134. ParseEncName;
  1135. ExpectString('''');
  1136. end else if buf[0] = '"' then begin
  1137. Inc(buf);
  1138. ParseEncName;
  1139. ExpectString('"');
  1140. end;
  1141. end;
  1142. end;
  1143. { Currently, this method will only resolve the entities which are
  1144. predefined in XML: }
  1145. procedure TXMLReader.ResolveEntities(RootNode: TDOMNode);
  1146. var
  1147. Node, NextNode: TDOMNode;
  1148. procedure ReplaceEntityRef(EntityNode: TDOMNode; const Replacement: string);
  1149. var
  1150. PrevSibling, NextSibling: TDOMNode;
  1151. begin
  1152. PrevSibling := EntityNode.PreviousSibling;
  1153. NextSibling := EntityNode.NextSibling;
  1154. if Assigned(PrevSibling) and (PrevSibling.NodeType = TEXT_NODE) then
  1155. begin
  1156. TDOMCharacterData(PrevSibling).AppendData(Replacement);
  1157. RootNode.RemoveChild(EntityNode);
  1158. if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
  1159. begin
  1160. // next sibling is to be removed, so we can't use it anymore
  1161. NextNode := NextSibling.NextSibling;
  1162. TDOMCharacterData(PrevSibling).AppendData(
  1163. TDOMCharacterData(NextSibling).Data);
  1164. RootNode.RemoveChild(NextSibling);
  1165. end
  1166. end else
  1167. if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
  1168. begin
  1169. TDOMCharacterData(NextSibling).InsertData(0, Replacement);
  1170. RootNode.RemoveChild(EntityNode);
  1171. end else
  1172. RootNode.ReplaceChild(Doc.CreateTextNode(Replacement), EntityNode);
  1173. end;
  1174. begin
  1175. Node := RootNode.FirstChild;
  1176. while Assigned(Node) do
  1177. begin
  1178. NextNode := Node.NextSibling;
  1179. if Node.NodeType = ENTITY_REFERENCE_NODE then
  1180. if Node.NodeName = 'amp' then
  1181. ReplaceEntityRef(Node, '&')
  1182. else if Node.NodeName = 'apos' then
  1183. ReplaceEntityRef(Node, '''')
  1184. else if Node.NodeName = 'gt' then
  1185. ReplaceEntityRef(Node, '>')
  1186. else if Node.NodeName = 'lt' then
  1187. ReplaceEntityRef(Node, '<')
  1188. else if Node.NodeName = 'quot' then
  1189. ReplaceEntityRef(Node, '"');
  1190. Node := NextNode;
  1191. end;
  1192. end;
  1193. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: File);
  1194. var
  1195. reader: TXMLReader;
  1196. buf: PChar;
  1197. BufSize: LongInt;
  1198. begin
  1199. ADoc := nil;
  1200. BufSize := FileSize(f) + 1;
  1201. if BufSize <= 1 then
  1202. exit;
  1203. GetMem(buf, BufSize);
  1204. try
  1205. BlockRead(f, buf^, BufSize - 1);
  1206. buf[BufSize - 1] := #0;
  1207. Reader := TXMLReader.Create;
  1208. try
  1209. Reader.ProcessXML(buf, TFileRec(f).name);
  1210. ADoc := TXMLDocument(Reader.doc);
  1211. finally
  1212. Reader.Free;
  1213. end;
  1214. finally
  1215. FreeMem(buf);
  1216. end;
  1217. end;
  1218. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
  1219. var
  1220. reader: TXMLReader;
  1221. buf: PChar;
  1222. begin
  1223. ADoc := nil;
  1224. if f.Size = 0 then exit;
  1225. GetMem(buf, f.Size + 1);
  1226. try
  1227. f.Read(buf^, f.Size);
  1228. buf[f.Size] := #0;
  1229. Reader := TXMLReader.Create;
  1230. try
  1231. Reader.ProcessXML(buf, AFilename);
  1232. finally
  1233. ADoc := TXMLDocument(Reader.doc);
  1234. Reader.Free;
  1235. end;
  1236. finally
  1237. FreeMem(buf);
  1238. end;
  1239. end;
  1240. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream);
  1241. begin
  1242. ReadXMLFile(ADoc, f, '<Stream>');
  1243. end;
  1244. procedure ReadXMLFile(var ADoc: TXMLDocument; const AFilename: String);
  1245. var
  1246. FileStream: TFileStream;
  1247. MemStream: TMemoryStream;
  1248. begin
  1249. ADoc := nil;
  1250. FileStream := TFileStream.Create(AFilename, fmOpenRead);
  1251. if FileStream=nil then exit;
  1252. MemStream := TMemoryStream.Create;
  1253. try
  1254. MemStream.LoadFromStream(FileStream);
  1255. ReadXMLFile(ADoc, MemStream, AFilename);
  1256. finally
  1257. FileStream.Free;
  1258. MemStream.Free;
  1259. end;
  1260. end;
  1261. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File);
  1262. var
  1263. Reader: TXMLReader;
  1264. buf: PChar;
  1265. BufSize: LongInt;
  1266. begin
  1267. BufSize := FileSize(f) + 1;
  1268. if BufSize <= 1 then
  1269. exit;
  1270. GetMem(buf, BufSize);
  1271. try
  1272. BlockRead(f, buf^, BufSize - 1);
  1273. buf[BufSize - 1] := #0;
  1274. Reader := TXMLReader.Create;
  1275. try
  1276. Reader.Doc := AParentNode.OwnerDocument;
  1277. Reader.ProcessFragment(AParentNode, buf, TFileRec(f).name);
  1278. finally
  1279. Reader.Free;
  1280. end;
  1281. finally
  1282. FreeMem(buf);
  1283. end;
  1284. end;
  1285. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String);
  1286. var
  1287. Reader: TXMLReader;
  1288. buf: PChar;
  1289. begin
  1290. if f.Size = 0 then
  1291. exit;
  1292. GetMem(buf, f.Size + 1);
  1293. try
  1294. f.Read(buf^, f.Size);
  1295. buf[f.Size] := #0;
  1296. Reader := TXMLReader.Create;
  1297. Reader.Doc := AParentNode.OwnerDocument;
  1298. try
  1299. Reader.ProcessFragment(AParentNode, buf, AFilename);
  1300. finally
  1301. Reader.Free;
  1302. end;
  1303. finally
  1304. FreeMem(buf);
  1305. end;
  1306. end;
  1307. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream);
  1308. begin
  1309. ReadXMLFragment(AParentNode, f, '<Stream>');
  1310. end;
  1311. procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String);
  1312. var
  1313. Stream: TStream;
  1314. begin
  1315. Stream := TFileStream.Create(AFilename, fmOpenRead);
  1316. try
  1317. ReadXMLFragment(AParentNode, Stream, AFilename);
  1318. finally
  1319. Stream.Free;
  1320. end;
  1321. end;
  1322. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File);
  1323. var
  1324. Reader: TXMLReader;
  1325. buf: PChar;
  1326. BufSize: LongInt;
  1327. begin
  1328. ADoc := nil;
  1329. BufSize := FileSize(f) + 1;
  1330. if BufSize <= 1 then
  1331. exit;
  1332. GetMem(buf, BufSize);
  1333. try
  1334. BlockRead(f, buf^, BufSize - 1);
  1335. buf[BufSize - 1] := #0;
  1336. Reader := TXMLReader.Create;
  1337. try
  1338. Reader.ProcessDTD(buf, TFileRec(f).name);
  1339. ADoc := TXMLDocument(Reader.doc);
  1340. finally
  1341. Reader.Free;
  1342. end;
  1343. finally
  1344. FreeMem(buf);
  1345. end;
  1346. end;
  1347. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
  1348. var
  1349. Reader: TXMLReader;
  1350. buf: PChar;
  1351. begin
  1352. ADoc := nil;
  1353. if f.Size = 0 then
  1354. exit;
  1355. GetMem(buf, f.Size + 1);
  1356. try
  1357. f.Read(buf^, f.Size);
  1358. buf[f.Size] := #0;
  1359. Reader := TXMLReader.Create;
  1360. try
  1361. Reader.ProcessDTD(buf, AFilename);
  1362. ADoc := TXMLDocument(Reader.doc);
  1363. finally
  1364. Reader.Free;
  1365. end;
  1366. finally
  1367. FreeMem(buf);
  1368. end;
  1369. end;
  1370. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream);
  1371. begin
  1372. ReadDTDFile(ADoc, f, '<Stream>');
  1373. end;
  1374. procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String);
  1375. var
  1376. Stream: TStream;
  1377. begin
  1378. ADoc := nil;
  1379. Stream := TFileStream.Create(AFilename, fmOpenRead);
  1380. try
  1381. ReadDTDFile(ADoc, Stream, AFilename);
  1382. finally
  1383. Stream.Free;
  1384. end;
  1385. end;
  1386. end.
  1387. {
  1388. $Log$
  1389. Revision 1.17 2005-05-02 13:06:51 michael
  1390. + Patch from Vincent Snijders to fix reading of entities
  1391. Revision 1.16 2005/03/14 21:10:12 florian
  1392. * adapated for the new widestring manager
  1393. Revision 1.15 2005/02/14 17:13:18 peter
  1394. * truncate log
  1395. Revision 1.14 2005/02/01 20:23:39 florian
  1396. * adapted to new widestring manager
  1397. Revision 1.13 2005/01/22 20:54:51 michael
  1398. * Patch from Colin Western to correctly read CDATA
  1399. }