| /******************************************************************************* |
| * Copyright (c) 2001, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.wst.dtd.core.internal.saxparser; |
| |
| import java.util.Vector; |
| |
| /** |
| * Scanning / parsing the content string from the Decl statement |
| * |
| * @version |
| */ |
| public class DTDScanner { |
| // element content model strings |
| private static final char[] empty_string = {'E', 'M', 'P', 'T', 'Y'}; |
| private static final char[] any_string = {'A', 'N', 'Y'}; |
| private static final char[] pcdata_string = {'#', 'P', 'C', 'D', 'A', 'T', 'A'}; |
| |
| // attribute type and default type strings |
| private static final char[] cdata_string = {'C', 'D', 'A', 'T', 'A'}; |
| private static final char[] id_string = {'I', 'D'}; |
| private static final char[] ref_string = {'R', 'E', 'F'}; |
| private static final char[] entit_string = {'E', 'N', 'T', 'I', 'T'}; |
| private static final char[] ies_string = {'I', 'E', 'S'}; |
| private static final char[] nmtoken_string = {'N', 'M', 'T', 'O', 'K', 'E', 'N'}; |
| private static final char[] notation_string = {'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N'}; |
| private static final char[] required_string = {'#', 'R', 'E', 'Q', 'U', 'I', 'R', 'E', 'D'}; |
| private static final char[] implied_string = {'#', 'I', 'M', 'P', 'L', 'I', 'E', 'D'}; |
| private static final char[] fixed_string = {'#', 'F', 'I', 'X', 'E', 'D'}; |
| |
| private static final char[] system_string = {'S', 'Y', 'S', 'T', 'E', 'M'}; |
| private static final char[] public_string = {'P', 'U', 'B', 'L', 'I', 'C'}; |
| private static final char[] ndata_string = {'N', 'D', 'A', 'T', 'A'}; |
| |
| private int[] fOpStack = null; |
| private CMGroupNode[] fGrpStack = null; |
| |
| private EntityPool entityPool; |
| |
| /* Attribute Def scanner state */ |
| static final int Att_Scanner_State_Name = 1, Att_Scanner_State_Type = 2, Att_Scanner_State_DefaultType = 3, Att_Scanner_State_DefaultValue = 4; |
| |
| private StringParser contentString; |
| private String cData; |
| private int prevNodeOffset = 0; |
| private int nodeOffset = 1; |
| private String ownerDTD; |
| |
| private String errorString; |
| |
| public DTDScanner(String ownerDTD, String cm) { |
| // System.out.println("Cm: " + cm); |
| contentString = new StringParser(cm); |
| cData = cm; |
| this.ownerDTD = ownerDTD; |
| } |
| |
| // |
| // [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children |
| // |
| // Specific to VisualDTD : also allows %PEReference; |
| // |
| public CMNode scanContentModel() { |
| CMNode cmNode = null; |
| contentString.skipPastSpaces(); |
| if (contentString.skippedString(empty_string)) { |
| cmNode = new CMBasicNode("EMPTY", CMNodeType.EMPTY); //$NON-NLS-1$ |
| } |
| else if (contentString.skippedString(any_string)) { |
| cmNode = new CMBasicNode("ANY", CMNodeType.ANY); //$NON-NLS-1$ |
| } |
| else if (contentString.lookingAtChar('%', true)) { |
| cmNode = new CMReferenceNode(contentString.getData(), CMNodeType.ENTITY_REFERENCE); |
| } |
| else if (!contentString.lookingAtChar('(', true)) { |
| // This means that the contentmodel string is bad... |
| // System.out.println("!!! exception - no ("); |
| return cmNode; |
| } |
| else { |
| // System.out.println("Remaining String = " + |
| // contentString.getRemainingString()); |
| |
| contentString.skipPastSpaces(); |
| boolean skippedPCDATA = contentString.skippedString(pcdata_string); |
| if (skippedPCDATA) { |
| cmNode = scanMixed(); |
| } |
| else { |
| cmNode = scanChildren(); |
| } |
| |
| } |
| return cmNode; |
| } |
| |
| // |
| // [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? |
| // '#PCDATA' S? ')' |
| // |
| // Called after scanning past '(' S? '#PCDATA' |
| // |
| private CMNode scanMixed() { |
| // System.out.println("ScanMixed..."); |
| CMGroupNode cmNode = new CMGroupNode(); |
| cmNode.setGroupKind(CMNodeType.GROUP_CHOICE); |
| cmNode.addChild(new CMBasicNode("#PCDATA", CMNodeType.PCDATA)); //$NON-NLS-1$ |
| |
| // int prevNodeIndex = -1; |
| boolean starRequired = false; |
| |
| |
| while (true) { |
| if (contentString.lookingAtSpace(true)) { |
| contentString.skipPastSpaces(); |
| } |
| prevNodeOffset = contentString.getCurrentOffset(); |
| |
| if (!contentString.lookingAtChar('|', true)) { |
| if (!contentString.lookingAtChar(')', true)) { |
| break; |
| } |
| if (contentString.lookingAtChar('*', true)) { |
| cmNode.setOccurrence(CMNodeType.ZERO_OR_MORE); |
| } |
| else if (starRequired) { |
| // System.out.println(" * is required ... "); |
| } |
| break; |
| } |
| |
| if (contentString.lookingAtSpace(true)) { |
| contentString.skipPastSpaces(); |
| } |
| |
| nodeOffset = contentString.getCurrentOffset(); |
| if (nodeOffset != -1) { |
| // skip pass "|" |
| prevNodeOffset = nodeOffset; |
| } |
| |
| starRequired = true; |
| contentString.skipPastNameAndPEReference(')'); |
| nodeOffset = contentString.getCurrentOffset(); |
| |
| if (nodeOffset == -1) |
| break; |
| |
| // add leave node |
| int len = nodeOffset - prevNodeOffset; |
| String refName = contentString.getString(prevNodeOffset, len); |
| prevNodeOffset = nodeOffset; |
| if (refName.startsWith("%")) //$NON-NLS-1$ |
| cmNode.addChild(new CMReferenceNode(refName, CMNodeType.ENTITY_REFERENCE)); |
| else |
| cmNode.addChild(new CMReferenceNode(refName, CMNodeType.ELEMENT_REFERENCE)); |
| |
| } // end while |
| |
| |
| if (cmNode.getChildren().size() == 1) { |
| // simplify the contentModel if the CMGroupNode only has one child |
| // node. |
| return (CMBasicNode) cmNode.getChildren().elementAt(0); |
| } |
| |
| return cmNode; |
| } |
| |
| // |
| // [47] children ::= (choice | seq) ('?' | '*' | '+')? |
| // [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')' |
| // [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' |
| // [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')? |
| // |
| // Called after scanning past '(' |
| |
| private CMNode scanChildren() { |
| |
| // System.out.println("scanChildren..."); |
| |
| if (contentString.lookingAtSpace(true)) { |
| contentString.skipPastSpaces(); |
| } |
| |
| prevNodeOffset = contentString.getCurrentOffset(); |
| nodeOffset = contentString.getCurrentOffset(); |
| int depth = 1; |
| initializeContentModelStack(depth); |
| int len; |
| |
| String nodeName; |
| CMGroupNode cmNode = new CMGroupNode(); |
| fGrpStack[depth] = cmNode; |
| |
| while (true) { |
| |
| // System.out.println(" Begin outter while loop ..." ); |
| if (contentString.lookingAtChar('(', true)) { |
| if (contentString.lookingAtSpace(true)) { |
| // skip past any white spaces after the '(' |
| contentString.skipPastSpaces(); |
| } |
| |
| depth++; |
| initializeContentModelStack(depth); |
| fGrpStack[depth] = new CMGroupNode(); |
| fGrpStack[depth - 1].addChild(fGrpStack[depth]); |
| continue; |
| } |
| |
| prevNodeOffset = contentString.getCurrentOffset(); |
| contentString.skipPastNameAndPEReference(')'); |
| nodeOffset = contentString.getCurrentOffset(); |
| |
| /* |
| * System.out.println(" prevNodeOFfset " + prevNodeOffset); |
| * System.out.println(" currentNodeOFfset " + nodeOffset); |
| */ |
| |
| len = nodeOffset - prevNodeOffset; |
| |
| if (nodeOffset == -1 || len < 1) { |
| break; |
| } |
| |
| nodeName = contentString.getString(prevNodeOffset, len); |
| |
| CMRepeatableNode rn; |
| if (nodeName.startsWith("%")) { //$NON-NLS-1$ |
| rn = new CMReferenceNode(nodeName, CMNodeType.ENTITY_REFERENCE); |
| } |
| else { |
| rn = new CMReferenceNode(nodeName, CMNodeType.ELEMENT_REFERENCE); |
| } |
| |
| fGrpStack[depth].addChild(rn); |
| |
| prevNodeOffset = nodeOffset; |
| |
| if (contentString.lookingAtChar('?', true)) { |
| rn.setOccurrence(CMNodeType.OPTIONAL); |
| } |
| else if (contentString.lookingAtChar('*', true)) { |
| rn.setOccurrence(CMNodeType.ZERO_OR_MORE); |
| } |
| else if (contentString.lookingAtChar('+', true)) { |
| rn.setOccurrence(CMNodeType.ONE_OR_MORE); |
| } |
| |
| if (contentString.lookingAtSpace(true)) { |
| contentString.skipPastSpaces(); |
| } |
| |
| prevNodeOffset = contentString.getCurrentOffset(); |
| |
| while (true) { |
| // System.out.println(" Begin inner while loop ... depth " + |
| // depth ); |
| if (fOpStack[depth] != CMNodeType.GROUP_SEQUENCE && contentString.lookingAtChar('|', true)) { |
| fOpStack[depth] = CMNodeType.GROUP_CHOICE; |
| fGrpStack[depth].setGroupKind(CMNodeType.GROUP_CHOICE); |
| if (contentString.lookingAtSpace(true)) |
| contentString.skipPastSpaces(); |
| break; |
| } |
| else if (fOpStack[depth] != CMNodeType.GROUP_CHOICE && contentString.lookingAtChar(',', true)) { |
| fOpStack[depth] = CMNodeType.GROUP_SEQUENCE; |
| fGrpStack[depth].setGroupKind(CMNodeType.GROUP_SEQUENCE); |
| if (contentString.lookingAtSpace(true)) |
| contentString.skipPastSpaces(); |
| break; |
| } |
| else { |
| if (contentString.lookingAtSpace(true)) { |
| contentString.skipPastSpaces(); |
| } |
| if (!contentString.lookingAtChar(')', true)) { |
| // System.out.println(" error ) not found"); |
| } |
| // end of the curent group node |
| if (contentString.lookingAtChar('?', true)) { |
| fGrpStack[depth].setOccurrence(CMNodeType.OPTIONAL); |
| } |
| else if (contentString.lookingAtChar('*', true)) { |
| fGrpStack[depth].setOccurrence(CMNodeType.ZERO_OR_MORE); |
| } |
| else if (contentString.lookingAtChar('+', true)) { |
| fGrpStack[depth].setOccurrence(CMNodeType.ONE_OR_MORE); |
| } |
| depth--; |
| if (depth == 0) { |
| break; |
| } |
| if (contentString.lookingAtSpace(true)) |
| contentString.skipPastSpaces(); |
| |
| // System.out.println(" End end inner while loop ... depth |
| // " + depth ); |
| |
| } |
| } // inner while |
| |
| if (depth == 0) { |
| break; |
| } |
| } // outer while |
| |
| if (cmNode.getChildren().size() == 1) { |
| // simplify the contentModel if the CMGroupNode only has one child |
| // node and that node is an element ref. |
| CMRepeatableNode rn = (CMRepeatableNode) cmNode.getChildren().elementAt(0); |
| if (rn instanceof CMReferenceNode) { |
| CMReferenceNode ref = (CMReferenceNode) rn; |
| if (ref.getType() == CMNodeType.ELEMENT_REFERENCE) { |
| if (ref.getOccurrence() == CMNodeType.ONE) { |
| ref.setOccurrence(cmNode.getOccurrence()); |
| return ref; |
| } |
| else if (cmNode.getOccurrence() == CMNodeType.ONE) { |
| return ref; |
| } |
| } // end of if () |
| } |
| } |
| |
| return cmNode; |
| } |
| |
| // |
| // [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>' |
| // [53] AttDef ::= S Name S AttType S DefaultDecl |
| // [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? |
| // AttValue) |
| // |
| |
| public Vector scanAttlistDecl(EntityPool entityPool) { |
| Vector attList = new Vector(); |
| this.entityPool = entityPool; |
| |
| int scannerState = Att_Scanner_State_Name; |
| |
| AttNode attNode; |
| |
| while (true) { |
| attNode = new AttNode(); |
| |
| // System.out.println(" scanner state: " + scannerState); |
| |
| // scanning att name |
| if (scannerState == Att_Scanner_State_Name) { |
| // System.out.println("scan att Name..."); |
| scannerState = checkForAttributeWithPEReference(attNode, scannerState); |
| if (scannerState == -1) { |
| return attList; |
| } |
| } |
| |
| // scanning att type |
| if (scannerState == Att_Scanner_State_Type) { |
| // System.out.println("scan att type..."); |
| |
| if (contentString.skippedString(cdata_string)) { |
| attNode.type = new String(cdata_string); |
| scannerState = Att_Scanner_State_DefaultType; |
| } |
| else if (contentString.skippedString(id_string)) { |
| if (!contentString.skippedString(ref_string)) { |
| attNode.type = new String(id_string); |
| } |
| else if (!contentString.lookingAtChar('S', true)) { |
| attNode.type = "IDREF"; //$NON-NLS-1$ |
| } |
| else { |
| attNode.type = "IDREFS"; //$NON-NLS-1$ |
| } |
| scannerState = Att_Scanner_State_DefaultType; |
| } |
| else if (contentString.skippedString(entit_string)) { |
| if (contentString.lookingAtChar('Y', true)) { |
| attNode.type = "ENTITY"; //$NON-NLS-1$ |
| } |
| else if (contentString.skippedString(ies_string)) { |
| attNode.type = "ENTITIES"; //$NON-NLS-1$ |
| } |
| scannerState = Att_Scanner_State_DefaultType; |
| } |
| else if (contentString.skippedString(nmtoken_string)) { |
| if (contentString.lookingAtChar('S', true)) { |
| attNode.type = "NMTOKENS"; //$NON-NLS-1$ |
| } |
| else { |
| attNode.type = "NMTOKEN"; //$NON-NLS-1$ |
| } |
| scannerState = Att_Scanner_State_DefaultType; |
| } |
| else if (contentString.skippedString(notation_string)) { |
| if (contentString.lookingAtSpace(true)) { |
| contentString.skipPastSpaces(); |
| } |
| if (!contentString.lookingAtChar('(', true)) { |
| System.out.println(" missing ( in notation "); //$NON-NLS-1$ |
| } |
| attNode.type = "NOTATION"; //$NON-NLS-1$ |
| attNode.enumList = scanEnumeration(contentString, true); |
| scannerState = Att_Scanner_State_DefaultType; |
| } |
| else if (contentString.lookingAtChar('(', true)) { |
| attNode.type = "ENUMERATION"; //$NON-NLS-1$ |
| attNode.enumList = scanEnumeration(contentString, false); |
| scannerState = Att_Scanner_State_DefaultType; |
| } |
| else { |
| scannerState = checkForAttributeWithPEReference(attNode, scannerState); |
| if (scannerState == Att_Scanner_State_Type) { |
| setErrorString("Failed to find type for attribute '" + attNode.name + "'. Please refer to the original DTD file."); //$NON-NLS-1$ //$NON-NLS-2$ |
| // we failed to find a type for this attribute |
| return attList; |
| } |
| } |
| } |
| |
| if (scannerState == Att_Scanner_State_DefaultType) { |
| contentString.skipPastSpaces(); |
| // System.out.println("scan default type..."); |
| if (contentString.skippedString(required_string)) { |
| attNode.defaultType = new String(required_string); |
| } |
| else if (contentString.skippedString(implied_string)) { |
| attNode.defaultType = new String(implied_string); |
| } |
| else { |
| if (contentString.skippedString(fixed_string)) { |
| contentString.skipPastSpaces(); |
| attNode.defaultType = new String(fixed_string); |
| } |
| else |
| // "default" |
| attNode.defaultType = "NOFIXED"; //$NON-NLS-1$ |
| |
| if (contentString.lookingAtSpace(true)) |
| contentString.skipPastSpaces(); |
| attNode.defaultValue = scanDefaultAttValue(contentString); |
| } |
| scannerState = Att_Scanner_State_Name; // next |
| } |
| |
| |
| attList.addElement(attNode); |
| if (contentString.lookingAtSpace(true)) |
| contentString.skipPastSpaces(); |
| nodeOffset = contentString.getCurrentOffset(); |
| |
| if (nodeOffset >= cData.length()) |
| return attList; |
| |
| prevNodeOffset = contentString.getCurrentOffset(); |
| |
| }// end while loop |
| } |
| |
| // |
| // content model stack |
| // |
| private void initializeContentModelStack(int depth) { |
| if (fOpStack == null) { |
| fOpStack = new int[8]; |
| fGrpStack = new CMGroupNode[8]; |
| } |
| else if (depth == fOpStack.length) { |
| int[] newStack = new int[depth * 2]; |
| System.arraycopy(fOpStack, 0, newStack, 0, depth); |
| fOpStack = newStack; |
| |
| CMGroupNode[] newGrpStack = new CMGroupNode[depth * 2]; |
| System.arraycopy(fGrpStack, 0, newGrpStack, 0, depth); |
| fGrpStack = newGrpStack; |
| } |
| fOpStack[depth] = -1; |
| fGrpStack[depth] = null; |
| } |
| |
| // |
| private int checkForAttributeWithPEReference(AttNode attNode, int scannerState) { |
| int state = -1; |
| int len; |
| String rawText; |
| EntityDecl pEntity; |
| |
| // System.out.println(" checkforATTPERReference- start scannerState: " |
| // + scannerState); |
| if (scannerState == Att_Scanner_State_Name) { |
| contentString.skipPastNameAndPEReference(' '); |
| nodeOffset = contentString.getCurrentOffset(); |
| len = nodeOffset - prevNodeOffset; |
| |
| rawText = contentString.getString(prevNodeOffset, len); |
| attNode.name = rawText; |
| |
| // System.out.println("State_name : " + rawText); |
| |
| if (rawText.startsWith("%") && rawText.endsWith(";")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| String pe = rawText.substring(1, rawText.length() - 1); |
| |
| pEntity = entityPool.referPara(pe); |
| if (pEntity != null) { |
| // System.out.println(" name :" + rawText +" expandTo:" + |
| // pEntity.expandedValue); |
| state = whatIsTheNextAttributeScanningState(pEntity.expandedValue, scannerState); |
| // System.out.println("checkForAttrwithPER - nextstate: " |
| // + state); |
| } |
| else |
| state = Att_Scanner_State_Type; |
| } |
| else |
| state = Att_Scanner_State_Type; |
| |
| } |
| else if (scannerState == Att_Scanner_State_Type) { |
| if (contentString.lookingAtChar('%', true)) { |
| rawText = getPEName(); |
| attNode.type = "%" + rawText; //$NON-NLS-1$ |
| String peName = rawText.substring(0, rawText.length() - 1); |
| // System.out.println("State_type : pe- " + peName); |
| pEntity = entityPool.referPara(peName); |
| if (pEntity != null) { |
| state = whatIsTheNextAttributeScanningState(pEntity.expandedValue, scannerState); |
| } |
| else |
| state = Att_Scanner_State_DefaultType; |
| } |
| else |
| state = Att_Scanner_State_Type; |
| } |
| else if (scannerState == Att_Scanner_State_DefaultType) { |
| if (contentString.lookingAtChar('%', true)) { |
| rawText = getPEName(); |
| attNode.defaultType = rawText; |
| // System.out.println("State_defaultType : " + rawText); |
| pEntity = entityPool.referPara(rawText.substring(1, rawText.length() - 1)); |
| if (pEntity != null) { |
| state = whatIsTheNextAttributeScanningState(pEntity.expandedValue, scannerState); |
| } |
| else |
| state = Att_Scanner_State_DefaultValue; |
| } |
| else |
| state = Att_Scanner_State_DefaultType; |
| } |
| else if (scannerState == Att_Scanner_State_DefaultValue) { |
| if (contentString.lookingAtChar('%', true)) { |
| rawText = getPEName(); |
| attNode.defaultValue = rawText; |
| // System.out.println("State_defaultValue : " + rawText); |
| |
| pEntity = entityPool.referPara(rawText.substring(1, rawText.length() - 1)); |
| if (pEntity != null) { |
| state = whatIsTheNextAttributeScanningState(pEntity.expandedValue, scannerState); |
| } |
| else |
| state = Att_Scanner_State_DefaultValue; |
| } |
| else |
| state = Att_Scanner_State_DefaultValue; |
| } |
| |
| if (contentString.lookingAtSpace(true)) |
| contentString.skipPastSpaces(); |
| prevNodeOffset = contentString.getCurrentOffset(); |
| return state; |
| } |
| |
| private String getPEName() { |
| prevNodeOffset = contentString.getCurrentOffset(); |
| contentString.skipToChar(';', true); |
| nodeOffset = contentString.getCurrentOffset(); |
| int len = nodeOffset - prevNodeOffset; |
| return contentString.getString(prevNodeOffset, len); |
| } |
| |
| private int whatIsTheNextAttributeScanningState(String attrContentString, int currentState) { |
| StringParser sp = new StringParser(attrContentString.trim()); |
| |
| |
| int nextState = currentState; |
| int nOffset = 0; |
| |
| /* |
| * System.out.println("WhatistheNext AttContentStringt : " + |
| * attrContentString); System.out.println("WhatistheNext |
| * AttContentStringL : " + attrContentString.length()); |
| * System.out.println("WhatistheNext currentstate : " + currentState); |
| */ |
| |
| while (true) { |
| // System.out.println("WhatistheNext inside whil nextstate : " + |
| // nextState); |
| if (nextState == Att_Scanner_State_Name) { // the current |
| // scanning state is |
| // Attr Name, is the |
| // next part Attr Type |
| // ? |
| if (isAttrName(sp)) { |
| nextState = Att_Scanner_State_Type; |
| } |
| } |
| else if (nextState == Att_Scanner_State_Type) { // the current |
| // scanning state |
| // is Attr Type, |
| // is the next |
| // part Default |
| // Attr Type ? |
| |
| if (isAttrType(sp)) { |
| nextState = Att_Scanner_State_DefaultType; |
| } |
| else |
| System.out.println("WhatistheNext Attr Part - is not an Attr Type"); //$NON-NLS-1$ |
| |
| } |
| |
| if (nextState == Att_Scanner_State_DefaultType) { |
| |
| int dType = isAttrDefaultType(sp); |
| // System.out.println("WhatistheNext inside dType : " + |
| // dType); |
| if (dType == 1) // #REQUIRED or #IMPLIED |
| { |
| nextState = Att_Scanner_State_Name; |
| } |
| else { |
| if (dType == 2) // #FIXED |
| { |
| // need to look at this again |
| nextState = Att_Scanner_State_DefaultType; |
| } |
| |
| if (scanDefaultAttValue(sp) != null) { |
| nextState = Att_Scanner_State_Name; |
| |
| } |
| } |
| } |
| |
| sp.skipPastSpaces(); |
| |
| if (nOffset == sp.getCurrentOffset()) |
| break; |
| |
| nOffset = sp.getCurrentOffset(); |
| |
| if (nOffset >= attrContentString.length() || nOffset == -1) |
| break; |
| |
| } // end while |
| |
| return nextState; |
| } |
| |
| |
| private boolean isAttrName(StringParser sp) { |
| // System.out.println("isAttrName - sp:" + sp.fData); |
| // System.out.println("isAttrName - currentOffset:" + |
| // sp.getCurrentOffset()); |
| boolean isAttrName = false; |
| int prev = sp.getCurrentOffset(); |
| sp.skipPastName(' '); |
| if ((sp.getCurrentOffset() - prev) > 0) |
| isAttrName = true; |
| return isAttrName; |
| |
| } |
| |
| private boolean isAttrType(StringParser sp) { |
| // System.out.println("isAttrType - sp:" + sp.fData); |
| // System.out.println("isAttrType - currentOffset:" + |
| // sp.getCurrentOffset()); |
| boolean isAttrType = false; |
| if (sp.skippedString(cdata_string)) { |
| isAttrType = true; |
| } |
| else if (sp.skippedString(id_string)) { |
| if (!sp.skippedString(ref_string)) { |
| isAttrType = true; // ID |
| } |
| else if (!sp.lookingAtChar('S', true)) { |
| isAttrType = true; // IDREFS |
| } |
| else { |
| isAttrType = true; // IDREF |
| } |
| } |
| else if (sp.skippedString(entit_string)) { |
| if (sp.lookingAtChar('Y', true)) { |
| isAttrType = true; // ENTITY |
| } |
| else if (sp.skippedString(ies_string)) { |
| isAttrType = true; // ENTITITES |
| } |
| } |
| else if (sp.skippedString(nmtoken_string)) { |
| if (sp.lookingAtChar('S', true)) { |
| isAttrType = true; // NMTOKENS |
| } |
| else { |
| isAttrType = true; // NMTOKEN |
| } |
| } |
| else if (sp.skippedString(notation_string)) { |
| if (!sp.lookingAtChar('(', true)) { |
| // System.out.println(" missing ( in notation "); |
| } |
| Vector enumList = scanEnumeration(sp, true); |
| if (enumList == null || enumList.size() == 0) |
| isAttrType = false; |
| else |
| isAttrType = true; |
| } |
| else if (sp.lookingAtChar('(', true)) { |
| // "ENUMERATION"; |
| Vector enumList = scanEnumeration(sp, false); |
| if (enumList == null || enumList.size() == 0) |
| isAttrType = false; |
| else |
| isAttrType = true; |
| } |
| |
| return isAttrType; |
| |
| } |
| |
| /* |
| * return 0 - not default type 1 - #REQUIRED or #IMPLIED 2 - #FIXED |
| */ |
| |
| private int isAttrDefaultType(StringParser sp) { |
| // System.out.println("isAttrDefaultType - sp:" + sp.fData); |
| int result = 0; |
| if (sp.skippedString(required_string)) { |
| result = 1; |
| } |
| else if (sp.skippedString(implied_string)) { |
| result = 1; |
| } |
| else if (sp.skippedString(fixed_string)) { |
| result = 2; |
| } |
| return result; |
| } |
| |
| // |
| // [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' |
| // [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' |
| // |
| // Called after scanning '(' |
| // |
| private Vector scanEnumeration(StringParser sp, boolean isNotationType) { |
| // System.out.println(" scanEnum ..."); |
| Vector enumList = null; |
| int len; |
| |
| if (sp.lookingAtSpace(true)) |
| sp.skipPastSpaces(); |
| |
| int prevNodeOffset = sp.getCurrentOffset(); |
| int nodeOffset; |
| |
| String nodeName; |
| |
| while (true) { |
| |
| if (isNotationType) |
| sp.skipPastNameAndPEReference(')'); |
| else |
| sp.skipPastNmtokenAndPEReference(')'); |
| |
| nodeOffset = sp.getCurrentOffset(); |
| |
| if (nodeOffset == -1) { |
| return enumList; |
| } |
| |
| len = nodeOffset - prevNodeOffset; |
| nodeName = sp.getString(prevNodeOffset, len); |
| |
| if (enumList == null) |
| enumList = new Vector(); |
| |
| enumList.addElement(nodeName); |
| |
| if (sp.lookingAtSpace(true)) |
| sp.skipPastSpaces(); |
| |
| if (!sp.lookingAtChar('|', true)) { |
| if (!sp.lookingAtChar(')', true)) { |
| System.out.println("scanning enum values - error missing ')'"); //$NON-NLS-1$ |
| break; |
| } |
| break; |
| } |
| |
| if (sp.lookingAtSpace(true)) |
| sp.skipPastSpaces(); |
| |
| prevNodeOffset = sp.getCurrentOffset(); |
| } |
| return enumList; |
| } |
| |
| // |
| // [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
| // | "'" ([^<&'] | Reference)* "'" |
| // |
| /** |
| * Scan the default value in an attribute declaration |
| * |
| * @param elementType |
| * handle to the element that owns the attribute |
| * @param attrName |
| * handle in the string pool for the attribute name |
| * @return handle in the string pool for the default attribute value |
| * @exception java.lang.Exception |
| */ |
| public String scanDefaultAttValue(StringParser sp) { |
| String value = null; |
| // System.out.println("scan default ATT Value... sp:" + sp.fData); |
| |
| sp.skipPastSpaces(); |
| |
| boolean single; |
| if (!(single = sp.lookingAtChar('\'', true)) && !sp.lookingAtChar('\"', true)) { |
| return value; |
| } |
| |
| char qchar = single ? '\'' : '\"'; |
| int sOffset = sp.getCurrentOffset(); |
| sp.skipToChar(qchar, true); |
| int len = sp.getCurrentOffset() - sOffset - 1; |
| if (len == 0) |
| value = ""; //$NON-NLS-1$ |
| else |
| value = sp.getString(sOffset, len); |
| |
| return value; |
| } |
| |
| // |
| // [70] EntityDecl ::= GEDecl | PEDecl |
| // [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>' |
| // [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>' |
| // [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?) |
| // [74] PEDef ::= EntityValue | ExternalID |
| // [75] ExternalID ::= 'SYSTEM' S SystemLiteral |
| // | 'PUBLIC' S PubidLiteral S SystemLiteral |
| // [76] NDataDecl ::= S 'NDATA' S Name |
| // [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
| // | "'" ([^%&'] | PEReference | Reference)* "'" |
| // |
| // Called after scanning 'ENTITY' |
| // |
| public EntityDecl scanEntityDecl() { |
| prevNodeOffset = 1; |
| nodeOffset = 1; |
| int len; |
| boolean isPEDecl = false; |
| EntityDecl entityDecl = null; |
| |
| String name = null; |
| String ndata = null; |
| |
| if (contentString.lookingAtSpace(true)) { |
| contentString.skipPastSpaces(); |
| if (!contentString.lookingAtChar('%', true)) { |
| isPEDecl = false; // <!ENTITY x "x"> |
| } |
| else if (contentString.lookingAtSpace(true)) { |
| isPEDecl = true; // <!ENTITY % x "x"> |
| } |
| prevNodeOffset = contentString.getCurrentOffset(); |
| contentString.skipPastName(' '); |
| nodeOffset = contentString.getCurrentOffset(); |
| len = nodeOffset - prevNodeOffset; |
| if (len > 0) { |
| name = contentString.getString(prevNodeOffset, len); |
| prevNodeOffset = nodeOffset; |
| } |
| } |
| |
| if (name == null) |
| return null; |
| |
| contentString.skipPastSpaces(); |
| prevNodeOffset = contentString.getCurrentOffset(); |
| |
| boolean single; |
| if ((single = contentString.lookingAtChar('\'', true)) || contentString.lookingAtChar('\"', true)) { |
| String value = scanEntityValue(single); |
| entityDecl = new EntityDecl(name, ownerDTD, value, isPEDecl); |
| } |
| else { |
| // external entity |
| ExternalID xID = scanExternalID(); |
| if (xID != null) { |
| if (!isPEDecl) // general entity |
| { |
| boolean unparsed = false; |
| contentString.skipPastSpaces(); |
| unparsed = contentString.skippedString(ndata_string); |
| if (unparsed) { |
| contentString.skipPastSpaces(); |
| prevNodeOffset = contentString.getCurrentOffset(); |
| contentString.skipPastName(' '); |
| nodeOffset = contentString.getCurrentOffset(); |
| len = nodeOffset - prevNodeOffset; |
| ndata = contentString.getString(prevNodeOffset, len); |
| } |
| } |
| entityDecl = new EntityDecl(name, ownerDTD, xID, isPEDecl, ndata); |
| } |
| } |
| return entityDecl; |
| } |
| |
| |
| // |
| // [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? |
| // '>' |
| // [75] ExternalID ::= 'SYSTEM' S SystemLiteral |
| // | 'PUBLIC' S PubidLiteral S SystemLiteral |
| // [83] PublicID ::= 'PUBLIC' S PubidLiteral |
| // |
| // Called after scanning 'NOTATION' |
| // |
| public NotationDecl scanNotationDecl() { |
| prevNodeOffset = 1; |
| nodeOffset = 1; |
| int len; |
| NotationDecl notationDecl = null; |
| |
| String name = null; |
| |
| if (contentString.lookingAtSpace(true)) { |
| contentString.skipPastSpaces(); |
| prevNodeOffset = contentString.getCurrentOffset(); |
| contentString.skipPastName(' '); |
| nodeOffset = contentString.getCurrentOffset(); |
| len = nodeOffset - prevNodeOffset; |
| if (len > 0) { |
| name = contentString.getString(prevNodeOffset, len); |
| prevNodeOffset = nodeOffset; |
| } |
| } |
| |
| if (name == null) |
| return null; |
| |
| contentString.skipPastSpaces(); |
| prevNodeOffset = contentString.getCurrentOffset(); |
| |
| notationDecl = new NotationDecl(name, ownerDTD); |
| |
| ExternalID xID = scanExternalID(); |
| if (xID != null) { |
| if (xID.getSystemLiteral() != null) { |
| notationDecl.setSystemId(xID.getSystemLiteral()); |
| } |
| if (xID.getPubIdLiteral() != null) { |
| notationDecl.setPublicId(xID.getPubIdLiteral()); |
| } |
| } |
| |
| return notationDecl; |
| } |
| |
| |
| private String scanEntityValue(boolean single) { |
| char qchar = single ? '\'' : '\"'; |
| prevNodeOffset = contentString.getCurrentOffset(); |
| contentString.skipToChar(qchar, false); |
| int len = contentString.getCurrentOffset() - prevNodeOffset; |
| String value = contentString.getString(prevNodeOffset, len); |
| return value; |
| } |
| |
| // |
| // [75] ExternalID ::= 'SYSTEM' S SystemLiteral |
| // | 'PUBLIC' S PubidLiteral S SystemLiteral |
| private ExternalID scanExternalID() { |
| ExternalID xID = null; |
| char qchar = '\"'; |
| if (contentString.skippedString(system_string)) { |
| if (!contentString.lookingAtSpace(true)) { |
| return null; |
| } |
| contentString.skipPastSpaces(); |
| |
| if (contentString.lookingAtChar('\'', true)) |
| qchar = '\''; |
| else if (contentString.lookingAtChar('\"', true)) |
| qchar = '\"'; |
| |
| prevNodeOffset = contentString.getCurrentOffset(); |
| contentString.skipToChar(qchar, true); |
| int len = contentString.getCurrentOffset() - prevNodeOffset - 1; |
| String systemId = contentString.getString(prevNodeOffset, len); |
| // System.out.println("systemid..." + systemId); |
| xID = new ExternalID(systemId); |
| } |
| else if (contentString.skippedString(public_string)) { |
| if (!contentString.lookingAtSpace(true)) { |
| return null; |
| } |
| |
| contentString.skipPastSpaces(); |
| if (contentString.lookingAtChar('\'', true)) |
| qchar = '\''; |
| else if (contentString.lookingAtChar('\"', true)) |
| qchar = '\"'; |
| |
| // publicLiteral |
| prevNodeOffset = contentString.getCurrentOffset(); |
| contentString.skipToChar(qchar, true); |
| int len = contentString.getCurrentOffset() - prevNodeOffset - 1; |
| String publicId = contentString.getString(prevNodeOffset, len); |
| |
| // systemLiteral |
| contentString.skipPastSpaces(); |
| if (contentString.lookingAtChar('\'', true)) |
| qchar = '\''; |
| else if (contentString.lookingAtChar('\"', true)) |
| qchar = '\"'; |
| prevNodeOffset = contentString.getCurrentOffset(); |
| contentString.skipToChar(qchar, true); |
| len = contentString.getCurrentOffset() - prevNodeOffset - 1; |
| |
| if (len > 0) { |
| String systemId = contentString.getString(prevNodeOffset, len); |
| xID = new ExternalID(publicId, systemId); |
| } |
| else { |
| xID = new ExternalID(publicId, null); |
| } |
| } |
| return xID; |
| } |
| |
| // |
| // [83] PublicID ::= 'PUBLIC' S PubidLiteral |
| // |
| |
| // dmw 11/15 private method never read locally |
| // TODO: change to private if used, otherwise should be removed |
| String scanPublicID() { |
| String pID = null; |
| if (contentString.skippedString(public_string)) { |
| if (!contentString.lookingAtSpace(true)) { |
| return pID; |
| } |
| contentString.skipPastSpaces(); |
| prevNodeOffset = contentString.getCurrentOffset(); |
| |
| contentString.skipToChar(' ', true); |
| int len = contentString.getCurrentOffset() - prevNodeOffset; |
| pID = contentString.getString(prevNodeOffset, len); |
| } |
| |
| return pID; |
| } |
| |
| // |
| // Main |
| // |
| |
| /** Main program entry point. */ |
| public static void main(String argv[]) { |
| |
| // is there anything to do? |
| if (argv.length == 0) { |
| System.exit(1); |
| } |
| |
| // DTDScanner sc = new DTDScanner(argv[0]); |
| DTDScanner sc = new DTDScanner("hello.dtd", " gif SYSTEM \"GIF File\" "); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| NotationDecl n = sc.scanNotationDecl(); |
| System.out.println("Noation Name: " + n.getNodeName()); //$NON-NLS-1$ |
| System.out.println("SystemId: " + n.getSystemId()); //$NON-NLS-1$ |
| |
| |
| // Attributes |
| // Vector lists = sc.scanAttlistDecl(); |
| // sc.printAttList(lists); |
| |
| // System.out.println("CM: " + sc.scanContentModel()); |
| |
| } // main(String[]) |
| |
| /** |
| * Gets the errorString |
| * |
| * @return Returns a String |
| */ |
| public String getErrorString() { |
| return errorString; |
| } |
| |
| /** |
| * Sets the errorString |
| * |
| * @param errorString |
| * The errorString to set |
| */ |
| public void setErrorString(String errorString) { |
| this.errorString = errorString; |
| } |
| |
| } |