summaryrefslogtreecommitdiff
path: root/src/main/java/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java')
-rw-r--r--src/main/java/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java866
1 files changed, 866 insertions, 0 deletions
diff --git a/src/main/java/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java b/src/main/java/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java
new file mode 100644
index 0000000..f554e09
--- /dev/null
+++ b/src/main/java/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java
@@ -0,0 +1,866 @@
+/*
+ *
+ * Copyright 2004-2008 The Ant-Contrib project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.cpptasks.devstudio;
+
+import net.sf.antcontrib.cpptasks.CCTask;
+import net.sf.antcontrib.cpptasks.CUtil;
+import net.sf.antcontrib.cpptasks.TargetInfo;
+import net.sf.antcontrib.cpptasks.compiler.CommandLineCompilerConfiguration;
+import net.sf.antcontrib.cpptasks.compiler.ProcessorConfiguration;
+import net.sf.antcontrib.cpptasks.compiler.CommandLineLinkerConfiguration;
+import net.sf.antcontrib.cpptasks.ide.ProjectDef;
+import net.sf.antcontrib.cpptasks.ide.CommentDef;
+import net.sf.antcontrib.cpptasks.ide.ProjectWriter;
+import net.sf.antcontrib.cpptasks.ide.DependencyDef;
+import org.apache.tools.ant.BuildException;
+import org.apache.xml.serialize.OutputFormat;
+import org.apache.xml.serialize.XMLSerializer;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Writes a Visual Studio.NET project file.
+ *
+ * @author curta
+ */
+public final class VisualStudioNETProjectWriter
+ implements ProjectWriter {
+ /**
+ * Version of VisualStudio.NET.
+ */
+ private final String version;
+
+ /**
+ * Literal to represent a true value.
+ */
+ private final String trueLiteral;
+
+ /**
+ * Literal to represent a false value.
+ */
+ private final String falseLiteral;
+
+ /**
+ * Constructor.
+ *
+ * @param versionArg String VisualStudio.NET version
+ * @param trueArg literal to represent true, "true" in VC 2005.
+ * @param falseArg literal to represent false, "false" in VC 2005.
+ */
+ public VisualStudioNETProjectWriter(final String versionArg,
+ final String trueArg,
+ final String falseArg) {
+ if (versionArg == null) {
+ throw new IllegalArgumentException("versionArg");
+ }
+ if (trueArg == null) {
+ throw new IllegalArgumentException("trueArg");
+ }
+ if (falseArg == null) {
+ throw new IllegalArgumentException("falseArg");
+ }
+ this.version = versionArg;
+ this.trueLiteral = trueArg;
+ this.falseLiteral = falseArg;
+ }
+
+
+
+ /**
+ * Gets the configuration type.
+ *
+ * @param task cc task, may not be null.
+ * @return configuration type
+ */
+ private String getConfigurationType(final CCTask task) {
+ String outputType = task.getOuttype();
+ String targtype = "2"; // Win32 (x86) Dynamic-Link Library";
+ if ("executable".equals(outputType)) {
+ targtype = "1"; // "Win32 (x86) Console Application";
+ } else if ("static".equals(outputType)) {
+ targtype = "4"; //"Win32 (x86) Static Library";
+ }
+ return targtype;
+ }
+
+
+
+ /**
+ * Get character set for Windows API.
+ * @param compilerConfig compiler configuration, may not be null.
+ * @return "1" is TCHAR is unicode, "0" if TCHAR is multi-byte.
+ */
+ private String getCharacterSet(
+ final CommandLineCompilerConfiguration compilerConfig) {
+ String[] args = compilerConfig.getPreArguments();
+ String charset = "0";
+ for (int i = 0; i < args.length; i++) {
+ if ("/D_UNICODE".equals(args[i]) || "/DUNICODE".equals(args[i])) {
+ charset = "1";
+ }
+ if ("/D_MBCS".equals(args[i])) {
+ charset = "2";
+ }
+ }
+ return charset;
+ }
+
+ /**
+ * Write the start tag of the Configuration element.
+ * @param content serialization content handler.
+ * @param isDebug if true, write a debug configuration.
+ * @param task cc task.
+ * @param compilerConfig compiler configuration.
+ * @throws SAXException thrown if serialization error.
+ */
+ private void writeConfigurationStartTag(final ContentHandler content,
+ final boolean isDebug,
+ final CCTask task,
+ final CommandLineCompilerConfiguration compilerConfig)
+ throws SAXException {
+ AttributesImpl attributes = new AttributesImpl();
+ if (isDebug) {
+ addAttribute(attributes, "Name", "Debug|Win32");
+ addAttribute(attributes, "OutputDirectory", "Debug");
+ addAttribute(attributes, "IntermediateDirectory", "Debug");
+ } else {
+ addAttribute(attributes, "Name", "Release|Win32");
+ addAttribute(attributes, "OutputDirectory", "Release");
+ addAttribute(attributes, "IntermediateDirectory", "Release");
+
+ }
+ addAttribute(attributes, "ConfigurationType",
+ getConfigurationType(task));
+ addAttribute(attributes, "CharacterSet",
+ getCharacterSet(compilerConfig));
+ content.startElement(null,
+ "Configuration", "Configuration", attributes);
+ }
+
+ /**
+ * Get value of Optimization property.
+ * @param compilerConfig compiler configuration, may not be null.
+ * @return value of Optimization property.
+ */
+ private String getOptimization(
+ final CommandLineCompilerConfiguration compilerConfig) {
+ String[] args = compilerConfig.getPreArguments();
+ String opt = "0";
+ for (int i = 0; i < args.length; i++) {
+ if ("/Od".equals(args[i])) {
+ opt = "0";
+ }
+ if ("/O1".equals(args[i])) {
+ opt = "1";
+ }
+ if ("/O2".equals(args[i])) {
+ opt = "2";
+ }
+ if ("/Ox".equals(args[i])) {
+ opt = "3";
+ }
+ }
+ return opt;
+ }
+
+ /**
+ * Get value of AdditionalIncludeDirectories property.
+ * @param compilerConfig compiler configuration.
+ * @param baseDir base for relative paths.
+ * @return value of AdditionalIncludeDirectories property.
+ */
+ private String getAdditionalIncludeDirectories(
+ final String baseDir,
+ final CommandLineCompilerConfiguration compilerConfig) {
+ File[] includePath = compilerConfig.getIncludePath();
+ StringBuffer includeDirs = new StringBuffer();
+ for (int i = 0; i < includePath.length; i++) {
+ String relPath = CUtil.getRelativePath(baseDir, includePath[i]);
+ includeDirs.append(CUtil.toWindowsPath(relPath));
+ includeDirs.append(';');
+ }
+
+
+ if (includeDirs.length() > 0) {
+ includeDirs.setLength(includeDirs.length() - 1);
+ }
+ return includeDirs.toString();
+ }
+
+ /**
+ * Get value of PreprocessorDefinitions property.
+ * @param compilerConfig compiler configuration.
+ * @param isDebug true if generating debug configuration.
+ * @return value of PreprocessorDefinitions property.
+ */
+ private String getPreprocessorDefinitions(
+ final CommandLineCompilerConfiguration compilerConfig,
+ final boolean isDebug) {
+ StringBuffer defines = new StringBuffer();
+ String[] args = compilerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].startsWith("/D")) {
+ String macro = args[i].substring(2);
+ if (isDebug) {
+ if (macro.equals("NDEBUG")) {
+ macro = "_DEBUG";
+ }
+ } else {
+ if (macro.equals("_DEBUG")) {
+ macro = "NDEBUG";
+ }
+ }
+ defines.append(macro);
+ defines.append(";");
+ }
+ }
+
+ if (defines.length() > 0) {
+ defines.setLength(defines.length() - 1);
+ }
+ return defines.toString();
+ }
+
+ /**
+ * Get value of RuntimeLibrary property.
+ * @param compilerConfig compiler configuration.
+ * @param isDebug true if generating debug configuration.
+ * @return value of RuntimeLibrary property.
+ */
+ private String getRuntimeLibrary(
+ final CommandLineCompilerConfiguration compilerConfig,
+ final boolean isDebug) {
+ String rtl = null;
+ String[] args = compilerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].startsWith("/MT")) {
+ if (isDebug) {
+ rtl = "1";
+ } else {
+ rtl = "0";
+ }
+ } else if (args[i].startsWith("/MD")) {
+ if (isDebug) {
+ rtl = "3";
+ } else {
+ rtl = "2";
+ }
+ }
+ }
+ return rtl;
+ }
+
+ /**
+ * Get value of UsePrecompiledHeader property.
+ * @param compilerConfig compiler configuration.
+ * @return value of UsePrecompiledHeader property.
+ */
+ private String getUsePrecompiledHeader(
+ final CommandLineCompilerConfiguration compilerConfig) {
+ String usePCH = "0";
+ String[] args = compilerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if ("/Yc".equals(args[i])) {
+ usePCH = "1";
+ }
+ if ("/Yu".equals(args[i])) {
+ usePCH = "2";
+ }
+ }
+ return usePCH;
+ }
+
+ /**
+ * Get value of PrecompiledHeaderFile property.
+ * @param compilerConfig compiler configuration.
+ * @return value of PrecompiledHeaderFile property.
+ */
+ private String getPrecompiledHeaderFile(
+ final CommandLineCompilerConfiguration compilerConfig) {
+ String pch = null;
+ String[] args = compilerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].startsWith("/Fp")) {
+ pch = args[i].substring(3);
+ }
+ }
+ return pch;
+ }
+
+
+
+ /**
+ * Get value of BasicRuntimeChecks property.
+ * @param compilerConfig compiler configuration.
+ * @return value of BasicRuntimeChecks property.
+ */
+ private String getBasicRuntimeChecks(
+ final CommandLineCompilerConfiguration compilerConfig) {
+ String checks = "0";
+ String[] args = compilerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if ("/RTCs".equals(args[i])) {
+ checks = "1";
+ }
+ if ("/RTCu".equals(args[i])) {
+ checks = "2";
+ }
+ if ("/RTC1".equals(args[i]) || "/GZ".equals(args[i])) {
+ checks = "3";
+ }
+ }
+ return checks;
+ }
+
+ /**
+ * Get value of WarningLevel property.
+ * @param compilerConfig compiler configuration.
+ * @return value of WarningLevel property.
+ */
+ private String getWarningLevel(
+ final CommandLineCompilerConfiguration compilerConfig) {
+ String warn = null;
+ String[] args = compilerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if ("/W0".equals(args[i])) {
+ warn = "0";
+ }
+ if ("/W1".equals(args[i])) {
+ warn = "1";
+ }
+ if ("/W2".equals(args[i])) {
+ warn = "2";
+ }
+ if ("/W3".equals(args[i])) {
+ warn = "3";
+ }
+ }
+ return warn;
+ }
+
+ /**
+ * Get value of Detect64BitPortabilityProblems property.
+ * @param compilerConfig compiler configuration.
+ * @return value of Detect64BitPortabilityProblems property.
+ */
+ private String getDetect64BitPortabilityProblems(
+ final CommandLineCompilerConfiguration compilerConfig) {
+ String warn64 = null;
+ String[] args = compilerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if ("/Wp64".equals(args[i])) {
+ warn64 = trueLiteral;
+ }
+ }
+ return warn64;
+ }
+
+ /**
+ * Get value of DebugInformationFormat property.
+ * @param compilerConfig compiler configuration.
+ * @return value of DebugInformationFormat property.
+ */
+ private String getDebugInformationFormat(
+ final CommandLineCompilerConfiguration compilerConfig) {
+ String format = "0";
+ String[] args = compilerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if ("/Z7".equals(args[i])) {
+ format = "1";
+ }
+ if ("/Zd".equals(args[i])) {
+ format = "2";
+ }
+ if ("/Zi".equals(args[i])) {
+ format = "3";
+ }
+ if ("/ZI".equals(args[i])) {
+ format = "4";
+ }
+ }
+ return format;
+ }
+
+ /**
+ * write the Compiler element.
+ * @param content serialization content handler.
+ * @param isDebug true if generating debug configuration.
+ * @param basePath base for relative file paths.
+ * @param compilerConfig compiler configuration.
+ * @throws SAXException thrown if error during serialization.
+ */
+ private void writeCompilerElement(final ContentHandler content,
+ final boolean isDebug,
+ final String basePath,
+ final CommandLineCompilerConfiguration compilerConfig)
+ throws SAXException {
+ AttributesImpl attributes = new AttributesImpl();
+ addAttribute(attributes, "Name", "VCCLCompilerTool");
+ String optimization = getOptimization(compilerConfig);
+ String debugFormat = getDebugInformationFormat(compilerConfig);
+ if(isDebug) {
+ optimization = "0";
+ if ("0".equals(debugFormat)) {
+ debugFormat = "4";
+ }
+ } else {
+ if ("0".equals(optimization)) {
+ optimization = "2";
+ }
+ debugFormat = "0";
+ }
+ addAttribute(attributes, "Optimization", optimization);
+ addAttribute(attributes, "AdditionalIncludeDirectories",
+ getAdditionalIncludeDirectories(basePath, compilerConfig));
+ addAttribute(attributes, "PreprocessorDefinitions",
+ getPreprocessorDefinitions(compilerConfig, isDebug));
+ addAttribute(attributes, "MinimalRebuild", trueLiteral);
+ addAttribute(attributes, "BasicRuntimeChecks",
+ getBasicRuntimeChecks(compilerConfig));
+ addAttribute(attributes, "RuntimeLibrary",
+ getRuntimeLibrary(compilerConfig, isDebug));
+ addAttribute(attributes, "UsePrecompiledHeader",
+ getUsePrecompiledHeader(compilerConfig));
+ addAttribute(attributes, "PrecompiledHeaderFile",
+ getPrecompiledHeaderFile(compilerConfig));
+ addAttribute(attributes, "WarningLevel",
+ getWarningLevel(compilerConfig));
+ addAttribute(attributes, "Detect64BitPortabilityProblems",
+ getDetect64BitPortabilityProblems(compilerConfig));
+ addAttribute(attributes, "DebugInformationFormat",
+ debugFormat);
+ content.startElement(null, "Tool", "Tool", attributes);
+ content.endElement(null, "Tool", "Tool");
+
+ }
+
+
+ /**
+ * Get value of LinkIncremental property.
+ * @param linkerConfig linker configuration.
+ * @return value of LinkIncremental property
+ */
+ private String getLinkIncremental(
+ final CommandLineLinkerConfiguration linkerConfig) {
+ String incremental = "0";
+ String[] args = linkerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if ("/INCREMENTAL:NO".equals(args[i])) {
+ incremental = "1";
+ }
+ if ("/INCREMENTAL:YES".equals(args[i])) {
+ incremental = "2";
+ }
+ }
+ return incremental;
+ }
+
+
+ /**
+ * Get value of Subsystem property.
+ * @param linkerConfig linker configuration.
+ * @return value of Subsystem property
+ */
+ private String getSubsystem(
+ final CommandLineLinkerConfiguration linkerConfig) {
+ String subsystem = "0";
+ String[] args = linkerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if ("/SUBSYSTEM:CONSOLE".equals(args[i])) {
+ subsystem = "1";
+ }
+ if ("/SUBSYSTEM:WINDOWS".equals(args[i])) {
+ subsystem = "2";
+ }
+ if ("/SUBSYSTEM:WINDOWSCE".equals(args[i])) {
+ subsystem = "9";
+ }
+ }
+ return subsystem;
+ }
+
+ /**
+ * Get value of TargetMachine property.
+ * @param linkerConfig linker configuration.
+ * @return value of TargetMachine property
+ */
+ private String getTargetMachine(
+ final CommandLineLinkerConfiguration linkerConfig) {
+ String subsystem = "0";
+ String[] args = linkerConfig.getPreArguments();
+ for (int i = 0; i < args.length; i++) {
+ if ("/MACHINE:X86".equals(args[i])) {
+ subsystem = "1";
+ }
+ }
+ return subsystem;
+ }
+
+ /**
+ * Get value of AdditionalDependencies property.
+ * @param linkTarget link target.
+ * @param projectDependencies dependencies declared in project.
+ * @param targets all targets.
+ * @param basePath path to directory containing project file.
+ * @return value of AdditionalDependencies property.
+ */
+ private String getAdditionalDependencies(final TargetInfo linkTarget,
+ final List projectDependencies,
+ final Map targets,
+ final String basePath) {
+ String dependencies = null;
+ File[] linkSources = linkTarget.getAllSources();
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < linkSources.length; i++) {
+ //
+ // if file was not compiled or otherwise generated
+ //
+ if (targets.get(linkSources[i].getName()) == null) {
+ //
+ // if source appears to be a system library or object file
+ // just output the name of the file (advapi.lib for example)
+ // otherwise construct a relative path.
+ //
+ String relPath = linkSources[i].getName();
+ //
+ // check if file comes from a project dependency
+ // if it does it should not be explicitly linked
+ boolean fromDependency = false;
+ if (relPath.indexOf(".") > 0) {
+ String baseName = relPath.substring(0, relPath.indexOf("."));
+ for(Iterator iter = projectDependencies.iterator(); iter.hasNext(); ) {
+ DependencyDef depend = (DependencyDef) iter.next();
+ if (baseName.compareToIgnoreCase(depend.getName()) == 0) {
+ fromDependency = true;
+ }
+ }
+ }
+
+ if (!fromDependency) {
+ if (!CUtil.isSystemPath(linkSources[i])) {
+ relPath = CUtil.getRelativePath(basePath, linkSources[i]);
+ }
+ //
+ // if path has an embedded space then
+ // must quote
+ if (relPath.indexOf(' ') > 0) {
+ buf.append('\"');
+ buf.append(CUtil.toWindowsPath(relPath));
+ buf.append('\"');
+ } else {
+ buf.append(relPath);
+ }
+ buf.append(' ');
+ }
+ }
+ }
+ if (buf.length() > 0) {
+ buf.setLength(buf.length() - 1);
+ dependencies = buf.toString();
+ }
+ return dependencies;
+
+ }
+
+ /**
+ * Write Tool element for linker.
+ * @param content serialization content handler.
+ * @param isDebug true if generating debug configuration.
+ * @param dependencies project dependencies.
+ * @param basePath path to directory containing project file.
+ * @param linkTarget link target.
+ * @param targets all targets.
+ * @throws SAXException thrown if error during serialization.
+ */
+ private void writeLinkerElement(final ContentHandler content,
+ final boolean isDebug,
+ final List dependencies,
+ final String basePath,
+ final TargetInfo linkTarget,
+ final Map targets) throws SAXException {
+ AttributesImpl attributes = new AttributesImpl();
+ addAttribute(attributes, "Name", "VCLinkerTool");
+
+ ProcessorConfiguration config = linkTarget.getConfiguration();
+ if (config instanceof CommandLineLinkerConfiguration) {
+ CommandLineLinkerConfiguration linkerConfig =
+ (CommandLineLinkerConfiguration) config;
+ if (linkerConfig.getLinker() instanceof DevStudioCompatibleLinker) {
+ addAttribute(attributes, "LinkIncremental",
+ getLinkIncremental(linkerConfig));
+ if (isDebug) {
+ addAttribute(attributes, "GenerateDebugInformation", trueLiteral);
+ } else {
+ addAttribute(attributes, "GenerateDebugInformation", falseLiteral);
+ }
+ addAttribute(attributes, "SubSystem",
+ getSubsystem(linkerConfig));
+ addAttribute(attributes, "TargetMachine",
+ getTargetMachine(linkerConfig));
+ }
+ }
+ addAttribute(attributes, "AdditionalDependencies",
+ getAdditionalDependencies(linkTarget, dependencies, targets, basePath));
+ content.startElement(null, "Tool", "Tool", attributes);
+ content.endElement(null, "Tool", "Tool");
+ }
+
+ /**
+ * Writes a project definition file.
+ *
+ * @param fileName project name for file, should has .cbx extension
+ * @param task cc task for which to write project
+ * @param projectDef project element
+ * @param sources source files
+ * @param targets compilation targets
+ * @param linkTarget link target
+ * @throws IOException if I/O error
+ * @throws SAXException if XML serialization error
+ */
+ public void writeProject(final File fileName,
+ final CCTask task,
+ final ProjectDef projectDef,
+ final List sources,
+ final Hashtable targets,
+ final TargetInfo linkTarget) throws
+ IOException,
+ SAXException {
+
+ String projectName = projectDef.getName();
+ if (projectName == null) {
+ projectName = fileName.getName();
+ }
+
+
+ File vcprojFile = new File(fileName + ".vcproj");
+ if (!projectDef.getOverwrite() && vcprojFile.exists()) {
+ throw new BuildException("Not allowed to overwrite project file "
+ + vcprojFile.toString());
+ }
+ File slnFile = new File(fileName + ".sln");
+ if (!projectDef.getOverwrite() && slnFile.exists()) {
+ throw new BuildException("Not allowed to overwrite project file "
+ + slnFile.toString());
+ }
+
+ CommandLineCompilerConfiguration compilerConfig =
+ getBaseCompilerConfiguration(targets);
+ if (compilerConfig == null) {
+ throw new BuildException(
+ "Unable to generate Visual Studio.NET project "
+ + "when Microsoft C++ is not used.");
+ }
+
+ OutputStream outStream = new FileOutputStream(fileName + ".vcproj");
+ OutputFormat format = new OutputFormat("xml", "UTF-8", true);
+ XMLSerializer serializer = new XMLSerializer(outStream, format);
+ ContentHandler content = serializer.asContentHandler();
+ String basePath = fileName.getParentFile().getAbsolutePath();
+ content.startDocument();
+
+ for(Iterator iter = projectDef.getComments().iterator(); iter.hasNext(); ) {
+ String comment = ((CommentDef) iter.next()).getText();
+ serializer.comment(comment);
+ }
+
+ AttributesImpl emptyAttrs = new AttributesImpl();
+
+ AttributesImpl attributes = new AttributesImpl();
+ addAttribute(attributes, "ProjectType", "Visual C++");
+ addAttribute(attributes, "Version", version);
+ addAttribute(attributes, "Name", projectName);
+ content.startElement(null, "VisualStudioProject",
+ "VisualStudioProject", attributes);
+
+ content.startElement(null, "Platforms", "Platforms", emptyAttrs);
+ attributes.clear();
+ addAttribute(attributes, "Name", "Win32");
+ content.startElement(null, "Platform", "Platform", attributes);
+ content.endElement(null, "Platform", "Platform");
+ content.endElement(null, "Platforms", "Platforms");
+ content.startElement(null, "Configurations",
+ "Configurations", emptyAttrs);
+
+ //
+ // write debug configuration
+ //
+ writeConfigurationStartTag(content, true, task, compilerConfig);
+ writeCompilerElement(content, true, basePath, compilerConfig);
+ writeLinkerElement(content, true, projectDef.getDependencies(), basePath, linkTarget, targets);
+ content.endElement(null, "Configuration", "Configuration");
+
+ //
+ // write release configuration
+ //
+ writeConfigurationStartTag(content, false, task, compilerConfig);
+ writeCompilerElement(content, false, basePath, compilerConfig);
+ writeLinkerElement(content, false, projectDef.getDependencies(), basePath, linkTarget, targets);
+ content.endElement(null, "Configuration", "Configuration");
+
+ content.endElement(null, "Configurations", "Configurations");
+ content.startElement(null, "References", "References", emptyAttrs);
+ content.endElement(null, "References", "References");
+ content.startElement(null, "Files", "Files", emptyAttrs);
+
+
+ File[] sortedSources = new File[sources.size()];
+ sources.toArray(sortedSources);
+ Arrays.sort(sortedSources, new Comparator() {
+ public int compare(final Object o1, final Object o2) {
+ return ((File) o1).getName().compareTo(((File) o2).getName());
+ }
+ });
+
+ writeFilteredSources("Source Files",
+ "cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx",
+ basePath, sortedSources, content);
+
+ writeFilteredSources("Header Files", "h;hpp;hxx;hm;inl;inc;xsd",
+ basePath, sortedSources, content);
+
+ writeFilteredSources("Resource Files",
+ "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx",
+ basePath, sortedSources, content);
+
+ content.endElement(null, "Files", "Files");
+ content.startElement(null, "Globals", "Globals", emptyAttrs);
+ content.endElement(null, "Globals", "Globals");
+ content.endElement(null, "VisualStudioProject", "VisualStudioProject");
+ content.endDocument();
+ }
+
+ /**
+ * Writes a cluster of source files to the project.
+ *
+ * @param name name of filter
+ * @param filter file extensions
+ * @param basePath base path for files
+ * @param sortedSources array of source files
+ * @param content generated project
+ * @throws SAXException if invalid content
+ */
+ private void writeFilteredSources(final String name, final String filter,
+ final String basePath,
+ final File[] sortedSources,
+ final ContentHandler content)
+ throws SAXException {
+ AttributesImpl filterAttrs = new AttributesImpl();
+ filterAttrs.addAttribute(null, "Name", "Name", "#PCDATA", name);
+ filterAttrs.addAttribute(null, "Filter", "Filter", "#PCDATA", filter);
+ content.startElement(null, "Filter", "Filter", filterAttrs);
+
+
+ AttributesImpl fileAttrs = new AttributesImpl();
+ fileAttrs.addAttribute(null, "RelativePath", "RelativePath",
+ "#PCDATA", "");
+
+
+ for (int i = 0; i < sortedSources.length; i++) {
+ if (isGroupMember(filter, sortedSources[i])) {
+ String relativePath = CUtil.getRelativePath(basePath,
+ sortedSources[i]);
+ fileAttrs.setValue(0, relativePath);
+ content.startElement(null, "File", "File", fileAttrs);
+ content.endElement(null, "File", "File");
+ }
+ }
+ content.endElement(null, "Filter", "Filter");
+
+ }
+
+ /**
+ * Returns true if the file has an extension that
+ * appears in the group filter.
+ *
+ * @param filter String group filter
+ * @param candidate File file
+ * @return boolean true if member of group
+ */
+ private boolean isGroupMember(final String filter, final File candidate) {
+ String fileName = candidate.getName();
+ int lastDot = fileName.lastIndexOf('.');
+ if (lastDot >= 0 && lastDot < fileName.length() - 1) {
+ String extension =
+ ";" + fileName.substring(lastDot + 1).toLowerCase() + ";";
+ String semiFilter = ";" + filter + ";";
+ return semiFilter.indexOf(extension) >= 0;
+ }
+ return false;
+ }
+
+
+ /**
+ * Adds an non-namespace-qualified attribute to attribute list.
+ * @param attributes list of attributes.
+ * @param attrName attribute name, may not be null.
+ * @param attrValue attribute value, if null attribute is not added.
+ */
+ private static void addAttribute(final AttributesImpl attributes,
+ final String attrName,
+ final String attrValue) {
+ if (attrName == null) {
+ throw new IllegalArgumentException("attrName");
+ }
+ if (attrValue != null) {
+ attributes.addAttribute(null, attrName, attrName,
+ "#PCDATA", attrValue);
+ }
+ }
+
+ /**
+ * Gets the first recognized compiler from the
+ * compilation targets.
+ * @param targets compilation targets
+ * @return representative (hopefully) compiler configuration
+ */
+ private CommandLineCompilerConfiguration
+ getBaseCompilerConfiguration(final Hashtable targets) {
+ //
+ // get the first target and assume that it is representative
+ //
+ Iterator targetIter = targets.values().iterator();
+ while (targetIter.hasNext()) {
+ TargetInfo targetInfo = (TargetInfo) targetIter.next();
+ ProcessorConfiguration config = targetInfo.getConfiguration();
+ //
+ // for the first cl compiler
+ //
+ if (config instanceof CommandLineCompilerConfiguration) {
+ CommandLineCompilerConfiguration compilerConfig =
+ (CommandLineCompilerConfiguration) config;
+ if (compilerConfig.getCompiler()
+ instanceof DevStudioCCompiler) {
+ return compilerConfig;
+ }
+ }
+ }
+ return null;
+ }
+}
+