1 16 17 package org.apache.xerces.impl.dtd.models; 18 19 import org.apache.xerces.xni.QName; 20 import org.apache.xerces.impl.dtd.XMLContentSpec; 21 22 38 public class DFAContentModel 39 implements ContentModelValidator { 40 41 46 47 private static String fEpsilonString = "<<CMNODE_EPSILON>>"; 48 49 50 private static String fEOCString = "<<CMNODE_EOC>>"; 51 52 53 static { 54 fEpsilonString = fEpsilonString.intern(); 55 fEOCString = fEOCString.intern(); 56 } 57 58 60 61 private static final boolean DEBUG_VALIDATE_CONTENT = false; 62 63 67 68 70 76 private QName fElemMap[] = null; 77 78 82 private int fElemMapType[] = null; 83 84 85 private int fElemMapSize = 0; 86 87 88 private boolean fMixed; 89 90 94 private int fEOCPos = 0; 95 96 97 102 private boolean fFinalStateFlags[] = null; 103 104 109 private CMStateSet fFollowList[] = null; 110 111 117 private CMNode fHeadNode = null; 118 119 123 private int fLeafCount = 0; 124 125 129 private CMLeaf fLeafList[] = null; 130 131 132 private int fLeafListType[] = null; 133 134 136 140 142 154 private int fTransTable[][] = null; 155 156 160 private int fTransTableSize = 0; 161 162 170 private boolean fEmptyContentIsValid = false; 171 172 174 175 private QName fQName = new QName(); 176 177 181 182 186 194 public DFAContentModel(CMNode syntaxTree, int leafCount, boolean mixed) { 195 fLeafCount = leafCount; 198 199 200 fMixed = mixed; 202 203 buildDFA(syntaxTree); 213 } 214 215 219 242 public int validate(QName[] children, int offset, int length) { 243 244 if (DEBUG_VALIDATE_CONTENT) 245 System.out.println("DFAContentModel#validateContent"); 246 247 if (length == 0) { 261 if (DEBUG_VALIDATE_CONTENT) { 262 System.out.println("!!! no children"); 263 System.out.println("elemMap="+fElemMap); 264 for (int i = 0; i < fElemMap.length; i++) { 265 String uri = fElemMap[i].uri; 266 String localpart = fElemMap[i].localpart; 267 268 System.out.println("fElemMap["+i+"]="+uri+","+ 269 localpart+" ("+ 270 uri+", "+ 271 localpart+ 272 ')'); 273 274 } 275 System.out.println("EOCIndex="+fEOCString); 276 } 277 278 return fEmptyContentIsValid ? -1 : 0; 279 280 } 282 int curState = 0; 288 for (int childIndex = 0; childIndex < length; childIndex++) 289 { 290 final QName curElem = children[offset + childIndex]; 292 if (fMixed && curElem.localpart == null) { 294 continue; 295 } 296 297 int elemIndex = 0; 299 for (; elemIndex < fElemMapSize; elemIndex++) 300 { 301 int type = fElemMapType[elemIndex] & 0x0f ; 302 if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) { 303 if (fElemMap[elemIndex].rawname == curElem.rawname) { 305 break; 306 } 307 } 308 else if (type == XMLContentSpec.CONTENTSPECNODE_ANY) { 309 String uri = fElemMap[elemIndex].uri; 310 if (uri == null || uri == curElem.uri) { 311 break; 312 } 313 } 314 else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) { 315 if (curElem.uri == null) { 316 break; 317 } 318 } 319 else if (type == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) { 320 if (fElemMap[elemIndex].uri != curElem.uri) { 321 break; 322 } 323 } 324 } 325 326 if (elemIndex == fElemMapSize) { 328 if (DEBUG_VALIDATE_CONTENT) { 329 System.out.println("!!! didn't find it"); 330 331 System.out.println("curElem : " +curElem ); 332 for (int i=0; i<fElemMapSize; i++) { 333 System.out.println("fElemMap["+i+"] = " +fElemMap[i] ); 334 System.out.println("fElemMapType["+i+"] = " +fElemMapType[i] ); 335 } 336 } 337 338 return childIndex; 339 } 340 341 curState = fTransTable[curState][elemIndex]; 346 347 if (curState == -1) { 349 if (DEBUG_VALIDATE_CONTENT) 350 System.out.println("!!! not a legal transition"); 351 return childIndex; 352 } 353 } 354 355 if (DEBUG_VALIDATE_CONTENT) 361 System.out.println("curState="+curState+", childCount="+length); 362 if (!fFinalStateFlags[curState]) 363 return length; 364 365 return -1; 367 } 369 370 374 381 private void buildDFA(CMNode syntaxTree) 382 { 383 412 423 424 fQName.setValues(null, fEOCString, fEOCString, null); 425 CMLeaf nodeEOC = new CMLeaf(fQName); 426 fHeadNode = new CMBinOp 427 ( 428 XMLContentSpec.CONTENTSPECNODE_SEQ 429 , syntaxTree 430 , nodeEOC 431 ); 432 433 fEOCPos = fLeafCount; 441 nodeEOC.setPosition(fLeafCount++); 442 443 fLeafList = new CMLeaf[fLeafCount]; 458 fLeafListType = new int[fLeafCount]; 459 postTreeBuildInit(fHeadNode, 0); 460 461 fFollowList = new CMStateSet[fLeafCount]; 467 for (int index = 0; index < fLeafCount; index++) 468 fFollowList[index] = new CMStateSet(fLeafCount); 469 calcFollowList(fHeadNode); 470 fElemMap = new QName[fLeafCount]; 482 fElemMapType = new int[fLeafCount]; 483 fElemMapSize = 0; 484 for (int outIndex = 0; outIndex < fLeafCount; outIndex++) 485 { 486 fElemMap[outIndex] = new QName(); 487 488 495 496 final QName element = fLeafList[outIndex].getElement(); 498 499 int inIndex = 0; 501 for (; inIndex < fElemMapSize; inIndex++) 502 { 503 if (fElemMap[inIndex].rawname == element.rawname) { 504 break; 505 } 506 } 507 508 if (inIndex == fElemMapSize) { 510 fElemMap[fElemMapSize].setValues(element); 511 fElemMapType[fElemMapSize] = fLeafListType[outIndex]; 512 fElemMapSize++; 513 } 514 } 515 526 527 int[] fLeafSorter = new int[fLeafCount + fElemMapSize]; 528 int fSortCount = 0; 529 530 for (int elemIndex = 0; elemIndex < fElemMapSize; elemIndex++) { 531 for (int leafIndex = 0; leafIndex < fLeafCount; leafIndex++) { 532 final QName leaf = fLeafList[leafIndex].getElement(); 533 final QName element = fElemMap[elemIndex]; 534 if (leaf.rawname == element.rawname) { 535 fLeafSorter[fSortCount++] = leafIndex; 536 } 537 } 538 fLeafSorter[fSortCount++] = -1; 539 } 540 541 542 543 int curArraySize = fLeafCount * 4; 557 CMStateSet[] statesToDo = new CMStateSet[curArraySize]; 558 fFinalStateFlags = new boolean[curArraySize]; 559 fTransTable = new int[curArraySize][]; 560 561 CMStateSet setT = fHeadNode.firstPos(); 567 568 int unmarkedState = 0; 577 int curState = 0; 578 579 fTransTable[curState] = makeDefStateList(); 584 statesToDo[curState] = setT; 585 curState++; 586 587 590 591 java.util.Hashtable stateTable = new java.util.Hashtable (); 592 593 594 595 while (unmarkedState < curState) 601 { 602 setT = statesToDo[unmarkedState]; 607 int[] transEntry = fTransTable[unmarkedState]; 608 609 fFinalStateFlags[unmarkedState] = setT.getBit(fEOCPos); 611 612 unmarkedState++; 614 615 CMStateSet newSet = null; 617 618 int sorterIndex = 0; 619 620 for (int elemIndex = 0; elemIndex < fElemMapSize; elemIndex++) 621 { 622 if (newSet == null) 629 newSet = new CMStateSet(fLeafCount); 630 else 631 newSet.zeroBits(); 632 633 634 int leafIndex = fLeafSorter[sorterIndex++]; 635 636 while (leafIndex != -1) { 637 if (setT.getBit(leafIndex)) 639 { 640 newSet.union(fFollowList[leafIndex]); 646 } 647 648 leafIndex = fLeafSorter[sorterIndex++]; 649 } 650 651 652 if (!newSet.isEmpty()) 657 { 658 663 664 Integer stateObj = (Integer )stateTable.get(newSet); 665 int stateIndex = (stateObj == null ? curState : stateObj.intValue()); 666 667 668 if (stateIndex == curState) 670 { 671 statesToDo[curState] = newSet; 677 fTransTable[curState] = makeDefStateList(); 678 679 680 stateTable.put(newSet, new Integer (curState)); 681 682 683 curState++; 685 686 newSet = null; 692 } 693 694 transEntry[elemIndex] = stateIndex; 701 702 if (curState == curArraySize) 704 { 705 final int newSize = (int)(curArraySize * 1.5); 711 CMStateSet[] newToDo = new CMStateSet[newSize]; 712 boolean[] newFinalFlags = new boolean[newSize]; 713 int[][] newTransTable = new int[newSize][]; 714 715 for (int expIndex = 0; expIndex < curArraySize; expIndex++) 717 { 718 newToDo[expIndex] = statesToDo[expIndex]; 719 newFinalFlags[expIndex] = fFinalStateFlags[expIndex]; 720 newTransTable[expIndex] = fTransTable[expIndex]; 721 } 722 723 curArraySize = newSize; 725 statesToDo = newToDo; 726 fFinalStateFlags = newFinalFlags; 727 fTransTable = newTransTable; 728 } 729 } 730 } 731 } 732 733 fEmptyContentIsValid = ((CMBinOp)fHeadNode).getLeft().isNullable(); 735 736 if (DEBUG_VALIDATE_CONTENT) 741 dumpTree(fHeadNode, 0); 742 fHeadNode = null; 743 fLeafList = null; 744 fFollowList = null; 745 746 } 747 748 755 private void calcFollowList(CMNode nodeCur) 756 { 757 if (nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_CHOICE) 759 { 760 calcFollowList(((CMBinOp)nodeCur).getLeft()); 762 calcFollowList(((CMBinOp)nodeCur).getRight()); 763 } 764 else if (nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_SEQ) 765 { 766 calcFollowList(((CMBinOp)nodeCur).getLeft()); 768 calcFollowList(((CMBinOp)nodeCur).getRight()); 769 770 final CMStateSet last = ((CMBinOp)nodeCur).getLeft().lastPos(); 776 final CMStateSet first = ((CMBinOp)nodeCur).getRight().firstPos(); 777 778 for (int index = 0; index < fLeafCount; index++) 784 { 785 if (last.getBit(index)) 786 fFollowList[index].union(first); 787 } 788 } 789 819 else if (nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE 820 || nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) 821 { 822 calcFollowList(((CMUniOp)nodeCur).getChild()); 824 825 final CMStateSet first = nodeCur.firstPos(); 830 final CMStateSet last = nodeCur.lastPos(); 831 832 for (int index = 0; index < fLeafCount; index++) 838 { 839 if (last.getBit(index)) 840 fFollowList[index].union(first); 841 } 842 } 843 844 else if (nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE) { 845 calcFollowList(((CMUniOp)nodeCur).getChild()); 847 } 848 849 } 850 851 859 private void dumpTree(CMNode nodeCur, int level) 860 { 861 for (int index = 0; index < level; index++) 862 System.out.print(" "); 863 864 int type = nodeCur.type(); 865 if ((type == XMLContentSpec.CONTENTSPECNODE_CHOICE) 866 || (type == XMLContentSpec.CONTENTSPECNODE_SEQ)) 867 { 868 if (type == XMLContentSpec.CONTENTSPECNODE_CHOICE) 869 System.out.print("Choice Node "); 870 else 871 System.out.print("Seq Node "); 872 873 if (nodeCur.isNullable()) 874 System.out.print("Nullable "); 875 876 System.out.print("firstPos="); 877 System.out.print(nodeCur.firstPos().toString()); 878 System.out.print(" lastPos="); 879 System.out.println(nodeCur.lastPos().toString()); 880 881 dumpTree(((CMBinOp)nodeCur).getLeft(), level+1); 882 dumpTree(((CMBinOp)nodeCur).getRight(), level+1); 883 } 884 else if (nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE) 885 { 886 System.out.print("Rep Node "); 887 888 if (nodeCur.isNullable()) 889 System.out.print("Nullable "); 890 891 System.out.print("firstPos="); 892 System.out.print(nodeCur.firstPos().toString()); 893 System.out.print(" lastPos="); 894 System.out.println(nodeCur.lastPos().toString()); 895 896 dumpTree(((CMUniOp)nodeCur).getChild(), level+1); 897 } 898 else if (nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_LEAF) 899 { 900 System.out.print 901 ( 902 "Leaf: (pos=" 903 + ((CMLeaf)nodeCur).getPosition() 904 + "), " 905 + ((CMLeaf)nodeCur).getElement() 906 + "(elemIndex=" 907 + ((CMLeaf)nodeCur).getElement() 908 + ") " 909 ); 910 911 if (nodeCur.isNullable()) 912 System.out.print(" Nullable "); 913 914 System.out.print("firstPos="); 915 System.out.print(nodeCur.firstPos().toString()); 916 System.out.print(" lastPos="); 917 System.out.println(nodeCur.lastPos().toString()); 918 } 919 else 920 { 921 throw new RuntimeException ("ImplementationMessages.VAL_NIICM"); 922 } 923 } 924 925 926 931 private int[] makeDefStateList() 932 { 933 int[] retArray = new int[fElemMapSize]; 934 for (int index = 0; index < fElemMapSize; index++) 935 retArray[index] = -1; 936 return retArray; 937 } 938 939 940 private int postTreeBuildInit(CMNode nodeCur, int curIndex) 941 { 942 nodeCur.setMaxStates(fLeafCount); 944 945 if ((nodeCur.type() & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY || 947 (nodeCur.type() & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL || 948 (nodeCur.type() & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) { 949 QName qname = new QName(null, null, null, ((CMAny)nodeCur).getURI()); 951 fLeafList[curIndex] = new CMLeaf(qname, ((CMAny)nodeCur).getPosition()); 952 fLeafListType[curIndex] = nodeCur.type(); 953 curIndex++; 954 } 955 else if ((nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_CHOICE) 956 || (nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_SEQ)) 957 { 958 curIndex = postTreeBuildInit(((CMBinOp)nodeCur).getLeft(), curIndex); 959 curIndex = postTreeBuildInit(((CMBinOp)nodeCur).getRight(), curIndex); 960 } 961 else if (nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE 962 || nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE 963 || nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE) 964 { 965 curIndex = postTreeBuildInit(((CMUniOp)nodeCur).getChild(), curIndex); 966 } 967 else if (nodeCur.type() == XMLContentSpec.CONTENTSPECNODE_LEAF) 968 { 969 final QName node = ((CMLeaf)nodeCur).getElement(); 974 if (node.localpart != fEpsilonString) { 975 fLeafList[curIndex] = (CMLeaf)nodeCur; 976 fLeafListType[curIndex] = XMLContentSpec.CONTENTSPECNODE_LEAF; 977 curIndex++; 978 } 979 } 980 else 981 { 982 throw new RuntimeException ("ImplementationMessages.VAL_NIICM: type="+nodeCur.type()); 983 } 984 return curIndex; 985 } 986 987 } | Popular Tags |