From fa8a6279d26c357a502f067b94f57a3614954a34 Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Thu, 4 Nov 2021 14:10:21 -0400 Subject: [PATCH] Bug 577074: Fix i18n on import/export language settings Side effect is that the indentation in the transformer now works properly, so the extra newlines inserted everywhere can be removed. This change was done by changing the output to an OutputStream instead of a Writer so that the XML handler could set the encoding to match what was in the settings, i.e.: transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); The non-translated language IDs are used in preference to the translated names when importing. The export now puts that ID (when available) in the output file. The ID is available on normal user files (C, ASM, C++) and not on object files. The object files probably don't have languages settings that are exported, but this code does not exclude them from being exported. Change-Id: I46de004bb8c6a0ca05210487a5d33390d397c720 --- .../SettingsImportExportTest.java | 5 ++- .../IncludePathsSettingsProcessor.java | 1 - .../MacroSettingsProcessor.java | 3 -- .../ProjectSettingsExportStrategy.java | 35 ++++++------------- .../settingswizards/SettingsProcessor.java | 26 +++++++------- 5 files changed, 28 insertions(+), 42 deletions(-) diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/wizards/settingswizards/SettingsImportExportTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/wizards/settingswizards/SettingsImportExportTest.java index 98ac5c52884..37b899de98f 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/wizards/settingswizards/SettingsImportExportTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/wizards/settingswizards/SettingsImportExportTest.java @@ -48,7 +48,10 @@ public class SettingsImportExportTest extends BaseUITestCase { new CMacroEntry("smac", "blah", 0) }; private static ICLanguageSettingEntry[] EXPORTED_INCLUDES = new ICLanguageSettingEntry[] { - new CIncludePathEntry("/path/to/somewhere", 0), new CIncludePathEntry("/blah/blah/blah", 0), + // There is a multi-byte character at the end of this first string. When this test + // was run without the fix for Bug 577074 and -Dfile.encoding that would cause the + // character to be corrupted (e.g. windows-1252) + new CIncludePathEntry("/path/to/somewhere¢", 0), new CIncludePathEntry("/blah/blah/blah", 0), new CIncludePathEntry("pantera/is/awesome", 0) }; public SettingsImportExportTest() { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/IncludePathsSettingsProcessor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/IncludePathsSettingsProcessor.java index 1df9bd7106e..1c3e926e6e9 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/IncludePathsSettingsProcessor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/IncludePathsSettingsProcessor.java @@ -76,7 +76,6 @@ public class IncludePathsSettingsProcessor extends SettingsProcessor { content.startElement(NONE, NONE, INCLUDE_PATH_ELEMENT, attrib); content.characters(value, 0, value.length); content.endElement(NONE, NONE, INCLUDE_PATH_ELEMENT); - newline(content); } catch (SAXException e) { throw new SettingsImportExportException(e); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/MacroSettingsProcessor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/MacroSettingsProcessor.java index 5dd69f82ab8..3b799b48197 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/MacroSettingsProcessor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/MacroSettingsProcessor.java @@ -74,7 +74,6 @@ public class MacroSettingsProcessor extends SettingsProcessor { try { content.startElement(NONE, NONE, MACRO_ELEMENT, null); - newline(content); content.startElement(NONE, NONE, NAME_ELEMENT, null); content.characters(name, 0, name.length); @@ -83,10 +82,8 @@ public class MacroSettingsProcessor extends SettingsProcessor { content.startElement(NONE, NONE, VALUE_ELEMENT, null); content.characters(value, 0, value.length); content.endElement(NONE, NONE, VALUE_ELEMENT); - newline(content); content.endElement(NONE, NONE, MACRO_ELEMENT); - newline(content); } catch (SAXException e) { throw new SettingsImportExportException(e); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/ProjectSettingsExportStrategy.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/ProjectSettingsExportStrategy.java index ebecc5c3d45..72f9fde5d06 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/ProjectSettingsExportStrategy.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/ProjectSettingsExportStrategy.java @@ -13,9 +13,8 @@ *******************************************************************************/ package org.eclipse.cdt.internal.ui.wizards.settingswizards; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; -import java.io.Writer; import java.net.URI; import java.util.List; @@ -34,7 +33,6 @@ import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; -import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; @@ -82,12 +80,12 @@ public class ProjectSettingsExportStrategy implements IProjectSettingsWizardPage // do nothing } - private Writer getWriter(IProjectSettingsWizardPage page) throws IOException { + private FileOutputStream getFileOutputStream(IProjectSettingsWizardPage page) throws IOException { IPath path = new Path(page.getDestinationFilePath()); if (!IProjectSettingsWizardPage.FILENAME_EXTENSION.equals(path.getFileExtension())) path.addFileExtension(IProjectSettingsWizardPage.FILENAME_EXTENSION); - return new FileWriter(path.toFile()); + return new FileOutputStream(path.toFile()); } /** @@ -107,22 +105,24 @@ public class ProjectSettingsExportStrategy implements IProjectSettingsWizardPage } // gets a writer for the file that was selected by the user - Writer writer; + FileOutputStream outputStream; try { - writer = getWriter(page); + outputStream = getFileOutputStream(page); } catch (IOException e) { page.showErrorDialog(Messages.ProjectSettingsExportStrategy_fileOpenError, Messages.ProjectSettingsExportStrategy_couldNotOpen); return false; } - // stream the results to the writer as text - handler.setResult(new StreamResult(writer)); - // write out the XML header Transformer transformer = handler.getTransformer(); - transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); //$NON-NLS-1$ //$NON-NLS-2$ + transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes"); //$NON-NLS-1$ + + // stream the results to the writer as text + handler.setResult(new StreamResult(outputStream)); List exporters = page.getSelectedSettingsProcessors(); @@ -134,27 +134,21 @@ public class ProjectSettingsExportStrategy implements IProjectSettingsWizardPage AttributesImpl attributes = new AttributesImpl(); handler.startDocument(); - newline(handler); handler.startElement(NONE, NONE, ROOT_ELEMENT, null); - newline(handler); for (ISettingsProcessor exporter : exporters) { attributes.clear(); attributes.addAttribute(NONE, NONE, SECTION_NAME_ATTRIBUTE, CDATA, exporter.getSectionName()); handler.startElement(NONE, NONE, SECTION_ELEMENT, attributes); - newline(handler); // each exporter is responsible for writing out its own section of the file exporter.writeSectionXML(projectRoot, handler); handler.endElement(NONE, NONE, SECTION_ELEMENT); - newline(handler); } handler.endElement(NONE, NONE, ROOT_ELEMENT); - newline(handler); handler.endDocument(); - newline(handler); result = true; } catch (SAXException e) { @@ -175,11 +169,4 @@ public class ProjectSettingsExportStrategy implements IProjectSettingsWizardPage return result; } - /** - * Outputs a newline (\n) to the given ContentHandler. - */ - private static void newline(ContentHandler handler) throws SAXException { - handler.ignorableWhitespace("\n".toCharArray(), 0, 1); //$NON-NLS-1$ - } - } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/SettingsProcessor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/SettingsProcessor.java index 0ce07081dea..3dfb4119226 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/SettingsProcessor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/settingswizards/SettingsProcessor.java @@ -37,6 +37,7 @@ public abstract class SettingsProcessor implements ISettingsProcessor { protected static final String NONE = ""; //$NON-NLS-1$ protected static final String CDATA = "CDATA"; //$NON-NLS-1$ + protected static final String ID_ATTRIBUTE = "id"; //$NON-NLS-1$ protected static final String NAME_ATTRIBUTE = "name"; //$NON-NLS-1$ protected static final String LANGUAGE_ELEMENT = "language"; //$NON-NLS-1$ @@ -51,13 +52,6 @@ public abstract class SettingsProcessor implements ISettingsProcessor { protected abstract void readSettings(ICLanguageSetting setting, Element language) throws SettingsImportExportException; - /** - * Outputs a newline (\n) to the given ContentHandler. - */ - protected static void newline(ContentHandler handler) throws SAXException { - handler.ignorableWhitespace("\n".toCharArray(), 0, 1); //$NON-NLS-1$ - } - @Override public void writeSectionXML(ICFolderDescription projectRoot, ContentHandler content) throws SettingsImportExportException { @@ -66,12 +60,14 @@ public abstract class SettingsProcessor implements ISettingsProcessor { try { for (ICLanguageSetting language : languages) { - //TODO for some reason language.getLanguageId() is returning null + String languageId = language.getLanguageId(); String languageName = language.getName(); attributes.clear(); + if (languageId != null) { + attributes.addAttribute(NONE, NONE, ID_ATTRIBUTE, CDATA, languageId); + } attributes.addAttribute(NONE, NONE, NAME_ATTRIBUTE, CDATA, languageName); content.startElement(NONE, NONE, LANGUAGE_ELEMENT, attributes); - newline(content); ICLanguageSettingEntry[] settings = language.getSettingEntries(getSettingsType()); @@ -81,9 +77,7 @@ public abstract class SettingsProcessor implements ISettingsProcessor { } } - newline(content); content.endElement(NONE, NONE, LANGUAGE_ELEMENT); - newline(content); } } catch (SAXException e) { @@ -95,15 +89,21 @@ public abstract class SettingsProcessor implements ISettingsProcessor { public void readSectionXML(ICFolderDescription projectRoot, Element section) throws SettingsImportExportException { ICLanguageSetting[] languageSettings = projectRoot.getLanguageSettings(); + Map languageIdMap = new HashMap<>(); Map languageMap = new HashMap<>(); for (ICLanguageSetting language : languageSettings) { + languageIdMap.put(language.getLanguageId(), language); languageMap.put(language.getName(), language); } List elements = XMLUtils.extractChildElements(section, LANGUAGE_ELEMENT); // throws SettingsImportExportException for (Element languageElement : elements) { - String languageName = languageElement.getAttribute(NAME_ATTRIBUTE); - ICLanguageSetting setting = languageMap.get(languageName); + String languageId = languageElement.getAttribute(ID_ATTRIBUTE); + ICLanguageSetting setting = languageIdMap.get(languageId); + if (setting == null) { + String languageName = languageElement.getAttribute(NAME_ATTRIBUTE); + setting = languageMap.get(languageName); + } if (setting != null) readSettings(setting, languageElement); }