xmlread.pp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572
  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. const
  354. WideStringManager: TWideStringManager = (
  355. Wide2AnsiMove: @SimpleWide2AnsiMove;
  356. Ansi2WideMove: @SimpleAnsi2WideMove
  357. );
  358. {$ENDIF}
  359. procedure TXMLReader.ProcessXML(ABuf: PChar; const AFilename: String); // [1]
  360. {$IFDEF UsesFPCWidestrings}
  361. var
  362. OldWideStringManager: TWideStringManager;
  363. {$ENDIF}
  364. begin
  365. buf := ABuf;
  366. BufStart := ABuf;
  367. Filename := AFilename;
  368. {$IFDEF UsesFPCWidestrings}
  369. SetWideStringManager(WideStringManager, OldWideStringManager);
  370. try
  371. {$ENDIF}
  372. doc := TXMLReaderDocument.Create;
  373. ExpectProlog;
  374. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML A');{$ENDIF}
  375. ExpectElement(doc);
  376. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML B');{$ENDIF}
  377. ParseMisc(doc);
  378. {$IFDEF UsesFPCWidestrings}
  379. finally
  380. SetWideStringManager(OldWideStringManager);
  381. end;
  382. {$ENDIF}
  383. if buf[0] <> #0 then
  384. RaiseExc('Text after end of document element found');
  385. end;
  386. procedure TXMLReader.ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
  387. {$IFDEF UsesFPCWidestrings}
  388. var
  389. OldWideStringManager: TWideStringManager;
  390. {$ENDIF}
  391. begin
  392. buf := ABuf;
  393. BufStart := ABuf;
  394. Filename := AFilename;
  395. {$IFDEF UsesFPCWidestrings}
  396. SetWideStringManager(WideStringManager, OldWideStringManager);
  397. try
  398. {$ENDIF}
  399. SkipWhitespace;
  400. while ParseCharData(AOwner) or ParseCDSect(AOwner) or ParsePI or
  401. ParseComment(AOwner) or ParseElement(AOwner) or
  402. ParseReference(AOwner) do
  403. SkipWhitespace;
  404. {$IFDEF UsesFPCWidestrings}
  405. finally
  406. SetWideStringManager(OldWideStringManager);
  407. end;
  408. {$ENDIF}
  409. end;
  410. function TXMLReader.CheckName: Boolean;
  411. var OldBuf: PChar;
  412. begin
  413. if not (buf[0] in (Letter + ['_', ':'])) then begin
  414. Result := False;
  415. exit;
  416. end;
  417. OldBuf := buf;
  418. Inc(buf);
  419. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  420. buf := OldBuf;
  421. Result := True;
  422. end;
  423. function TXMLReader.GetName(var s: String): Boolean; // [5]
  424. var OldBuf: PChar;
  425. begin
  426. if not (buf[0] in (Letter + ['_', ':'])) then begin
  427. SetLength(s, 0);
  428. Result := False;
  429. exit;
  430. end;
  431. OldBuf := buf;
  432. Inc(buf);
  433. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  434. s := GetString(OldBuf,buf-OldBuf);
  435. Result := True;
  436. end;
  437. function TXMLReader.ExpectName: String; // [5]
  438. procedure RaiseNameNotFound;
  439. begin
  440. RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
  441. end;
  442. var OldBuf: PChar;
  443. begin
  444. if not (buf[0] in (Letter + ['_', ':'])) then
  445. RaiseNameNotFound;
  446. OldBuf := buf;
  447. Inc(buf);
  448. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  449. Result:=GetString(OldBuf,buf-OldBuf);
  450. end;
  451. procedure TXMLReader.SkipName;
  452. procedure RaiseSkipNameNotFound;
  453. begin
  454. RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
  455. end;
  456. begin
  457. if not (buf[0] in (Letter + ['_', ':'])) then
  458. RaiseSkipNameNotFound;
  459. Inc(buf);
  460. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  461. end;
  462. procedure TXMLReader.ExpectAttValue(attr: TDOMAttr); // [10]
  463. var
  464. OldBuf: PChar;
  465. procedure FlushStringBuffer;
  466. var
  467. s: String;
  468. begin
  469. if OldBuf<>buf then begin
  470. s := GetString(OldBuf,buf-OldBuf);
  471. OldBuf := buf;
  472. attr.AppendChild(doc.CreateTextNode(s));
  473. SetLength(s, 0);
  474. end;
  475. end;
  476. var
  477. StrDel: char;
  478. begin
  479. if (buf[0] <> '''') and (buf[0] <> '"') then
  480. RaiseExc('Expected quotation marks');
  481. StrDel:=buf[0];
  482. Inc(buf);
  483. OldBuf := buf;
  484. while (buf[0]<>StrDel) and (buf[0]<>#0) do begin
  485. if buf[0] <> '&' then begin
  486. Inc(buf);
  487. end else
  488. begin
  489. if OldBuf<>buf then FlushStringBuffer;
  490. ParseReference(attr);
  491. OldBuf := buf;
  492. end;
  493. end;
  494. if OldBuf<>buf then FlushStringBuffer;
  495. inc(buf);
  496. ResolveEntities(Attr);
  497. end;
  498. function TXMLReader.ExpectPubidLiteral: String;
  499. begin
  500. SetLength(Result, 0);
  501. if CheckForChar('''') then begin
  502. SkipString(PubidChars - ['''']);
  503. ExpectString('''');
  504. end else if CheckForChar('"') then begin
  505. SkipString(PubidChars - ['"']);
  506. ExpectString('"');
  507. end else
  508. RaiseExc('Expected quotation marks');
  509. end;
  510. procedure TXMLReader.SkipPubidLiteral;
  511. begin
  512. if CheckForChar('''') then begin
  513. SkipString(PubidChars - ['''']);
  514. ExpectString('''');
  515. end else if CheckForChar('"') then begin
  516. SkipString(PubidChars - ['"']);
  517. ExpectString('"');
  518. end else
  519. RaiseExc('Expected quotation marks');
  520. end;
  521. function TXMLReader.ParseComment(AOwner: TDOMNode): Boolean; // [15]
  522. var
  523. comment: String;
  524. OldBuf: PChar;
  525. begin
  526. if CheckFor('<!--') then begin
  527. OldBuf := buf;
  528. while (buf[0] <> #0) and (buf[1] <> #0) and
  529. ((buf[0] <> '-') or (buf[1] <> '-')) do begin
  530. Inc(buf);
  531. end;
  532. comment:=GetString(OldBuf,buf-OldBuf);
  533. AOwner.AppendChild(doc.CreateComment(comment));
  534. ExpectString('-->');
  535. Result := True;
  536. end else
  537. Result := False;
  538. end;
  539. function TXMLReader.ParsePI: Boolean; // [16]
  540. begin
  541. if CheckFor('<?') then begin
  542. if CompareLIPChar(buf,'XML ',4) then
  543. RaiseExc('"<?xml" processing instruction not allowed here');
  544. SkipName;
  545. if SkipWhitespace then
  546. while (buf[0] <> #0) and (buf[1] <> #0) and not
  547. ((buf[0] = '?') and (buf[1] = '>')) do Inc(buf);
  548. ExpectString('?>');
  549. Result := True;
  550. end else
  551. Result := False;
  552. end;
  553. procedure TXMLReader.ExpectProlog; // [22]
  554. procedure ParseVersionNum;
  555. begin
  556. if doc.InheritsFrom(TXMLDocument) then
  557. TXMLDocument(doc).XMLVersion :=
  558. GetString(['a'..'z', 'A'..'Z', '0'..'9', '_', '.', ':', '-']);
  559. end;
  560. procedure ParseDoctypeDecls;
  561. begin
  562. repeat
  563. SkipWhitespace;
  564. until not (ParseMarkupDecl or ParsePEReference);
  565. ExpectString(']');
  566. end;
  567. var
  568. DocType: TXMLReaderDocumentType;
  569. begin
  570. if CheckFor('<?xml') then
  571. begin
  572. // '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
  573. // VersionInfo: S 'version' Eq (' VersionNum ' | " VersionNum ")
  574. SkipWhitespace;
  575. ExpectString('version');
  576. ParseEq;
  577. if buf[0] = '''' then
  578. begin
  579. Inc(buf);
  580. ParseVersionNum;
  581. ExpectString('''');
  582. end else if buf[0] = '"' then
  583. begin
  584. Inc(buf);
  585. ParseVersionNum;
  586. ExpectString('"');
  587. end else
  588. RaiseExc('Expected single or double quotation mark');
  589. // EncodingDecl?
  590. SkipEncodingDecl;
  591. // SDDecl?
  592. SkipWhitespace;
  593. if CheckFor('standalone') then
  594. begin
  595. ExpectEq;
  596. if buf[0] = '''' then
  597. begin
  598. Inc(buf);
  599. if not (CheckFor('yes''') or CheckFor('no''')) then
  600. RaiseExc('Expected ''yes'' or ''no''');
  601. end else if buf[0] = '''' then
  602. begin
  603. Inc(buf);
  604. if not (CheckFor('yes"') or CheckFor('no"')) then
  605. RaiseExc('Expected "yes" or "no"');
  606. end;
  607. SkipWhitespace;
  608. end;
  609. ExpectString('?>');
  610. end;
  611. // Check for "Misc*"
  612. ParseMisc(doc);
  613. // Check for "(doctypedecl Misc*)?" [28]
  614. if CheckFor('<!DOCTYPE') then
  615. begin
  616. DocType := TXMLReaderDocumentType.Create(doc as TXMLReaderDocument);
  617. if doc.InheritsFrom(TXMLReaderDocument) then
  618. TXMLReaderDocument(doc).SetDocType(DocType);
  619. SkipWhitespace;
  620. DocType.Name := ExpectName;
  621. SkipWhitespace;
  622. if CheckForChar('[') then
  623. begin
  624. ParseDoctypeDecls;
  625. SkipWhitespace;
  626. ExpectString('>');
  627. end else if not CheckForChar('>') then
  628. begin
  629. ParseExternalID;
  630. SkipWhitespace;
  631. if CheckForChar('[') then
  632. begin
  633. ParseDoctypeDecls;
  634. SkipWhitespace;
  635. end;
  636. ExpectString('>');
  637. end;
  638. ParseMisc(doc);
  639. end;
  640. end;
  641. function TXMLReader.ParseEq: Boolean; // [25]
  642. var
  643. savedbuf: PChar;
  644. begin
  645. savedbuf := buf;
  646. SkipWhitespace;
  647. if buf[0] = '=' then begin
  648. Inc(buf);
  649. SkipWhitespace;
  650. Result := True;
  651. end else begin
  652. buf := savedbuf;
  653. Result := False;
  654. end;
  655. end;
  656. procedure TXMLReader.ExpectEq;
  657. begin
  658. if not ParseEq then
  659. RaiseExc('Expected "="');
  660. end;
  661. // Parse "Misc*":
  662. // Misc ::= Comment | PI | S
  663. procedure TXMLReader.ParseMisc(AOwner: TDOMNode); // [27]
  664. begin
  665. repeat
  666. SkipWhitespace;
  667. until not (ParseComment(AOwner) or ParsePI);
  668. end;
  669. function TXMLReader.ParseMarkupDecl: Boolean; // [29]
  670. function ParseElementDecl: Boolean; // [45]
  671. procedure ExpectChoiceOrSeq; // [49], [50]
  672. procedure ExpectCP; // [48]
  673. begin
  674. if CheckForChar('(') then
  675. ExpectChoiceOrSeq
  676. else
  677. SkipName;
  678. if CheckForChar('?') then
  679. else if CheckForChar('*') then
  680. else if CheckForChar('+') then;
  681. end;
  682. var
  683. delimiter: Char;
  684. begin
  685. SkipWhitespace;
  686. ExpectCP;
  687. SkipWhitespace;
  688. delimiter := #0;
  689. while not CheckForChar(')') do begin
  690. if delimiter = #0 then begin
  691. if (buf[0] = '|') or (buf[0] = ',') then
  692. delimiter := buf[0]
  693. else
  694. RaiseExc('Expected "|" or ","');
  695. Inc(buf);
  696. end else
  697. ExpectString(delimiter);
  698. SkipWhitespace;
  699. ExpectCP;
  700. end;
  701. end;
  702. begin
  703. if CheckFor('<!ELEMENT') then begin
  704. ExpectWhitespace;
  705. SkipName;
  706. ExpectWhitespace;
  707. // Get contentspec [46]
  708. if CheckFor('EMPTY') then
  709. else if CheckFor('ANY') then
  710. else if CheckForChar('(') then begin
  711. SkipWhitespace;
  712. if CheckFor('#PCDATA') then begin
  713. // Parse Mixed section [51]
  714. SkipWhitespace;
  715. if not CheckForChar(')') then
  716. repeat
  717. ExpectString('|');
  718. SkipWhitespace;
  719. SkipName;
  720. until CheckFor(')*');
  721. end else begin
  722. // Parse Children section [47]
  723. ExpectChoiceOrSeq;
  724. if CheckForChar('?') then
  725. else if CheckForChar('*') then
  726. else if CheckForChar('+') then;
  727. end;
  728. end else
  729. RaiseExc('Invalid content specification');
  730. SkipWhitespace;
  731. ExpectString('>');
  732. Result := True;
  733. end else
  734. Result := False;
  735. end;
  736. function ParseAttlistDecl: Boolean; // [52]
  737. var
  738. attr: TDOMAttr;
  739. begin
  740. if CheckFor('<!ATTLIST') then begin
  741. ExpectWhitespace;
  742. SkipName;
  743. SkipWhitespace;
  744. while not CheckForChar('>') do begin
  745. SkipName;
  746. ExpectWhitespace;
  747. // Get AttType [54], [55], [56]
  748. if CheckFor('CDATA') then
  749. else if CheckFor('ID') then
  750. else if CheckFor('IDREF') then
  751. else if CheckFor('IDREFS') then
  752. else if CheckFor('ENTITTY') then
  753. else if CheckFor('ENTITIES') then
  754. else if CheckFor('NMTOKEN') then
  755. else if CheckFor('NMTOKENS') then
  756. else if CheckFor('NOTATION') then begin // [57], [58]
  757. ExpectWhitespace;
  758. ExpectString('(');
  759. SkipWhitespace;
  760. SkipName;
  761. SkipWhitespace;
  762. while not CheckForChar(')') do begin
  763. ExpectString('|');
  764. SkipWhitespace;
  765. SkipName;
  766. SkipWhitespace;
  767. end;
  768. end else if CheckForChar('(') then begin // [59]
  769. SkipWhitespace;
  770. SkipString(Nmtoken);
  771. SkipWhitespace;
  772. while not CheckForChar(')') do begin
  773. ExpectString('|');
  774. SkipWhitespace;
  775. SkipString(Nmtoken);
  776. SkipWhitespace;
  777. end;
  778. end else
  779. RaiseExc('Invalid tokenized type');
  780. ExpectWhitespace;
  781. // Get DefaultDecl [60]
  782. if CheckFor('#REQUIRED') then
  783. else if CheckFor('#IMPLIED') then
  784. else begin
  785. if CheckFor('#FIXED') then
  786. SkipWhitespace;
  787. attr := doc.CreateAttribute('');
  788. ExpectAttValue(attr);
  789. end;
  790. SkipWhitespace;
  791. end;
  792. Result := True;
  793. end else
  794. Result := False;
  795. end;
  796. function ParseEntityDecl: Boolean; // [70]
  797. var
  798. NewEntity: TDOMEntity;
  799. function ParseEntityValue: Boolean; // [9]
  800. var
  801. strdel: Char;
  802. begin
  803. if (buf[0] <> '''') and (buf[0] <> '"') then begin
  804. Result := False;
  805. exit;
  806. end;
  807. strdel := buf[0];
  808. Inc(buf);
  809. while not CheckForChar(strdel) do
  810. if ParsePEReference then
  811. else if ParseReference(NewEntity) then
  812. else begin
  813. Inc(buf); // Normal haracter
  814. end;
  815. Result := True;
  816. end;
  817. begin
  818. if CheckFor('<!ENTITY') then begin
  819. ExpectWhitespace;
  820. if CheckForChar('%') then begin // [72]
  821. ExpectWhitespace;
  822. NewEntity := doc.CreateEntity(ExpectName);
  823. ExpectWhitespace;
  824. // Get PEDef [74]
  825. if ParseEntityValue then
  826. else if ParseExternalID then
  827. else
  828. RaiseExc('Expected entity value or external ID');
  829. end else begin // [71]
  830. NewEntity := doc.CreateEntity(ExpectName);
  831. ExpectWhitespace;
  832. // Get EntityDef [73]
  833. if ParseEntityValue then
  834. else begin
  835. ExpectExternalID;
  836. // Get NDataDecl [76]
  837. ExpectWhitespace;
  838. ExpectString('NDATA');
  839. ExpectWhitespace;
  840. SkipName;
  841. end;
  842. end;
  843. SkipWhitespace;
  844. ExpectString('>');
  845. Result := True;
  846. end else
  847. Result := False;
  848. end;
  849. function ParseNotationDecl: Boolean; // [82]
  850. begin
  851. if CheckFor('<!NOTATION') then begin
  852. ExpectWhitespace;
  853. SkipName;
  854. ExpectWhitespace;
  855. if ParseExternalID then
  856. else if CheckFor('PUBLIC') then begin // [83]
  857. ExpectWhitespace;
  858. SkipPubidLiteral;
  859. end else
  860. RaiseExc('Expected external or public ID');
  861. SkipWhitespace;
  862. ExpectString('>');
  863. Result := True;
  864. end else
  865. Result := False;
  866. end;
  867. begin
  868. Result := False;
  869. while ParseElementDecl or ParseAttlistDecl or ParseEntityDecl or
  870. ParseNotationDecl or ParsePI or ParseComment(doc) or SkipWhitespace do
  871. Result := True;
  872. end;
  873. procedure TXMLReader.ProcessDTD(ABuf: PChar; const AFilename: String);
  874. begin
  875. buf := ABuf;
  876. BufStart := ABuf;
  877. Filename := AFilename;
  878. doc := TXMLReaderDocument.Create;
  879. ParseMarkupDecl;
  880. {
  881. if buf[0] <> #0 then begin
  882. DebugLn('=== Unparsed: ===');
  883. //DebugLn(buf);
  884. DebugLn(StrLen(buf), ' chars');
  885. end;
  886. }
  887. end;
  888. function TXMLReader.ParseCharData(AOwner: TDOMNode): Boolean; // [14]
  889. var
  890. p: PChar;
  891. DataLen: integer;
  892. OldBuf: PChar;
  893. begin
  894. OldBuf := buf;
  895. while not (buf[0] in [#0, '<', '&']) do
  896. begin
  897. Inc(buf);
  898. end;
  899. DataLen:=buf-OldBuf;
  900. if DataLen > 0 then
  901. begin
  902. // Check if chardata has non-whitespace content
  903. p:=OldBuf;
  904. while (p<buf) and (p[0] in WhitespaceChars) do
  905. inc(p);
  906. if p<buf then
  907. AOwner.AppendChild(doc.CreateTextNode(GetString(OldBuf,DataLen)));
  908. Result := True;
  909. end
  910. else
  911. Result := False;
  912. end;
  913. function TXMLReader.ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
  914. var
  915. OldBuf: PChar;
  916. begin
  917. if CheckFor('<![CDATA[') then
  918. begin
  919. OldBuf := buf;
  920. while not CheckFor(']]>') do
  921. begin
  922. Inc(buf);
  923. end;
  924. AOwner.AppendChild(doc.CreateCDATASection(GetString(OldBuf,buf-OldBuf-3))); { Copy CDATA, discarding terminator }
  925. Result := True;
  926. end
  927. else
  928. Result := False;
  929. end;
  930. function TXMLReader.ParseElement(AOwner: TDOMNode): Boolean; // [39] [40] [44]
  931. var
  932. NewElem: TDOMElement;
  933. procedure CreateNameElement;
  934. var
  935. IsEmpty: Boolean;
  936. attr: TDOMAttr;
  937. name: string;
  938. begin
  939. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement A');{$ENDIF}
  940. GetName(name);
  941. NewElem := doc.CreateElement(name);
  942. AOwner.AppendChild(NewElem);
  943. SkipWhitespace;
  944. IsEmpty := False;
  945. while True do
  946. begin
  947. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement E');{$ENDIF}
  948. if CheckFor('/>') then
  949. begin
  950. IsEmpty := True;
  951. break;
  952. end;
  953. if CheckForChar('>') then
  954. break;
  955. // Get Attribute [41]
  956. attr := doc.CreateAttribute(ExpectName);
  957. NewElem.Attributes.SetNamedItem(attr);
  958. ExpectEq;
  959. ExpectAttValue(attr);
  960. SkipWhitespace;
  961. end;
  962. if not IsEmpty then
  963. begin
  964. // Get content
  965. SkipWhitespace;
  966. while ParseCharData(NewElem) or ParseCDSect(NewElem) or ParsePI or
  967. ParseComment(NewElem) or ParseElement(NewElem) or
  968. ParseReference(NewElem) do;
  969. // Get ETag [42]
  970. ExpectString('</');
  971. if ExpectName <> name then
  972. RaiseExc('Unmatching element end tag (expected "</' + name + '>")');
  973. SkipWhitespace;
  974. ExpectString('>');
  975. end;
  976. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement END');{$ENDIF}
  977. ResolveEntities(NewElem);
  978. end;
  979. var
  980. OldBuf: PChar;
  981. begin
  982. OldBuf := Buf;
  983. if CheckForChar('<') then
  984. begin
  985. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement A');{$ENDIF}
  986. if not CheckName then
  987. begin
  988. Buf := OldBuf;
  989. Result := False;
  990. end else begin
  991. CreateNameElement;
  992. Result := True;
  993. end;
  994. end else
  995. Result := False;
  996. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement END');{$ENDIF}
  997. end;
  998. procedure TXMLReader.ExpectElement(AOwner: TDOMNode);
  999. begin
  1000. if not ParseElement(AOwner) then
  1001. RaiseExc('Expected element');
  1002. end;
  1003. function TXMLReader.ParsePEReference: Boolean; // [69]
  1004. begin
  1005. if CheckForChar('%') then begin
  1006. SkipName;
  1007. ExpectString(';');
  1008. Result := True;
  1009. end else
  1010. Result := False;
  1011. end;
  1012. function TXMLReader.ParseReference(AOwner: TDOMNode): Boolean; // [67] [68]
  1013. begin
  1014. if not CheckForChar('&') then begin
  1015. Result := False;
  1016. exit;
  1017. end;
  1018. if CheckForChar('#') then begin // Test for CharRef [66]
  1019. if CheckForChar('x') then begin
  1020. // !!!: there must be at least one digit
  1021. while buf[0] in ['0'..'9', 'a'..'f', 'A'..'F'] do Inc(buf);
  1022. end else
  1023. // !!!: there must be at least one digit
  1024. while buf[0] in ['0'..'9'] do Inc(buf);
  1025. end else
  1026. AOwner.AppendChild(doc.CreateEntityReference(ExpectName));
  1027. ExpectString(';');
  1028. Result := True;
  1029. end;
  1030. procedure TXMLReader.ExpectReference(AOwner: TDOMNode);
  1031. begin
  1032. if not ParseReference(AOwner) then
  1033. RaiseExc('Expected reference ("&Name;" or "%Name;")');
  1034. end;
  1035. function TXMLReader.ParseExternalID: Boolean; // [75]
  1036. function GetSystemLiteral: String;
  1037. var
  1038. OldBuf: PChar;
  1039. begin
  1040. if buf[0] = '''' then begin
  1041. Inc(buf);
  1042. OldBuf := buf;
  1043. while (buf[0] <> '''') and (buf[0] <> #0) do begin
  1044. Inc(buf);
  1045. end;
  1046. Result := GetString(OldBuf,buf-OldBuf);
  1047. ExpectString('''');
  1048. end else if buf[0] = '"' then begin
  1049. Inc(buf);
  1050. OldBuf := buf;
  1051. while (buf[0] <> '"') and (buf[0] <> #0) do begin
  1052. Inc(buf);
  1053. end;
  1054. Result := GetString(OldBuf,buf-OldBuf);
  1055. ExpectString('"');
  1056. end else
  1057. Result:='';
  1058. end;
  1059. procedure SkipSystemLiteral;
  1060. begin
  1061. if buf[0] = '''' then begin
  1062. Inc(buf);
  1063. while (buf[0] <> '''') and (buf[0] <> #0) do begin
  1064. Inc(buf);
  1065. end;
  1066. ExpectString('''');
  1067. end else if buf[0] = '"' then begin
  1068. Inc(buf);
  1069. while (buf[0] <> '"') and (buf[0] <> #0) do begin
  1070. Inc(buf);
  1071. end;
  1072. ExpectString('"');
  1073. end;
  1074. end;
  1075. begin
  1076. if CheckFor('SYSTEM') then begin
  1077. ExpectWhitespace;
  1078. SkipSystemLiteral;
  1079. Result := True;
  1080. end else if CheckFor('PUBLIC') then begin
  1081. ExpectWhitespace;
  1082. SkipPubidLiteral;
  1083. ExpectWhitespace;
  1084. SkipSystemLiteral;
  1085. Result := True;
  1086. end else
  1087. Result := False;
  1088. end;
  1089. procedure TXMLReader.ExpectExternalID;
  1090. begin
  1091. if not ParseExternalID then
  1092. RaiseExc('Expected external ID');
  1093. end;
  1094. function TXMLReader.ParseEncodingDecl: String; // [80]
  1095. function ParseEncName: String;
  1096. var OldBuf: PChar;
  1097. begin
  1098. if not (buf[0] in ['A'..'Z', 'a'..'z']) then
  1099. RaiseExc('Expected character (A-Z, a-z)');
  1100. OldBuf := buf;
  1101. Inc(buf);
  1102. SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
  1103. Result := GetString(OldBuf,buf-OldBuf);
  1104. end;
  1105. begin
  1106. SetLength(Result, 0);
  1107. SkipWhitespace;
  1108. if CheckFor('encoding') then begin
  1109. ExpectEq;
  1110. if buf[0] = '''' then begin
  1111. Inc(buf);
  1112. Result := ParseEncName;
  1113. ExpectString('''');
  1114. end else if buf[0] = '"' then begin
  1115. Inc(buf);
  1116. Result := ParseEncName;
  1117. ExpectString('"');
  1118. end;
  1119. end;
  1120. end;
  1121. procedure TXMLReader.SkipEncodingDecl;
  1122. procedure ParseEncName;
  1123. begin
  1124. if not (buf[0] in ['A'..'Z', 'a'..'z']) then
  1125. RaiseExc('Expected character (A-Z, a-z)');
  1126. Inc(buf);
  1127. SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
  1128. end;
  1129. begin
  1130. SkipWhitespace;
  1131. if CheckFor('encoding') then begin
  1132. ExpectEq;
  1133. if buf[0] = '''' then begin
  1134. Inc(buf);
  1135. ParseEncName;
  1136. ExpectString('''');
  1137. end else if buf[0] = '"' then begin
  1138. Inc(buf);
  1139. ParseEncName;
  1140. ExpectString('"');
  1141. end;
  1142. end;
  1143. end;
  1144. { Currently, this method will only resolve the entities which are
  1145. predefined in XML: }
  1146. procedure TXMLReader.ResolveEntities(RootNode: TDOMNode);
  1147. procedure ReplaceEntityRef(EntityNode: TDOMNode; const Replacement: String);
  1148. var
  1149. PrevSibling, NextSibling: TDOMNode;
  1150. begin
  1151. PrevSibling := EntityNode.PreviousSibling;
  1152. NextSibling := EntityNode.NextSibling;
  1153. if Assigned(PrevSibling) and (PrevSibling.NodeType = TEXT_NODE) then
  1154. begin
  1155. TDOMCharacterData(PrevSibling).AppendData(Replacement);
  1156. RootNode.RemoveChild(EntityNode);
  1157. if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
  1158. begin
  1159. TDOMCharacterData(PrevSibling).AppendData(
  1160. TDOMCharacterData(NextSibling).Data);
  1161. RootNode.RemoveChild(NextSibling);
  1162. end
  1163. end else
  1164. if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
  1165. begin
  1166. TDOMCharacterData(NextSibling).InsertData(0, Replacement);
  1167. RootNode.RemoveChild(EntityNode);
  1168. end else
  1169. RootNode.ReplaceChild(Doc.CreateTextNode(Replacement), EntityNode);
  1170. end;
  1171. var
  1172. Node, NextSibling: TDOMNode;
  1173. begin
  1174. Node := RootNode.FirstChild;
  1175. while Assigned(Node) do
  1176. begin
  1177. NextSibling := Node.NextSibling;
  1178. if Node.NodeType = ENTITY_REFERENCE_NODE then
  1179. if Node.NodeName = 'amp' then
  1180. ReplaceEntityRef(Node, '&')
  1181. else if Node.NodeName = 'apos' then
  1182. ReplaceEntityRef(Node, '''')
  1183. else if Node.NodeName = 'gt' then
  1184. ReplaceEntityRef(Node, '>')
  1185. else if Node.NodeName = 'lt' then
  1186. ReplaceEntityRef(Node, '<')
  1187. else if Node.NodeName = 'quot' then
  1188. ReplaceEntityRef(Node, '"');
  1189. Node := NextSibling;
  1190. end;
  1191. end;
  1192. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: File);
  1193. var
  1194. reader: TXMLReader;
  1195. buf: PChar;
  1196. BufSize: LongInt;
  1197. begin
  1198. ADoc := nil;
  1199. BufSize := FileSize(f) + 1;
  1200. if BufSize <= 1 then
  1201. exit;
  1202. GetMem(buf, BufSize);
  1203. try
  1204. BlockRead(f, buf^, BufSize - 1);
  1205. buf[BufSize - 1] := #0;
  1206. Reader := TXMLReader.Create;
  1207. try
  1208. Reader.ProcessXML(buf, TFileRec(f).name);
  1209. ADoc := TXMLDocument(Reader.doc);
  1210. finally
  1211. Reader.Free;
  1212. end;
  1213. finally
  1214. FreeMem(buf);
  1215. end;
  1216. end;
  1217. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
  1218. var
  1219. reader: TXMLReader;
  1220. buf: PChar;
  1221. begin
  1222. ADoc := nil;
  1223. if f.Size = 0 then exit;
  1224. GetMem(buf, f.Size + 1);
  1225. try
  1226. f.Read(buf^, f.Size);
  1227. buf[f.Size] := #0;
  1228. Reader := TXMLReader.Create;
  1229. try
  1230. Reader.ProcessXML(buf, AFilename);
  1231. ADoc := TXMLDocument(Reader.doc);
  1232. finally
  1233. Reader.Free;
  1234. end;
  1235. finally
  1236. FreeMem(buf);
  1237. end;
  1238. end;
  1239. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream);
  1240. begin
  1241. ReadXMLFile(ADoc, f, '<Stream>');
  1242. end;
  1243. procedure ReadXMLFile(var ADoc: TXMLDocument; const AFilename: String);
  1244. var
  1245. FileStream: TFileStream;
  1246. MemStream: TMemoryStream;
  1247. begin
  1248. ADoc := nil;
  1249. FileStream := TFileStream.Create(AFilename, fmOpenRead);
  1250. if FileStream=nil then exit;
  1251. MemStream := TMemoryStream.Create;
  1252. try
  1253. MemStream.LoadFromStream(FileStream);
  1254. ReadXMLFile(ADoc, MemStream, AFilename);
  1255. finally
  1256. FileStream.Free;
  1257. MemStream.Free;
  1258. end;
  1259. end;
  1260. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File);
  1261. var
  1262. Reader: TXMLReader;
  1263. buf: PChar;
  1264. BufSize: LongInt;
  1265. begin
  1266. BufSize := FileSize(f) + 1;
  1267. if BufSize <= 1 then
  1268. exit;
  1269. GetMem(buf, BufSize);
  1270. try
  1271. BlockRead(f, buf^, BufSize - 1);
  1272. buf[BufSize - 1] := #0;
  1273. Reader := TXMLReader.Create;
  1274. try
  1275. Reader.Doc := AParentNode.OwnerDocument;
  1276. Reader.ProcessFragment(AParentNode, buf, TFileRec(f).name);
  1277. finally
  1278. Reader.Free;
  1279. end;
  1280. finally
  1281. FreeMem(buf);
  1282. end;
  1283. end;
  1284. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String);
  1285. var
  1286. Reader: TXMLReader;
  1287. buf: PChar;
  1288. begin
  1289. if f.Size = 0 then
  1290. exit;
  1291. GetMem(buf, f.Size + 1);
  1292. try
  1293. f.Read(buf^, f.Size);
  1294. buf[f.Size] := #0;
  1295. Reader := TXMLReader.Create;
  1296. Reader.Doc := AParentNode.OwnerDocument;
  1297. try
  1298. Reader.ProcessFragment(AParentNode, buf, AFilename);
  1299. finally
  1300. Reader.Free;
  1301. end;
  1302. finally
  1303. FreeMem(buf);
  1304. end;
  1305. end;
  1306. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream);
  1307. begin
  1308. ReadXMLFragment(AParentNode, f, '<Stream>');
  1309. end;
  1310. procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String);
  1311. var
  1312. Stream: TStream;
  1313. begin
  1314. Stream := TFileStream.Create(AFilename, fmOpenRead);
  1315. try
  1316. ReadXMLFragment(AParentNode, Stream, AFilename);
  1317. finally
  1318. Stream.Free;
  1319. end;
  1320. end;
  1321. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File);
  1322. var
  1323. Reader: TXMLReader;
  1324. buf: PChar;
  1325. BufSize: LongInt;
  1326. begin
  1327. ADoc := nil;
  1328. BufSize := FileSize(f) + 1;
  1329. if BufSize <= 1 then
  1330. exit;
  1331. GetMem(buf, BufSize);
  1332. try
  1333. BlockRead(f, buf^, BufSize - 1);
  1334. buf[BufSize - 1] := #0;
  1335. Reader := TXMLReader.Create;
  1336. try
  1337. Reader.ProcessDTD(buf, TFileRec(f).name);
  1338. ADoc := TXMLDocument(Reader.doc);
  1339. finally
  1340. Reader.Free;
  1341. end;
  1342. finally
  1343. FreeMem(buf);
  1344. end;
  1345. end;
  1346. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
  1347. var
  1348. Reader: TXMLReader;
  1349. buf: PChar;
  1350. begin
  1351. ADoc := nil;
  1352. if f.Size = 0 then
  1353. exit;
  1354. GetMem(buf, f.Size + 1);
  1355. try
  1356. f.Read(buf^, f.Size);
  1357. buf[f.Size] := #0;
  1358. Reader := TXMLReader.Create;
  1359. try
  1360. Reader.ProcessDTD(buf, AFilename);
  1361. ADoc := TXMLDocument(Reader.doc);
  1362. finally
  1363. Reader.Free;
  1364. end;
  1365. finally
  1366. FreeMem(buf);
  1367. end;
  1368. end;
  1369. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream);
  1370. begin
  1371. ReadDTDFile(ADoc, f, '<Stream>');
  1372. end;
  1373. procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String);
  1374. var
  1375. Stream: TStream;
  1376. begin
  1377. ADoc := nil;
  1378. Stream := TFileStream.Create(AFilename, fmOpenRead);
  1379. try
  1380. ReadDTDFile(ADoc, Stream, AFilename);
  1381. finally
  1382. Stream.Free;
  1383. end;
  1384. end;
  1385. end.
  1386. {
  1387. $Log$
  1388. Revision 1.13 2005-01-22 20:54:51 michael
  1389. * Patch from Colin Western to correctly read CDATA
  1390. Revision 1.12 2004/11/05 22:32:28 peter
  1391. * merged xml updates from lazarus
  1392. }