blob: 830c92242c3912fdf9d0e0da6f2f7ff498fa5289 [file] [log] [blame]
/*
* Copyright (c) 2009 Borland Software Corporation
*
* 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:
* Artem Tikhomirov (Borland) - initial API and implementation
*/
package org.eclipse.gmf.internal.xpand.inactive;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.content.ITextContentDescriber;
/**
* Major difference from platform's default content describer (which uses BOM) is that we
* supply ISO-8859-1 encoding for legacy template files (those with 0xAB and 0xBB), but keep
* exposing UTF-8 as our default encoding. Besides, we do recognize UTF-8 encoding even if
* there's no BOM in the file (looking for 0xC2 0xAB and 0xC2 0xBB sequences)
*
* Another important aspect of this detector is that it is confident (i.e. VALID) about GMF-Xpand
* content type when there's no IMPORT statement in the template that looks like OAW Xpand.
* @author artem
*/
public class ContentDescriber implements ITextContentDescriber {
private final Pattern myImportClause;
public ContentDescriber() {
myImportClause = Pattern.compile("IMPORT\\s+");
}
public int describe(Reader contents, IContentDescription description) throws IOException {
// no idea what I can tell here, but if I do not implement ITextContentDescriber, attempt to save
// existing! UTF-8 xpt file under template folder with ISO encoding results in error "can't convert UTF to ISO"
// - for some stupid reason Eclipse TextEditor tries to come up with new encoding for existing file
final char[] lookahead = new char[1024];
int count = contents.read(lookahead);
if (count == 0 || count == -1) {
return INDETERMINATE;
}
return checkSpecificToGMF(CharBuffer.wrap(lookahead, 0, count));
}
public int describe(InputStream contents, IContentDescription description) throws IOException {
contents = StreamDecoder.ensureMarkSupported(contents);
int check = INDETERMINATE;
try {
final char[] lookahead = new char[1024];
contents.mark(lookahead.length + 1);
// use US-ASCII as keywords we are looking for got codes < 127
int count = new InputStreamReader(contents, Charset.forName("US-ASCII")).read(lookahead); //$NON-NLS-1$
if (count == 0 || count == -1) {
return INDETERMINATE;
}
check = checkSpecificToGMF(CharBuffer.wrap(lookahead, 0, count));
if (check == INVALID) {
return INVALID;
}
} finally {
contents.reset();
}
StreamDecoder sd = new StreamDecoder(contents, null);
if (sd.getEncoding() == null) {
return check;
}
if (description != null) {
description.setProperty(IContentDescription.CHARSET, sd.getEncoding().name());
}
// XXX alternatively, may return 'check' result, but which content type
// would get assigned to empty (just created) files then?
return VALID;
}
public QualifiedName[] getSupportedOptions() {
return null; // none
}
// uses INVALID, VALID and INDETERMINATE constants to indicate
// whether template is "definitely not GMF's", "definitely GMF's" and "can't tell" respectively
private int checkSpecificToGMF(CharSequence s) throws IOException {
Matcher m = myImportClause.matcher(s);
if (m.find()) {
if (m.hitEnd() || m.end() >= s.length()) {
return INDETERMINATE; // found IMPORT, but can't tell what's after that
}
char firstNonSpace = s.charAt(m.end());
return firstNonSpace == '"' || firstNonSpace == '\'' ? VALID : INVALID;
}
return INDETERMINATE;
}
}