blob: 9be6f189f30d08440b3dc10daedf7743a23c7efe [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2005 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
* Jens Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org.eclipse.wst.dtd.core.internal.parser;
import java.io.Reader;
import java.io.StringReader;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;
import org.eclipse.wst.dtd.core.internal.text.DTDStructuredDocumentRegionFactory;
import org.eclipse.wst.dtd.core.internal.tokenizer.DTDTokenizer;
import org.eclipse.wst.dtd.core.internal.tokenizer.Token;
import org.eclipse.wst.sse.core.internal.ltk.parser.RegionParser;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
public class DTDRegionParser implements RegionParser {
private Vector cachedRegions = null;
private DTDTokenizer tokenizer = null;
private IStructuredDocumentRegion cachedNode = null; // top of node
// chain
public RegionParser newInstance() {
return new DTDRegionParser();
}
private IStructuredDocumentRegion addNewNodes(IStructuredDocumentRegion lastNode, Vector regions) {
IStructuredDocumentRegion leadingSpaceNode = null;
IStructuredDocumentRegion contentNode = null;
IStructuredDocumentRegion trailingSpaceNode = null;
LinkedList nodeSeeds = new LinkedList();
int nRegions = regions.size();
int leadingSpaceEnd = -1;
int trailingSpaceBegin = nRegions;
// find leading space
nodeSeeds.clear();
for (int i = 0; i < nRegions; i++) {
ITextRegion region = (ITextRegion) regions.get(i);
String type = region.getType();
if (isBlankRegion(type)) {
leadingSpaceEnd = i;
nodeSeeds.addLast(region);
}
else {
break;
}
}
if (!nodeSeeds.isEmpty()) {
leadingSpaceNode = createNode(nodeSeeds);
if (lastNode != null) {
lastNode.setNext(leadingSpaceNode);
leadingSpaceNode.setPrevious(lastNode);
}
lastNode = leadingSpaceNode;
}
// find trailing space
if (leadingSpaceEnd < nRegions - 1) {
nodeSeeds.clear();
for (int i = nRegions - 1; 0 <= i; i--) {
ITextRegion region = (ITextRegion) regions.get(i);
String type = ((ITextRegion) regions.get(i)).getType();
if (isBlankRegion(type)) {
trailingSpaceBegin = i;
nodeSeeds.addFirst(region);
}
else {
break;
}
}
if (!nodeSeeds.isEmpty()) {
trailingSpaceNode = createNode(nodeSeeds);
}
nodeSeeds.clear();
for (int i = leadingSpaceEnd + 1; i < trailingSpaceBegin; i++) {
nodeSeeds.addLast(regions.get(i));
}
if (!nodeSeeds.isEmpty()) {
contentNode = createNode(nodeSeeds);
if (lastNode != null) {
lastNode.setNext(contentNode);
contentNode.setPrevious(lastNode);
}
lastNode = contentNode;
}
if (trailingSpaceNode != null) {
lastNode.setNext(trailingSpaceNode);
trailingSpaceNode.setPrevious(lastNode);
lastNode = trailingSpaceNode;
}
}
return lastNode;
}
private IStructuredDocumentRegion createNode(LinkedList regions) {
if (regions.size() == 0) {
return null;
}
IStructuredDocumentRegion node = DTDStructuredDocumentRegionFactory.createStructuredDocumentRegion(DTDStructuredDocumentRegionFactory.DTD_GENERIC);
int start = ((ITextRegion) regions.getFirst()).getStart();
int length = ((ITextRegion) regions.getLast()).getEnd() - start;
node.setStart(start);
node.setLength(length);
for (ListIterator i = regions.listIterator(0); i.hasNext();) {
ITextRegion region = (ITextRegion) i.next();
node.addRegion(region);
region.adjustStart(-start);
}
node.setEnded(true);
return node;
}
private IStructuredDocumentRegion createNodeChain(List regions) {
IStructuredDocumentRegion headNode = null;
IStructuredDocumentRegion lastNode = null;
Vector nodeSeeds = new Vector();
for (Iterator e = regions.iterator(); e.hasNext();) {
ITextRegion region = (ITextRegion) e.next();
String type = region.getType();
// If the following regions appear,
// a previous node is closed in front of it.
if (!nodeSeeds.isEmpty() && isBeginningRegion(type)) {
lastNode = addNewNodes(lastNode, nodeSeeds);
nodeSeeds.clear();
}
nodeSeeds.addElement(region);
// The following regions close the current node.
if (!nodeSeeds.isEmpty() && isEndingRegion(type)) {
lastNode = addNewNodes(lastNode, nodeSeeds);
nodeSeeds.clear();
}
if (headNode == null && lastNode != null) {
headNode = findFirstNode(lastNode);
}
}
// close current node forcibly.
if (!nodeSeeds.isEmpty()) {
lastNode = addNewNodes(lastNode, nodeSeeds);
if (headNode == null && lastNode != null) {
headNode = findFirstNode(lastNode);
}
}
return headNode;
}
private IStructuredDocumentRegion findFirstNode(IStructuredDocumentRegion node) {
IStructuredDocumentRegion firstNode = node;
IStructuredDocumentRegion prevNode = null;
while ((prevNode = firstNode.getPrevious()) != null) {
firstNode = prevNode;
}
return firstNode;
}
public IStructuredDocumentRegion getDocumentRegions() {
if (cachedNode != null) {
return cachedNode;
}
List regions = getRegions();
IStructuredDocumentRegion headNode = createNodeChain(regions);
cachedNode = headNode;
return headNode;
}
public List getRegions() {
if (cachedRegions != null) {
return cachedRegions;
}
Vector regions = new Vector();
Token currentToken = null;
do {
try {
currentToken = (Token) tokenizer.yylex();
if (currentToken != null) {
ITextRegion region = DTDRegionFactory.createRegion(currentToken.getType(), currentToken.getStartOffset(), currentToken.getLength());
regions.add(region);
}
}
catch (java.io.FileNotFoundException e) {
System.out.println("File not found"); //$NON-NLS-1$
}
catch (java.io.IOException e) {
System.out.println("Error opening file"); //$NON-NLS-1$
}
}
while (currentToken != null);
cachedRegions = regions;
return regions;
}
public void reset(Reader reader) {
if (tokenizer == null) {
try {
tokenizer = new DTDTokenizer(reader);
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Usage : java DTDTokenizer <inputfile>"); //$NON-NLS-1$
}
}
else {
try {
tokenizer.yyreset(reader);
}
catch (java.io.IOException e) {
System.out.println("Error opening file"); //$NON-NLS-1$
}
}
cachedNode = null;
cachedRegions = null;
}
/**
* An additional offset for use with any position-dependant parsing rules
*/
public void reset(Reader reader, int offset) {
reset(reader);
}
public void reset(String input) {
reset(new StringReader(input));
}
public void reset(String input, int offset) {
reset(input);
}
// never used
DTDTokenizer getTokenizer() {
return tokenizer;
}
private boolean isBeginningRegion(String type) {
return (type == DTDRegionTypes.START_TAG) || (type == DTDRegionTypes.ENTITY_PARM);
}
private boolean isBlankRegion(String type) {
return (type == DTDRegionTypes.WHITESPACE);
}
private boolean isEndingRegion(String type) {
return (type == DTDRegionTypes.END_TAG) || (type == DTDRegionTypes.ENTITY_PARM) || (type == DTDRegionTypes.COMMENT_END);
}
}