diff options
Diffstat (limited to 'bundles/org.eclipse.wst.sse.core/src-encoding/org/eclipse/wst/sse/core/internal/encoding/CodedReaderCreator.java')
-rw-r--r-- | bundles/org.eclipse.wst.sse.core/src-encoding/org/eclipse/wst/sse/core/internal/encoding/CodedReaderCreator.java | 542 |
1 files changed, 0 insertions, 542 deletions
diff --git a/bundles/org.eclipse.wst.sse.core/src-encoding/org/eclipse/wst/sse/core/internal/encoding/CodedReaderCreator.java b/bundles/org.eclipse.wst.sse.core/src-encoding/org/eclipse/wst/sse/core/internal/encoding/CodedReaderCreator.java deleted file mode 100644 index 155ccdb55f..0000000000 --- a/bundles/org.eclipse.wst.sse.core/src-encoding/org/eclipse/wst/sse/core/internal/encoding/CodedReaderCreator.java +++ /dev/null @@ -1,542 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001, 2008 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.sse.core.internal.encoding; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CodingErrorAction; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.content.IContentDescription; -import org.eclipse.core.runtime.content.IContentTypeManager; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.wst.sse.core.internal.SSECoreMessages; -import org.eclipse.wst.sse.core.internal.encoding.util.Assert; -import org.eclipse.wst.sse.core.internal.encoding.util.BufferedLimitedStream; -import org.eclipse.wst.sse.core.internal.encoding.util.Logger; -import org.eclipse.wst.sse.core.internal.encoding.util.NullInputStream; -import org.eclipse.wst.sse.core.internal.encoding.util.UnicodeBOMEncodingDetector; -import org.eclipse.wst.sse.core.internal.exceptions.UnsupportedCharsetExceptionWithDetail; - - -/** - * The purpose of this class is to centralize analysis of a file to determine - * the most appropriate rules of decoding it. The intended use is to set the - * input, then get the reader for that input which will have its encoding set - * appropriately. Additionally, there is an EncodingMemento provided, which - * will be required, in some cases, to later determine the most appropriate - * form of encoded output. - */ -public class CodedReaderCreator extends CodedIO { - - - private boolean fClientSuppliedStream; - - - private EncodingMemento fEncodingMemento; - - private EncodingRule fEncodingRule; - - private String fFilename; - - private IFile fIFile; - - - private InputStream fInputStream; - - private static final String CHARSET_UTF_16= "UTF-16"; //$NON-NLS-1$ - - private static final String CHARSET_UTF_16LE= "UTF-16LE"; //$NON-NLS-1$ - - public CodedReaderCreator() { - - super(); - } - - public CodedReaderCreator(IFile file) throws CoreException, IOException { - - this(); - set(file); - setEncodingRule(EncodingRule.CONTENT_BASED); - } - - public CodedReaderCreator(IFile file, EncodingRule encodingRule) throws CoreException, IOException { - - this(); - set(file); - setEncodingRule(encodingRule); - } - - public CodedReaderCreator(String filename, InputStream inputStream) { - - this(); - set(filename, inputStream); - setEncodingRule(EncodingRule.CONTENT_BASED); - } - - public CodedReaderCreator(String filename, InputStream inputStream, EncodingRule encodingRule) { - - this(); - set(filename, inputStream); - setEncodingRule(encodingRule); - } - - private EncodingMemento checkForEncodingInContents(InputStream limitedStream) throws CoreException, IOException { - EncodingMemento result = null; - - // if encoding memento already set, then iFile must - // have been set, and no need to get again. - if (fEncodingMemento != null) { - result = fEncodingMemento; - } - else { - if (fClientSuppliedStream) { - try { - limitedStream.reset(); - IContentTypeManager contentTypeManager = Platform.getContentTypeManager(); - IContentDescription contentDescription = contentTypeManager.getDescriptionFor(limitedStream, fFilename, IContentDescription.ALL); - if (contentDescription != null) { - fEncodingMemento = createMemento(contentDescription); - } - result = fEncodingMemento; - } - finally { - limitedStream.reset(); - } - } - else { - // throw new IllegalStateException("unexpected state: - // encodingMemento was null but no input stream supplied by - // client"); //$NON-NLS-1$ - result = null; - } - } - - if (result != null && !result.isValid() && !forceDefault()) { - throw new UnsupportedCharsetExceptionWithDetail(result); - } - - return result; - } - - /** - * @param resettableLimitedStream - */ - private EncodingMemento checkStreamForBOM(InputStream resettableLimitedStream) { - EncodingMemento result = null; - UnicodeBOMEncodingDetector unicodeBOMEncodingDetector = new UnicodeBOMEncodingDetector(); - unicodeBOMEncodingDetector.set(resettableLimitedStream); - result = unicodeBOMEncodingDetector.getEncodingMemento(); - return result; - } - - /** - * @param iFile - * @throws CoreException - * @throws IOException - */ - private EncodingMemento findMementoFromFileCase() throws CoreException, IOException { - EncodingMemento result = null; - IContentDescription contentDescription = null; - try { - // This method provides possible improved performance at the - // cost of sometimes returning null - if (fIFile.exists()) - contentDescription = fIFile.getContentDescription(); - } - catch (CoreException e) { - // Assume if core exception occurs, we can still try more - // expensive - // discovery options. - Logger.logException(e); - } - if (contentDescription == null && fIFile.isAccessible()) { - InputStream contents = null; - try { - contents = fIFile.getContents(); - contentDescription = Platform.getContentTypeManager().getDescriptionFor(contents, fIFile.getName(), IContentDescription.ALL); - } - catch (CoreException e1) { - // Assume if core exception occurs, we can't really do much - // with - // determining encoding, etc. - Logger.logException(e1); - throw e1; - } - catch (IOException e2) { - // We likely couldn't get the contents of the file, something - // is really wrong - Logger.logException(e2); - throw e2; - } - if (contents != null) { - try { - contents.close(); - } - catch (IOException e2) { - Logger.logException(e2); - } - } - } - if (contentDescription != null) { - result = createMemento(contentDescription); - } - - return result; - } - - /** - * The primary method which contains the highest level rules for how to - * decide appropriate decoding rules: 1. first check for unicode stream 2. - * then looked for encoding specified in content (according to the type of - * content that is it ... xml, html, jsp, etc. 3. then check for various - * settings: file settings first, if null check project settings, if null, - * check user preferences. 4. lastly (or, what is the last user - * preference) is to use "workbench defaults". - * - * @throws IOException - * @throws CoreException - */ - private EncodingMemento findMementoFromStreamCase() throws CoreException, IOException { - - EncodingMemento result = null; - InputStream resettableLimitedStream = null; - try { - resettableLimitedStream = getLimitedStream(getResettableStream()); - if (resettableLimitedStream != null) { - // first check for unicode stream - result = checkStreamForBOM(resettableLimitedStream); - // if not that, then check contents - if (result == null) { - resettableLimitedStream.reset(); - result = checkForEncodingInContents(resettableLimitedStream); - } - - } - else { - // stream null, may name's not. - if (fFilename != null) { - // filename not null - IContentTypeManager contentTypeManager = Platform.getContentTypeManager(); - IContentDescription contentDescription = contentTypeManager.getDescriptionFor(new NullInputStream(), fFilename, IContentDescription.ALL); - if (contentDescription != null) { - result = createMemento(contentDescription); - } - } - } - } - finally { - if (resettableLimitedStream != null) { - handleStreamClose(resettableLimitedStream); - } - } - return result; - } - - private boolean forceDefault() { - - boolean result = false; - if (fEncodingRule != null && fEncodingRule == EncodingRule.FORCE_DEFAULT) - result = true; - return result; - } - - public Reader getCodedReader() throws CoreException, IOException { - - Reader result = null; - // we make a local copy of encoding memento so - // stream won't - // be accessed simultaneously. - EncodingMemento encodingMemento = getEncodingMemento(); - Assert.isNotNull(encodingMemento, "Appears reader requested before file or stream set"); //$NON-NLS-1$ - InputStream streamToReturn = getResettableStream(); - streamToReturn.reset(); - // if UTF 3 byte BOM is used (or UTF-16LE), the - // built in converters - // don't - // correct skip all three bytes ... so skip - // remaining one to leave - // stream transparently ready for client. - // see ... TODO look up bug number - if (encodingMemento.isUnicodeStream()) { - streamToReturn.skip(2); - } - else if (encodingMemento.isUTF83ByteBOMUsed()) { - streamToReturn.skip(3); - } - String charsetName = encodingMemento.getJavaCharsetName(); - if (charsetName == null) { - charsetName = encodingMemento.getDetectedCharsetName(); - } - if (!encodingMemento.isValid() && !forceDefault()) { - throw new UnsupportedCharsetExceptionWithDetail(encodingMemento); - } - - if (fEncodingRule == EncodingRule.FORCE_DEFAULT) { - charsetName = encodingMemento.getAppropriateDefault(); - } - - // [228366] For files that have a unicode BOM, and a charset name of UTF-16, the charset decoder needs "UTF-16LE" - if(CHARSET_UTF_16.equals(charsetName) && encodingMemento.getUnicodeBOM() == IContentDescription.BOM_UTF_16LE) - charsetName = CHARSET_UTF_16LE; - - Charset charset = Charset.forName(charsetName); - CharsetDecoder charsetDecoder = charset.newDecoder(); - if (fEncodingRule == EncodingRule.IGNORE_CONVERSION_ERROR) { - charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE); - charsetDecoder.onUnmappableCharacter(CodingErrorAction.REPLACE); - } - else { - charsetDecoder.onMalformedInput(CodingErrorAction.REPORT); - charsetDecoder.onUnmappableCharacter(CodingErrorAction.REPORT); - } - // more efficient to be buffered, and I know of no - // reason not to return - // that directly. - result = new BufferedReader(new InputStreamReader(streamToReturn, charsetDecoder), CodedIO.MAX_BUF_SIZE); - result.mark(CodedIO.MAX_BUF_SIZE); - return result; - } - - public EncodingMemento getEncodingMemento() throws CoreException, IOException { - // figure out encoding memento from encoding strategy - if (fEncodingMemento == null) { - if (fClientSuppliedStream) { - fEncodingMemento = findMementoFromStreamCase(); - } - else if (fIFile != null) { - fEncodingMemento = findMementoFromFileCase(); - } - } - - // if encoding stratagy doesn't provide answer, - // then try file settings, project settings, - // user preferences, and - // finally workbench default. - // - if (fEncodingMemento == null || fEncodingMemento.getDetectedCharsetName() == null) { - fEncodingMemento = getEncodingMementoFromResourceAndPreference(); - } - - // use DefaultNameRules from NonContentBasedEncodingRules as the final - // default - if (fEncodingMemento == null) { - fEncodingMemento = handleNotProvidedFromContentCase(); - } - - return fEncodingMemento; - } - - /* - * This method is called only when encoding is not detected in the file. - * - * Here is encoding lookup order we will try: - try resource content - * description (Eclipse Text file encoding) - try resource content - * properties (for JSP only) - try content type encoding preferences (for - * HTML only) - try resource content description (Eclipse Text file - * encoding, implicit check) - * - * Note: This method appears in both CodedReaderCreator and - * CodedStreamCreator (with just a minor difference). They should be kept - * the same. - */ - private EncodingMemento getEncodingMementoFromResourceAndPreference() throws IOException, CoreException { - EncodingMemento encodingMemento = fEncodingMemento; - - // Follow Eclipse Platform's direction. Get the charset from IFile. - if (fIFile != null) { - String charset = fIFile.getCharset(); - encodingMemento = CodedIO.createEncodingMemento(charset); - } - - return encodingMemento; - } - - /** - * Ensures that an InputStream has mark/reset support, is readlimit is - * set, and that the stream is "limitable" (that is, reports "end of - * input" rather than allow going past mark). This is very specialized - * stream introduced to overcome - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=67211. See also - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=68565 - */ - private InputStream getLimitedStream(InputStream original) { - if (original == null) - return null; - if (original instanceof BufferedLimitedStream) - return original; - InputStream s = new BufferedLimitedStream(original, CodedIO.MAX_MARK_SIZE); - s.mark(CodedIO.MAX_MARK_SIZE); - return s; - } - - private InputStream getResettableStream() throws CoreException, IOException { - - InputStream resettableStream = null; - - if (fIFile != null) { - InputStream inputStream = null; - try { - // note we always get contents, even if out of synch - inputStream = fIFile.getContents(true); - } - catch (CoreException e) { - // SHOULD actually check for existence of - // fIStorage, but - // for now will just assume core exception - // means it - // doesn't exist on file system, yet. - // and we'll log, just in case its a noteable error - Logger.logException(e); - inputStream = new NullInputStream(); - } - resettableStream = new BufferedInputStream(inputStream, CodedIO.MAX_BUF_SIZE); - } - else { - if (fInputStream != null) { - if (fInputStream.markSupported()) { - resettableStream = fInputStream; - // try { - resettableStream.reset(); - // } - // catch (IOException e) { - // // assumed just hasn't been marked yet, so ignore - // } - } - else { - resettableStream = new BufferedInputStream(fInputStream, CodedIO.MAX_BUF_SIZE); - } - } - } - - if (resettableStream == null) { - resettableStream = new NullInputStream(); - } - - // mark this once, stream at "zero" position - resettableStream.mark(MAX_MARK_SIZE); - return resettableStream; - } - - private EncodingMemento handleNotProvidedFromContentCase() { - - EncodingMemento result = null; - String specDefault = null; - // try { - // specDefault = getEncodingDetector().getSpecDefaultEncoding(); - // } - // catch (CoreException e) { - // // If this exception occurs, assumes there is - // // no specDefault - // } - // catch (IOException e) { - // // If this exception occurs, assumes there is - // // no specDefault - // } - // finally { - // try { - // handleStreamClose(fEncodingDetectorStream); - // } - // catch (IOException e1) { - // // severe error, not much to do here - // } - // } - // this logic should be moved to 'detection' if not already - String charset = NonContentBasedEncodingRules.useDefaultNameRules(specDefault); - Assert.isNotNull(charset, "post condition failed"); //$NON-NLS-1$ - result = CodedIO.createEncodingMemento(charset); - return result; - } - - /** - * @param resettableInputStream - * @throws IOException - */ - private void handleStreamClose(InputStream resettableInputStream) throws IOException { - - if (resettableInputStream != null) { - if (fClientSuppliedStream) { - resettableInputStream.reset(); - } - else { - - resettableInputStream.close(); - } - } - } - - // TODO We just copy the content properties encoding to current resource's - // encoding for now. May improve the UI later by setting an informational - // message and/or disable the content properties encoding field. - // TODO: remake private else remove - void migrateContentPropertiesEncoding(String encoding) throws CoreException { - final IFile file = fIFile; - final String charset = encoding; - // TODO: externalize string later - Job migrater = new Job(SSECoreMessages.Migrate_Charset) { //$NON-NLS-1$ - protected IStatus run(IProgressMonitor monitor) { - if (file != null) { - try { - file.setCharset(charset, null); - } - catch (CoreException e) { - Logger.logException(e); - } - } - return Status.OK_STATUS; - } - }; - migrater.setSystem(true); - migrater.schedule(); - } - - private void resetAll() { - - fEncodingRule = null; - fIFile = null; - fFilename = null; - fInputStream = null; - fEncodingMemento = null; - fClientSuppliedStream = false; - } - - public void set(IFile iFile) throws CoreException, IOException { - Assert.isNotNull(iFile, "illegal argument"); //$NON-NLS-1$ - resetAll(); - fIFile = iFile; - } - - public void set(String filename, InputStream inputStream) { - - resetAll(); - fFilename = filename; - fInputStream = inputStream; - fClientSuppliedStream = true; - } - - public void setEncodingRule(EncodingRule encodingRule) { - - fEncodingRule = encodingRule; - } -} |