1------------------------------------------------------------------------------ 2-- -- 3-- Matreshka Project -- 4-- -- 5-- XML Processor -- 6-- -- 7-- Runtime Library Component -- 8-- -- 9------------------------------------------------------------------------------ 10-- -- 11-- Copyright © 2011-2012, Vadim Godunko <vgodunko@gmail.com> -- 12-- All rights reserved. -- 13-- -- 14-- Redistribution and use in source and binary forms, with or without -- 15-- modification, are permitted provided that the following conditions -- 16-- are met: -- 17-- -- 18-- * Redistributions of source code must retain the above copyright -- 19-- notice, this list of conditions and the following disclaimer. -- 20-- -- 21-- * Redistributions in binary form must reproduce the above copyright -- 22-- notice, this list of conditions and the following disclaimer in the -- 23-- documentation and/or other materials provided with the distribution. -- 24-- -- 25-- * Neither the name of the Vadim Godunko, IE nor the names of its -- 26-- contributors may be used to endorse or promote products derived from -- 27-- this software without specific prior written permission. -- 28-- -- 29-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- 30-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- 31-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- 32-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- 33-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- 34-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -- 35-- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -- 36-- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -- 37-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -- 38-- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -- 39-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- 40-- -- 41------------------------------------------------------------------------------ 42-- $Revision: 3001 $ $Date: 2012-05-17 14:03:40 +0400 (Thu, 17 May 2012) $ 43------------------------------------------------------------------------------ 44with Ada.Containers.Vectors; 45 46with Matreshka.XML_Catalogs.Loader; 47with Matreshka.XML_Catalogs.Normalization; 48 49package body Matreshka.XML_Catalogs.Resolver is 50 51 use Matreshka.XML_Catalogs.Entry_Files; 52 use type League.Strings.Universal_String; 53 54 package Next_Catalog_Vectors is 55 new Ada.Containers.Vectors 56 (Positive, 57 Next_Catalog_Entry_Vectors.Cursor, 58 Next_Catalog_Entry_Vectors."="); 59 60 procedure Resolve_External_Identifier 61 (File : 62 not null Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_Access; 63 Public_Id : in out League.Strings.Universal_String; 64 System_Id : in out League.Strings.Universal_String; 65 Resolved_URI : out League.Strings.Universal_String; 66 Delegate : out 67 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access); 68 -- Attempts to resolve external identifier using specified catalog entry 69 -- file. 70 71 procedure Resolve_URI 72 (File : 73 not null Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_Access; 74 URI : League.Strings.Universal_String; 75 Resolved_URI : out League.Strings.Universal_String; 76 Delegate : out 77 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access); 78 -- Attempts to resolve URI using specified catalog entry file. 79 80 --------------------------------- 81 -- Resolve_External_Identifier -- 82 --------------------------------- 83 84 procedure Resolve_External_Identifier 85 (List : 86 not null 87 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access; 88 Public_Id : League.Strings.Universal_String; 89 System_Id : League.Strings.Universal_String; 90 Resolved_URI : out League.Strings.Universal_String; 91 Success : out Boolean) 92 is 93 Current_List : 94 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access 95 := List; 96 Current_Public_Id : League.Strings.Universal_String := Public_Id; 97 Current_System_Id : League.Strings.Universal_String := System_Id; 98 Delegate : 99 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access; 100 Identifier : League.Strings.Universal_String; 101 Unwrapped : Boolean; 102 103 begin 104 Success := False; 105 Resolved_URI := League.Strings.Empty_Universal_String; 106 107 -- Normalization and unwrapping. 108 109 -- [XML Catalogs] 7.1.1. Input to the Resolver 110 -- 111 -- "If the public identifier is a URN in the publicid namespace ([RFC 112 -- 3151]), it is converted into another public identifier by 113 -- "unwrapping" the URN (Section 6.4, “URN "Unwrapping"”). This may be 114 -- done, for example, so that a URN can be specified as the public 115 -- identifier and a URL as the system identifier, in the absence of 116 -- widely deployed URN-resolution facilities." 117 118 Matreshka.XML_Catalogs.Normalization.Unwrap_URN 119 (Current_Public_Id, Identifier, Unwrapped); 120 121 if Unwrapped then 122 Current_Public_Id := Identifier; 123 end if; 124 125 -- [XML Catalogs] 7.1.1. Input to the Resolver 126 -- 127 -- "If the system identifier is a URN in the publicid namespace, it is 128 -- converted into a public identifier by "unwrapping" the URN. In this 129 -- case, one of the following must apply: 130 -- 131 -- 1. No public identifier was provided. Resolution continues as if the 132 -- public identifier constructed by unwrapping the URN was supplied as 133 -- the original public identifier and no system identifier was provided. 134 -- 135 -- 2. The normalized public identifier provided is lexically identical 136 -- to the public identifier constructed by unwrapping the URN. 137 -- Resolution continues as if the system identifier had not been 138 -- supplied. 139 -- 140 -- 3. The normalized public identifier provided is different from the 141 -- public identifier constructed by unwrapping the URN. This is an 142 -- error. Applications may recover from this error by discarding the 143 -- system identifier and proceeding with the original public 144 -- identifier." 145 146 Matreshka.XML_Catalogs.Normalization.Unwrap_URN 147 (Current_System_Id, Identifier, Unwrapped); 148 149 if Unwrapped then 150 Current_System_Id.Clear; 151 152 if Current_Public_Id.Is_Empty then 153 Current_Public_Id := Identifier; 154 155 else 156 Current_Public_Id := 157 Matreshka.XML_Catalogs.Normalization.Normalize_Public_Identifier 158 (Current_Public_Id); 159 160 if Current_Public_Id /= Identifier then 161 -- XXX Error reporting is not implemented yet. KDE's test from 162 -- XmlCatConf require to return empty URI and report resolution 163 -- failure. 164 165 Resolved_URI.Clear; 166 Success := False; 167 168 return; 169 end if; 170 end if; 171 172 else 173 Current_Public_Id := 174 Matreshka.XML_Catalogs.Normalization.Normalize_Public_Identifier 175 (Current_Public_Id); 176 Current_System_Id := 177 Matreshka.XML_Catalogs.Normalization.Normalize_System_Identifier 178 (Current_System_Id); 179 end if; 180 181 -- External loop handles delegation processing. 182 183 Delegation : loop 184 -- [XML Catalogs] 7.1.2. Resolution of External Identifiers 185 -- 186 -- "1. Resolution begins in the first catalog entry file in the 187 -- current catalog entry file list." 188 189 for J in Current_List.Catalog_Entry_Files.First_Index 190 .. Current_List.Catalog_Entry_Files.Last_Index 191 loop 192 Resolve_External_Identifier 193 (Current_List.Catalog_Entry_Files.Element (J), 194 Current_Public_Id, 195 Current_System_Id, 196 Resolved_URI, 197 Delegate); 198 199 if Delegate /= null then 200 exit; 201 202 elsif not Resolved_URI.Is_Empty then 203 Success := True; 204 205 return; 206 end if; 207 208 -- [XML Catalogs] 7.1.2. Resolution of External Identifiers 209 -- 210 -- "9. If there are one or more catalog entry files remaining on 211 -- the current catalog entry file list, load the next catalog 212 -- entry file and continue resolution efforts: return to step 2." 213 end loop; 214 215 exit when Delegate = null; 216 -- External identifier not resolved and there is no delegation 217 -- requested, return. 218 219 -- Make requested delegation list to be current list. 220 221 Current_List := Delegate; 222 Delegate := null; 223 end loop Delegation; 224 225 Resolved_URI := System_Id; 226 end Resolve_External_Identifier; 227 228 --------------------------------- 229 -- Resolve_External_Identifier -- 230 --------------------------------- 231 232 procedure Resolve_External_Identifier 233 (File : 234 not null Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_Access; 235 Public_Id : in out League.Strings.Universal_String; 236 System_Id : in out League.Strings.Universal_String; 237 Resolved_URI : out League.Strings.Universal_String; 238 Delegate : out 239 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access) 240 is 241 Length : Natural; 242 Inserted : Boolean; 243 Current_File : 244 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_Access; 245 Rewrite_System : 246 Matreshka.XML_Catalogs.Entry_Files.Rewrite_System_Entry_Access; 247 System_Suffix : 248 Matreshka.XML_Catalogs.Entry_Files.System_Suffix_Entry_Access; 249 Next_Catalog : 250 Matreshka.XML_Catalogs.Entry_Files.Next_Catalog_Entry_Access; 251 Delegate_System : 252 Matreshka.XML_Catalogs.Entry_Files.Delegate_System_Entry_Vectors.Vector; 253 Delegate_Public : 254 Matreshka.XML_Catalogs.Entry_Files.Delegate_Public_Entry_Vectors.Vector; 255 Next : 256 Matreshka.XML_Catalogs.Entry_Files.Next_Catalog_Entry_Vectors.Cursor; 257 Stack : Next_Catalog_Vectors.Vector; 258 259 begin 260 Current_File := File; 261 262 loop 263 if not System_Id.Is_Empty then 264 -- [XML Catalogs] 7.1.2. Resolution of External Identifiers 265 -- 266 -- "2. If a system identifier is provided, and at least one 267 -- matching system entry exists, the (absolutized) value of the 268 -- uri attribute of the first matching system entry is returned." 269 270 for J in Current_File.System_Entries.First_Index 271 .. Current_File.System_Entries.Last_Index 272 loop 273 if System_Id 274 = Current_File.System_Entries.Element (J).System_Id 275 then 276 Resolved_URI := Current_File.System_Entries.Element (J).URI; 277 278 return; 279 end if; 280 end loop; 281 282 -- [XML Catalogs] 7.1.2. Resolution of External Identifiers 283 -- 284 -- "3. If a system identifier is provided, and at least one 285 -- matching rewriteSystem entry exists, rewriting is performed. 286 -- 287 -- If more than one rewriteSystem entry matches, the matching 288 -- entry with the longest normalized systemIdStartString value is 289 -- used. 290 -- 291 -- Rewriting removes the matching prefix and replaces it with the 292 -- rewrite prefix identified by the matching rewriteSystem entry. 293 -- The rewritten string is returned." 294 295 Length := 0; 296 297 for J in Current_File.Rewrite_System_Entries.First_Index 298 .. Current_File.Rewrite_System_Entries.Last_Index 299 loop 300 if System_Id.Starts_With 301 (Current_File.Rewrite_System_Entries.Element (J).System_Id) 302 then 303 if Length 304 < Current_File.Rewrite_System_Entries.Element 305 (J).System_Id.Length 306 then 307 Rewrite_System := 308 Current_File.Rewrite_System_Entries.Element (J); 309 Length := 310 Current_File.Rewrite_System_Entries.Element 311 (J).System_Id.Length; 312 end if; 313 end if; 314 end loop; 315 316 if Rewrite_System /= null then 317 Resolved_URI := 318 Rewrite_System.Prefix 319 & System_Id.Slice 320 (Rewrite_System.System_Id.Length + 1, System_Id.Length); 321 322 return; 323 end if; 324 325 -- [XML Catalogs] 7.1.2. Resolution of External Identifiers 326 -- 327 -- "4. If a system identifier is provided, and at least one 328 -- matching systemSuffix entry exists, the (absolutized) value of 329 -- the uri attribute of the matching entry with the longest 330 -- normalized systemIdSuffix value is returned." 331 332 Length := 0; 333 334 for J in Current_File.System_Suffix_Entries.First_Index 335 .. Current_File.System_Suffix_Entries.Last_Index 336 loop 337 if System_Id.Ends_With 338 (Current_File.System_Suffix_Entries.Element (J).System_Id) 339 then 340 if Length 341 < Current_File.System_Suffix_Entries.Element 342 (J).System_Id.Length 343 then 344 System_Suffix := 345 Current_File.System_Suffix_Entries.Element (J); 346 Length := 347 Current_File.System_Suffix_Entries.Element 348 (J).System_Id.Length; 349 end if; 350 end if; 351 end loop; 352 353 if System_Suffix /= null then 354 Resolved_URI := System_Suffix.URI; 355 356 return; 357 end if; 358 359 -- [XML Catalogs] 7.1.2. Resolution of External Identifiers 360 -- 361 -- "5. If a system identifier is provided, and one or more 362 -- delegateSystem entries match, delegation is performed. 363 -- 364 -- If delegation is to be performed, a new catalog entry file list 365 -- is generated from the set of all matching delegateSystem 366 -- entries. The (absolutized) value of the catalog attribute of 367 -- each matching delegateSystem entry is inserted into the new 368 -- catalog entry file list such that the delegate entry with the 369 -- longest matching systemIdStartString is first on the list, the 370 -- entry with the second longest match is second, etc. 371 -- 372 -- These are the only catalog entry files on the list, the current 373 -- list is not considered for the purpose of delegation. If 374 -- delegation fails to find a match, resolution for this entity 375 -- does not resume with the current list. (A subsequent resolution 376 -- attempt for a different entity begins with the original list; 377 -- in other words the catalog entry file list used for delegation 378 -- is distinct and unrelated to the "normal" catalog entry file 379 -- list.) 380 -- 381 -- Catalog resolution restarts using exclusively the catalog entry 382 -- files in this new list and the given system identifier; any 383 -- originally given public identifier is ignored during the 384 -- remainder of the resolution of this external identifier: return 385 -- to step 1." 386 387 for J in Current_File.Delegate_System_Entries.First_Index 388 .. Current_File.Delegate_System_Entries.Last_Index 389 loop 390 if System_Id.Starts_With 391 (Current_File.Delegate_System_Entries.Element (J).System_Id) 392 then 393 Inserted := False; 394 395 for K in Delegate_System.First_Index 396 .. Delegate_System.Last_Index 397 loop 398 if Current_File.Delegate_System_Entries.Element 399 (J).System_Id.Length 400 > Delegate_System.Element (K).System_Id.Length 401 then 402 Delegate_System.Insert 403 (K, Current_File.Delegate_System_Entries.Element (J)); 404 Inserted := True; 405 406 exit; 407 end if; 408 end loop; 409 410 if not Inserted then 411 Delegate_System.Append 412 (Current_File.Delegate_System_Entries.Element (J)); 413 end if; 414 end if; 415 end loop; 416 417 if not Delegate_System.Is_Empty then 418 Delegate := 419 new Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List; 420 421 for J in Delegate_System.First_Index 422 .. Delegate_System.Last_Index 423 loop 424 Delegate.Catalog_Entry_Files.Append 425 (Matreshka.XML_Catalogs.Loader.Load 426 (Delegate_System.Element (J).Catalog, 427 Current_File.Default_Prefer_Mode)); 428 end loop; 429 430 Public_Id.Clear; 431 432 return; 433 end if; 434 end if; 435 436 if not Public_Id.Is_Empty then 437 -- [XML Catalogs] 7.1.2. Resolution of External Identifiers 438 -- 439 -- "6. If a public identifier is provided, and at least one 440 -- matching public entry exists, the (absolutized) value of the 441 -- uri attribute of the first matching public entry is returned. 442 -- If a system identifier is also provided as part of the input to 443 -- this catalog lookup, only public entries that occur where the 444 -- prefer setting is public are considered for matching." 445 446 for J in Current_File.Public_Entries.First_Index 447 .. Current_File.Public_Entries.Last_Index 448 loop 449 if Public_Id = Current_File.Public_Entries.Element (J).Public_Id 450 and then (System_Id.Is_Empty 451 or else Current_File.Public_Entries.Element 452 (J).Prefer 453 = Public) 454 then 455 Resolved_URI := Current_File.Public_Entries.Element (J).URI; 456 457 return; 458 end if; 459 end loop; 460 461 -- [XML Catalogs] 7.1.2. Resolution of External Identifiers 462 -- 463 -- "7. If a public identifier is provided, and one or more 464 -- delegatePublic entries match, delegation is performed. If a 465 -- system identifier is also provided as part of the input to this 466 -- catalog lookup, only delegatePublic entries that occur where 467 -- the prefer setting is public are considered for matching. 468 -- 469 -- If delegation is to be performed, a new catalog entry file list 470 -- is generated from the set of all matching delegatePublic 471 -- entries. The value of the catalog attribute of each matching 472 -- delegatePublic entry is inserted into the new catalog entry 473 -- file list such that the delegate entry with the longest 474 -- matching publicIdStartString is first on the list, the entry 475 -- with the second longest match is second, etc. 476 -- 477 -- These are the only catalog entry files on the list, the current 478 -- list is not considered for the purpose of delegation. If 479 -- delegation fails to find a match, resolution for this entity 480 -- does not resume with the current list. (A subsequent resolution 481 -- attempt for a different entity begins with the original list; 482 -- in other words the catalog entry file list used for delegation 483 -- is distinct and unrelated to the "normal" catalog entry file 484 -- list.) 485 -- 486 -- Catalog resolution restarts using exclusively the catalog entry 487 -- files in this new list and the given public identifier; any 488 -- originally given system identifier is ignored during the 489 -- remainder of the resolution of this external identifier: return 490 -- to step 1." 491 492 for J in Current_File.Delegate_Public_Entries.First_Index 493 .. Current_File.Delegate_Public_Entries.Last_Index 494 loop 495 if Public_Id.Starts_With 496 (Current_File.Delegate_Public_Entries.Element (J).Public_Id) 497 and then (System_Id.Is_Empty 498 or else 499 Current_File.Delegate_Public_Entries.Element 500 (J).Prefer = Public) 501 then 502 Inserted := False; 503 504 for K in Delegate_Public.First_Index 505 .. Delegate_Public.Last_Index 506 loop 507 if Current_File.Delegate_Public_Entries.Element 508 (J).Public_Id.Length 509 > Delegate_Public.Element (K).Public_Id.Length 510 then 511 Delegate_Public.Insert 512 (K, Current_File.Delegate_Public_Entries.Element (J)); 513 Inserted := True; 514 515 exit; 516 end if; 517 end loop; 518 519 if not Inserted then 520 Delegate_Public.Append 521 (Current_File.Delegate_Public_Entries.Element (J)); 522 end if; 523 end if; 524 end loop; 525 526 if not Delegate_Public.Is_Empty then 527 Delegate := 528 new Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List; 529 530 for J in Delegate_Public.First_Index 531 .. Delegate_Public.Last_Index 532 loop 533 Delegate.Catalog_Entry_Files.Append 534 (Matreshka.XML_Catalogs.Loader.Load 535 (Delegate_Public.Element (J).Catalog, 536 Current_File.Default_Prefer_Mode)); 537 end loop; 538 539 System_Id.Clear; 540 541 return; 542 end if; 543 end if; 544 545 -- [XML Catalogs] 7.1.2. Resolution of External Identifiers 546 -- 547 -- "8. If the current catalog entry file contains one or more 548 -- nextCatalog entries, the catalog entry files referenced by each 549 -- nextCatalog entry's "catalog" attribute are inserted, in the order 550 -- that they appear in this catalog entry file, onto the current 551 -- catalog entry file list, immediately after the current catalog 552 -- entry file. 553 554 Next := Current_File.Next_Catalog_Entries.First; 555 556 if Next_Catalog_Entry_Vectors.Has_Element (Next) then 557 Stack.Append (Next); 558 end if; 559 560 exit when Stack.Is_Empty; 561 562 -- Take next catalog entry file from the stack. 563 564 Next := Stack.Last_Element; 565 Stack.Delete_Last; 566 Next_Catalog := Next_Catalog_Entry_Vectors.Element (Next); 567 568 if Next_Catalog.File = null then 569 Next_Catalog.File := 570 Matreshka.XML_Catalogs.Loader.Load 571 (Next_Catalog.Catalog, File.Default_Prefer_Mode); 572 end if; 573 574 Current_File := Next_Catalog.File; 575 576 Next_Catalog_Entry_Vectors.Next (Next); 577 578 if Next_Catalog_Entry_Vectors.Has_Element (Next) then 579 Stack.Append (Next); 580 end if; 581 end loop; 582 end Resolve_External_Identifier; 583 584 ----------------- 585 -- Resolve_URI -- 586 ----------------- 587 588 procedure Resolve_URI 589 (List : 590 not null 591 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access; 592 URI : League.Strings.Universal_String; 593 Resolved_URI : out League.Strings.Universal_String; 594 Success : out Boolean) 595 is 596 Current_List : 597 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access 598 := List; 599 Delegate : 600 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access; 601 Current_URI : League.Strings.Universal_String; 602 Identifier : League.Strings.Universal_String; 603 Unwrapped : Boolean; 604 605 begin 606 Success := False; 607 Resolved_URI := League.Strings.Empty_Universal_String; 608 609 -- [XML Catalogs] 7.2.1. Input to the Resolver 610 -- 611 -- "If the URI reference is a URN in the publicid namespace ([RFC 612 -- 3151]), it is converted into a public identifier by "unwrapping" the 613 -- URN (Section 6.4, “URN "Unwrapping"”). Resolution continues by 614 -- following the semantics of external identifier resolution (Section 615 -- 7.1, “External Identifier Resolution”) as if the public identifier 616 -- constructed by unwrapping the URN had been provided and no system 617 -- identifier had been provided. Otherwise, resolution of the URI 618 -- reference proceeds according to the steps below." 619 620 Matreshka.XML_Catalogs.Normalization.Unwrap_URN 621 (URI, Identifier, Unwrapped); 622 623 if Unwrapped then 624 Resolve_External_Identifier 625 (List, 626 Identifier, 627 League.Strings.Empty_Universal_String, 628 Resolved_URI, 629 Success); 630 631 return; 632 end if; 633 634 Current_URI := Matreshka.XML_Catalogs.Normalization.Normalize_URI (URI); 635 636 -- External loop handles delegation processing. 637 638 Delegation : loop 639 -- [XML Catalogs] 7.2.2. Resolution of URI references 640 -- 641 -- "1. Resolution begins in the first catalog entry file in the 642 -- current catalog list." 643 644 for J in Current_List.Catalog_Entry_Files.First_Index 645 .. Current_List.Catalog_Entry_Files.Last_Index 646 loop 647 Resolve_URI 648 (Current_List.Catalog_Entry_Files.Element (J), 649 Current_URI, 650 Resolved_URI, 651 Delegate); 652 653 if Delegate /= null then 654 exit; 655 656 elsif not Resolved_URI.Is_Empty then 657 Success := True; 658 659 return; 660 end if; 661 662 -- [XML Catalogs] 7.2.2. Resolution of URI references 663 -- 664 -- "7. If there are one or more catalog entry files remaining on 665 -- the current catalog entry file list, load the next catalog 666 -- entry file and continue resolution efforts: return to step 2." 667 end loop; 668 669 exit when Delegate = null; 670 -- URI is not resolved and there is no delegation requested, return. 671 672 -- Make requested delegation list to be current list. 673 674 Current_List := Delegate; 675 Delegate := null; 676 end loop Delegation; 677 678 Resolved_URI := Current_URI; 679 end Resolve_URI; 680 681 ----------------- 682 -- Resolve_URI -- 683 ----------------- 684 685 procedure Resolve_URI 686 (File : 687 not null Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_Access; 688 URI : League.Strings.Universal_String; 689 Resolved_URI : out League.Strings.Universal_String; 690 Delegate : out 691 Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List_Access) 692 is 693 Length : Natural; 694 Inserted : Boolean; 695 Rewrite_URI : 696 Matreshka.XML_Catalogs.Entry_Files.Rewrite_URI_Entry_Access; 697 URI_Suffix : 698 Matreshka.XML_Catalogs.Entry_Files.URI_Suffix_Entry_Access; 699 Delegate_URI : 700 Matreshka.XML_Catalogs.Entry_Files.Delegate_URI_Entry_Vectors.Vector; 701 702 begin 703 -- [XML Catalogs] 7.2.2. Resolution of URI references 704 -- 705 -- "2. If at least one matching uri entry exists, the (absolutized) 706 -- value of the uri attribute of the first matching uri entry is 707 -- returned." 708 709 for J in File.URI_Entries.First_Index .. File.URI_Entries.Last_Index loop 710 if URI = File.URI_Entries.Element (J).Name then 711 Resolved_URI := File.URI_Entries.Element (J).URI; 712 713 return; 714 end if; 715 end loop; 716 717 -- [XML Catalogs] 7.2.2. Resolution of URI references 718 -- 719 -- "3. If at least one matching rewriteURI entry exists, rewriting is 720 -- performed. 721 -- 722 -- If more than one rewriteURI entry matches, the matching entry with 723 -- the longest normalized uriStartString value is used. 724 -- 725 -- Rewriting removes the matching prefix and replaces it with the 726 -- rewrite prefix identified by the matching rewriteURI entry. The 727 -- rewritten string is returned." 728 729 Length := 0; 730 731 for J in File.Rewrite_URI_Entries.First_Index 732 .. File.Rewrite_URI_Entries.Last_Index 733 loop 734 if URI.Starts_With (File.Rewrite_URI_Entries.Element (J).Prefix) then 735 if Length < File.Rewrite_URI_Entries.Element (J).Prefix.Length then 736 Rewrite_URI := File.Rewrite_URI_Entries.Element (J); 737 Length := File.Rewrite_URI_Entries.Element (J).Prefix.Length; 738 end if; 739 end if; 740 end loop; 741 742 if Rewrite_URI /= null then 743 Resolved_URI := 744 Rewrite_URI.Rewrite 745 & URI.Slice (Rewrite_URI.Prefix.Length + 1, URI.Length); 746 747 return; 748 end if; 749 750 -- [XML Catalogs] 7.2.2. Resolution of URI references 751 -- 752 -- "4. If at least one matching uriSuffix entry exists, the 753 -- (absolutized) value of the uri attribute of the matching entry with 754 -- the longest normalized uriSuffix value is returned." 755 756 Length := 0; 757 758 for J in File.URI_Suffix_Entries.First_Index 759 .. File.URI_Suffix_Entries.Last_Index 760 loop 761 if URI.Ends_With (File.URI_Suffix_Entries.Element (J).Suffix) then 762 if Length < File.URI_Suffix_Entries.Element (J).Suffix.Length then 763 URI_Suffix := File.URI_Suffix_Entries.Element (J); 764 Length := File.URI_Suffix_Entries.Element (J).Suffix.Length; 765 end if; 766 end if; 767 end loop; 768 769 if URI_Suffix /= null then 770 Resolved_URI := URI_Suffix.URI; 771 772 return; 773 end if; 774 775 -- [XML Catalogs] 7.2.2. Resolution of URI references 776 -- 777 -- "5. If one or more delegateURI entries match, delegation is 778 -- performed. 779 -- 780 -- If delegation is to be performed, a new catalog entry file list is 781 -- generated from the set of all matching delegateURI entries. The 782 -- (absolutized) value of the catalog attribute of each matching 783 -- delegateURI entry is inserted into the new catalog entry file list 784 -- such that the delegate entry with the longest matching uriStartString 785 -- is first on the list, the entry with the second longest match is 786 -- second, etc. 787 -- 788 -- These are the only catalog entry files on the list, the current list 789 -- is not considered for the purpose of delegation. If delegation fails 790 -- to find a match, resolution for this entity does not resume with the 791 -- current list. (A subsequent resolution attempt for a different entity 792 -- begins with the original list; in other words the catalog entry file 793 -- list used for delegation is distinct and unrelated to the "normal" 794 -- catalog entry file list.) 795 -- 796 -- Catalog resolution restarts using exclusively the catalog entry files 797 -- in this new list and the given URI reference: return to step 1. 798 799 for J in File.Delegate_URI_Entries.First_Index 800 .. File.Delegate_URI_Entries.Last_Index 801 loop 802 if URI.Starts_With (File.Delegate_URI_Entries.Element (J).Prefix) then 803 Inserted := False; 804 805 for K in Delegate_URI.First_Index .. Delegate_URI.Last_Index loop 806 if File.Delegate_URI_Entries.Element (J).Prefix.Length 807 > Delegate_URI.Element (K).Prefix.Length 808 then 809 Delegate_URI.Insert 810 (K, File.Delegate_URI_Entries.Element (J)); 811 Inserted := True; 812 813 exit; 814 end if; 815 end loop; 816 817 if not Inserted then 818 Delegate_URI.Append 819 (File.Delegate_URI_Entries.Element (J)); 820 end if; 821 end if; 822 end loop; 823 824 if not Delegate_URI.Is_Empty then 825 Delegate := 826 new Matreshka.XML_Catalogs.Entry_Files.Catalog_Entry_File_List; 827 828 for J in Delegate_URI.First_Index .. Delegate_URI.Last_Index loop 829 Delegate.Catalog_Entry_Files.Append 830 (Matreshka.XML_Catalogs.Loader.Load 831 (Delegate_URI.Element (J).Catalog, 832 File.Default_Prefer_Mode)); 833 end loop; 834 835 return; 836 end if; 837 end Resolve_URI; 838 839end Matreshka.XML_Catalogs.Resolver; 840