From 6a897468edca9b5b8eb24689b9adaa6d8f11a1cc Mon Sep 17 00:00:00 2001
From: Doug Schaefer <doug.schaefer@windriver.com>
Date: Thu, 10 Jul 2003 17:50:34 +0000
Subject: [PATCH] - Added the ability to add arbitrary XML data to the
 cdtproject file. - Used to store the data that had been put in the cdtbuild
 file for Standard Make projects. - Cleaned up some of the exception handling
 in the StandardBuildManager.

---
 .../managed/tests/StandardBuildTests.java     |  12 +-
 .../build/standard/StandardBuildManager.java  | 103 ++++++------------
 .../cdt/core/parser/IScannerInfoProvider.java |   3 +-
 .../org/eclipse/cdt/core/CProjectNature.java  |   7 +-
 .../org/eclipse/cdt/core/ICDescriptor.java    |   4 +
 .../cdt/internal/core/CDescriptor.java        |  59 ++++++++++
 .../cdt/ui/wizards/BuildPathInfoBlock.java    |  34 ++++--
 7 files changed, 131 insertions(+), 91 deletions(-)

diff --git a/core/org.eclipse.cdt.core.tests/build/org/eclipse/cdt/core/build/managed/tests/StandardBuildTests.java b/core/org.eclipse.cdt.core.tests/build/org/eclipse/cdt/core/build/managed/tests/StandardBuildTests.java
index 3b929310bad..257da98bd78 100644
--- a/core/org.eclipse.cdt.core.tests/build/org/eclipse/cdt/core/build/managed/tests/StandardBuildTests.java
+++ b/core/org.eclipse.cdt.core.tests/build/org/eclipse/cdt/core/build/managed/tests/StandardBuildTests.java
@@ -107,7 +107,7 @@ public class StandardBuildTests extends TestCase {
 		return suite;
 	}
 	
-	private void checkDefaultProjectSettings(IProject project) {
+	private void checkDefaultProjectSettings(IProject project) throws Exception {
 		assertNotNull(project);
 
 		// There should not be any include path or defined symbols for the project
@@ -128,7 +128,7 @@ public class StandardBuildTests extends TestCase {
 		assertEquals(EMPTY_STRING, info.getIncrementalBuildArguments()); 
 	}
 	
-	private void checkOverriddenProjectSettings(IProject project) {
+	private void checkOverriddenProjectSettings(IProject project) throws Exception {
 		assertNotNull(project);
 
 		// Check that the new stuff is there
@@ -232,7 +232,7 @@ public class StandardBuildTests extends TestCase {
 		removeProject(PROJECT_NAME);
 	}
 
-	public void testProjectConversion() {
+	public void testProjectConversion() throws Exception {
 		// Open the project
 		IProject project = null;
 		try {
@@ -280,7 +280,7 @@ public class StandardBuildTests extends TestCase {
 	/**
 	 * 
 	 */
-	public void testProjectCreation () {
+	public void testProjectCreation() throws Exception  {
 		// Create a new project
 		IProject project = null;
 		try {
@@ -303,7 +303,7 @@ public class StandardBuildTests extends TestCase {
 		checkDefaultProjectSettings(project);
 	}
 	
-	public void testProjectSettings() {
+	public void testProjectSettings() throws Exception {
 		// Get the project
 		IProject project = null;
 		try {
@@ -342,7 +342,7 @@ public class StandardBuildTests extends TestCase {
 		checkOverriddenProjectSettings(project);
 	}
 
-	public void testScannerListenerInterface() {
+	public void testScannerListenerInterface() throws Exception  {
 		// Get the project
 		IProject project = null;
 		try {
diff --git a/core/org.eclipse.cdt.core/build/org/eclipse/cdt/core/build/standard/StandardBuildManager.java b/core/org.eclipse.cdt.core/build/org/eclipse/cdt/core/build/standard/StandardBuildManager.java
index 263e307cbdc..6dc46993f61 100644
--- a/core/org.eclipse.cdt.core/build/org/eclipse/cdt/core/build/standard/StandardBuildManager.java
+++ b/core/org.eclipse.cdt.core/build/org/eclipse/cdt/core/build/standard/StandardBuildManager.java
@@ -1,9 +1,5 @@
 package org.eclipse.cdt.core.build.standard;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -11,16 +7,9 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.apache.xerces.dom.DocumentImpl;
-import org.apache.xml.serialize.Method;
-import org.apache.xml.serialize.OutputFormat;
-import org.apache.xml.serialize.Serializer;
-import org.apache.xml.serialize.SerializerFactory;
 import org.eclipse.cdt.core.BuildInfoFactory;
 import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.ICDescriptor;
 import org.eclipse.cdt.core.parser.IScannerInfo;
 import org.eclipse.cdt.core.parser.IScannerInfoChangeListener;
 import org.eclipse.cdt.core.parser.IScannerInfoProvider;
@@ -30,9 +19,9 @@ import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.QualifiedName;
-import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**********************************************************************
  * Copyright (c) 2002,2003 Rational Software Corporation and others.
@@ -49,18 +38,16 @@ public class StandardBuildManager implements IScannerInfoProvider {
 	// Name we will use to store build property with the project
 	private static final QualifiedName buildInfoProperty
 		= new QualifiedName(CCorePlugin.PLUGIN_ID, "standardBuildInfo");
+	private static final String ID = CCorePlugin.PLUGIN_ID + ".standardBuildInfo";
 
 	// Listeners interested in build model changes
 	private static Map buildModelListeners; 
 
-	private static final String FILE_NAME = ".cdtbuild";
-	private static final String ROOT_ELEM_NAME = "StandardProjectBuildInfo";
-
 	/**
 	 * @param project
 	 * @return
 	 */
-	private static IStandardBuildInfo findBuildInfo(IResource resource, boolean create) {
+	private static IStandardBuildInfo findBuildInfo(IResource resource, boolean create) throws CoreException {
 		IStandardBuildInfo buildInfo = null;
 		// See if there's already one associated with the resource for this session
 		try {
@@ -87,11 +74,11 @@ public class StandardBuildManager implements IScannerInfoProvider {
 		return buildInfo;
 	}
 
-	public static IStandardBuildInfo getBuildInfo(IProject project) {
+	public static IStandardBuildInfo getBuildInfo(IProject project) throws CoreException {
 		return findBuildInfo(project, false);
 	}
 	
-	public static IStandardBuildInfo getBuildInfo(IProject project, boolean create) {
+	public static IStandardBuildInfo getBuildInfo(IProject project, boolean create) throws CoreException {
 		return findBuildInfo(project, create);
 	}
 
@@ -108,7 +95,7 @@ public class StandardBuildManager implements IScannerInfoProvider {
 	/* (non-Javadoc)
 	 * @see org.eclipse.cdt.core.parser.IScannerInfoProvider#managesResource(org.eclipse.core.resources.IResource)
 	 */
-	public boolean managesResource(IResource resource) {
+	public boolean managesResource(IResource resource) throws CoreException {
 		/* 
 		 * Answers true if this project has a build info associated with it
 		 */
@@ -129,7 +116,9 @@ public class StandardBuildManager implements IScannerInfoProvider {
 		return info == null ? false : true;
 	}
 
-	public static void setPreprocessorSymbols(IProject project, String[] symbols) {
+	public static void setPreprocessorSymbols(IProject project, String[] symbols)
+		throws CoreException 
+	{
 		// Get the information for the project
 		IStandardBuildInfo info = getBuildInfo(project);
 		// Set the new information
@@ -143,7 +132,9 @@ public class StandardBuildManager implements IScannerInfoProvider {
 		}
 	}
 	
-	public static void setIncludePaths(IProject project, String[] paths) {
+	public static void setIncludePaths(IProject project, String[] paths)
+		throws CoreException
+	{
 		// Get the build info for the project
 		IStandardBuildInfo info = getBuildInfo(project);
 		if (info != null) {
@@ -177,25 +168,10 @@ public class StandardBuildManager implements IScannerInfoProvider {
 	 * information is then associated with the resource for the duration of 
 	 * the session.
 	 */
-	private static IStandardBuildInfo loadBuildInfo(IProject project) {
-		IStandardBuildInfo buildInfo = null;
-		IFile file = project.getFile(FILE_NAME);
-		if (!file.exists())
-			return null;
-	
-		try {
-			InputStream stream = file.getContents();
-			DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-			Document document = parser.parse(stream);
-			Node rootElement = document.getFirstChild();
-			if (rootElement.getNodeName().equals(ROOT_ELEM_NAME)) {
-				buildInfo = BuildInfoFactory.create(project, (Element)rootElement);
-				project.setSessionProperty(buildInfoProperty, buildInfo);
-			}
-		} catch (Exception e) {
-			buildInfo = null;
-		}
-
+	private static IStandardBuildInfo loadBuildInfo(IProject project) throws CoreException {
+		ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project);
+		IStandardBuildInfo buildInfo = BuildInfoFactory.create(project, descriptor.getProjectData(ID));
+		project.setSessionProperty(buildInfoProperty, buildInfo);
 		return buildInfo;
 	}
 
@@ -224,38 +200,25 @@ public class StandardBuildManager implements IScannerInfoProvider {
 	 * 
 	 * @param project
 	 */
-	public static void saveBuildInfo(IProject project) {
-		// Create document
-		Document doc = new DocumentImpl();
-		Element rootElement = doc.createElement(ROOT_ELEM_NAME);
-		doc.appendChild(rootElement);
-
+	public static void saveBuildInfo(IProject project) throws CoreException {
+		ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project);
+		
+		Element rootElement = descriptor.getProjectData(ID); 
+		
+		// Clear out all current children
+		// Note: Probably would be a better idea to merge in the data
+		NodeList nodes = rootElement.getChildNodes();
+		for (int i = 0; i < nodes.getLength(); ++i) {
+			Node node = nodes.item(i);
+			if (node instanceof Element)
+				rootElement.removeChild(nodes.item(i));
+		}
+		
 		// Save the build info
 		IStandardBuildInfo buildInfo = getBuildInfo(project);
 		if (buildInfo != null)
-			buildInfo.serialize(doc, rootElement);
-		
-		// Save the document
-		ByteArrayOutputStream s = new ByteArrayOutputStream();
-		OutputFormat format = new OutputFormat();
-		format.setIndenting(true);
-		format.setLineSeparator(System.getProperty("line.separator")); //$NON-NLS-1$
-		String xml = null;
-		try {
-			Serializer serializer = SerializerFactory.getSerializerFactory(Method.XML).makeSerializer(new OutputStreamWriter(s, "UTF8"), format);
-			serializer.asDOMSerializer().serialize(doc);
-			xml = s.toString("UTF8"); //$NON-NLS-1$		
-			IFile rscFile = project.getFile(FILE_NAME);
-			InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
-			// update the resource content
-			if (rscFile.exists()) {
-				rscFile.setContents(inputStream, IResource.FORCE, null);
-			} else {
-				rscFile.create(inputStream, IResource.FORCE, null);
-			}
-		} catch (Exception e) {
-			return;
-		}
+			buildInfo.serialize(rootElement.getOwnerDocument(), rootElement);
+		descriptor.saveProjectData();
 	}
 
 	/* (non-Javadoc)
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IScannerInfoProvider.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IScannerInfoProvider.java
index db15f417dd2..ad34dc829d4 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IScannerInfoProvider.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IScannerInfoProvider.java
@@ -1,6 +1,7 @@
 package org.eclipse.cdt.core.parser;
 
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
 
 /**********************************************************************
  * Copyright (c) 2002,2003 Rational Software Corporation and others.
@@ -31,7 +32,7 @@ public interface IScannerInfoProvider {
 	 * @param resource
 	 * @return
 	 */
-	public boolean managesResource(IResource resource);
+	public boolean managesResource(IResource resource) throws CoreException;
 	
 	/**
 	 * The receiver will no longer notify the listener specified in 
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CProjectNature.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CProjectNature.java
index 99b3c8014df..0de56493305 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CProjectNature.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CProjectNature.java
@@ -296,8 +296,11 @@ public class CProjectNature implements IProjectNature {
      * @see IProjectNature#setProject
      */
     public void setProject(IProject project) {
-		fProject= project;
-		fBuildInfo = StandardBuildManager.getBuildInfo(fProject, true);
+    	try {
+			fProject= project;
+			fBuildInfo = StandardBuildManager.getBuildInfo(fProject, true);
+		} catch (CoreException e) {
+		}
     }
     
 }
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptor.java
index 8a6544204ae..b1e0b21aea0 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptor.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ICDescriptor.java
@@ -12,6 +12,7 @@ package org.eclipse.cdt.core;
 
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
+import org.w3c.dom.Element;
 
 public interface ICDescriptor {
 	public ICOwnerInfo getProjectOwner();
@@ -27,4 +28,7 @@ public interface ICDescriptor {
 	
 	public void setPathEntries(ICPathEntry[] entries) throws CoreException;
 	public ICPathEntry[] getPathEntries();
+	
+	public Element getProjectData(String id) throws CoreException;
+	public void saveProjectData() throws CoreException;
 }
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CDescriptor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CDescriptor.java
index 3bffb908547..7cd41537942 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CDescriptor.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CDescriptor.java
@@ -23,6 +23,7 @@ import java.util.Map.Entry;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.xerces.dom.DocumentImpl;
 import org.apache.xml.serialize.Method;
@@ -60,6 +61,7 @@ public class CDescriptor implements ICDescriptor {
 	private IProject fProject;
 	private HashMap extMap = new HashMap(4);
 	private HashMap extInfoMap = new HashMap(4);
+	private Document dataDoc;
 
 	static final String DESCRIPTION_FILE_NAME = ".cdtproject";
 	private static final char[][] NO_CHAR_CHAR = new char[0][];
@@ -67,6 +69,9 @@ public class CDescriptor implements ICDescriptor {
 	private static final String PROJECT_EXTENSION = "extension";
 	private static final String PROJECT_EXTENSION_ATTRIBUTE = "attribute";
 	private static final String PATH_ENTRY = "cpathentry";
+	private static final String PROJECT_DATA = "data";
+	private static final String PROJECT_DATA_ITEM = "item";
+	private static final String PROJECT_DATA_ID = "id";
 
 	private boolean fDirty;
 	private boolean autoSave;
@@ -328,6 +333,8 @@ public class CDescriptor implements ICDescriptor {
 					if (entry != null) {
 						pathEntries.add(entry);
 					}
+				} else if (childNode.getNodeName().equals(PROJECT_DATA)) {
+					decodeProjectData((Element)childNode);
 				}
 			}
 		}
@@ -450,6 +457,7 @@ public class CDescriptor implements ICDescriptor {
 		configRootElement.setAttribute("id", fOwner.getID()); //$NON-NLS-1$
 		encodeProjectExtensions(doc, configRootElement);
 		encodePathEntries(doc, configRootElement);
+		encodeProjectData(doc, configRootElement);
 		return serializeDocument(doc);
 	}
 
@@ -545,4 +553,55 @@ public class CDescriptor implements ICDescriptor {
 		}
 		return (ICExtension) cExtension;
 	}
+	
+	// The project data allows for the storage of any structured information
+	// into the cdtproject file.
+	private Document getProjectDataDoc() throws CoreException {
+		if (dataDoc == null) {
+			try {
+				dataDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+			} catch (ParserConfigurationException e) {
+				throw new CoreException(
+					new Status(
+						IStatus.ERROR,
+						CCorePlugin.PLUGIN_ID,
+						IStatus.ERROR,
+						"getProjectDataDoc",
+						e));
+			}
+			Element rootElem = dataDoc.createElement(PROJECT_DATA);
+			dataDoc.appendChild(rootElem);
+		}
+		return dataDoc;
+	}
+	
+	private void decodeProjectData(Element data) throws CoreException {
+		Document doc = getProjectDataDoc();
+		doc.getDocumentElement().appendChild(doc.importNode(data, true));
+	}
+
+	public Element getProjectData(String id) throws CoreException {
+		NodeList nodes = getProjectDataDoc().getDocumentElement().getElementsByTagName(PROJECT_DATA_ITEM);
+		for (int i = 0; i < nodes.getLength(); ++i) {
+			Element element = (Element)nodes.item(i);
+			if (element.getAttribute(PROJECT_DATA_ID).equals(id))
+				return element; 
+		}
+
+		// Not found, make a new one
+		Element element = dataDoc.createElement(PROJECT_DATA_ITEM);
+		element.setAttribute(PROJECT_DATA_ID, id);
+		dataDoc.getDocumentElement().appendChild(element);
+		return element;
+	}
+	
+	public void saveProjectData() throws CoreException {
+		setDirty();
+	}
+	
+	private void encodeProjectData(Document doc, Element root) {
+		// Don't create or encode the doc if it isn't there already
+		if (dataDoc != null)
+			root.appendChild(doc.importNode(dataDoc.getDocumentElement(), true));
+	}
 }
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/BuildPathInfoBlock.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/BuildPathInfoBlock.java
index d5d74c7bb84..4f30a79a671 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/BuildPathInfoBlock.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/BuildPathInfoBlock.java
@@ -265,14 +265,18 @@ public class BuildPathInfoBlock implements IWizardTab {
 			monitor = new NullProgressMonitor();
 		}
 		if (project != null) {
-			// Store the paths and symbols 
-			monitor.beginTask("Setting Include Paths", 1);
-			StandardBuildManager.setIncludePaths(project, getPathListContents());
-
-			monitor.beginTask("Setting Defined Symbols", 1);
-			StandardBuildManager.setPreprocessorSymbols(project, getSymbolListContents());
-		
-			StandardBuildManager.saveBuildInfo(project);
+			try {
+				// Store the paths and symbols 
+				monitor.beginTask("Setting Include Paths", 1);
+				StandardBuildManager.setIncludePaths(project, getPathListContents());
+	
+				monitor.beginTask("Setting Defined Symbols", 1);
+				StandardBuildManager.setPreprocessorSymbols(project, getSymbolListContents());
+			
+				StandardBuildManager.saveBuildInfo(project);
+			} catch (CoreException e) {
+				// Should probably tell someone
+			}
 		}
 	}
 
@@ -589,15 +593,21 @@ public class BuildPathInfoBlock implements IWizardTab {
 
 	private void setPathListContents() {
 		if (project != null) {
-			IStandardBuildInfo info = StandardBuildManager.getBuildInfo(project);
-			pathList.setItems(info.getIncludePaths());
+			try {
+				IStandardBuildInfo info = StandardBuildManager.getBuildInfo(project);
+				pathList.setItems(info.getIncludePaths());
+			} catch (CoreException e) {
+			}
 		}
 	}
 	
 	private void setSymbolListContents() {
 		if (project != null) {
-			IStandardBuildInfo info = StandardBuildManager.getBuildInfo(project);
-			symbolList.setItems(info.getPreprocessorSymbols());
+			try {
+				IStandardBuildInfo info = StandardBuildManager.getBuildInfo(project);
+				symbolList.setItems(info.getPreprocessorSymbols());
+			} catch (CoreException e) {
+			}
 		}
 	}