001: /*
002: * :tabSize=8:indentSize=8:noTabs=false:
003: * :folding=explicit:collapseFolds=1:
004: *
005: * Copyright (C) 2006 Kazutoshi Satoda
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.gjt.sp.jedit.io;
023:
024: //{{{ Imports
025: import java.io.InputStream;
026: import java.io.BufferedInputStream;
027: import java.io.IOException;
028: import java.util.List;
029: import java.util.ArrayList;
030: import java.util.zip.GZIPInputStream;
031:
032: import org.gjt.sp.jedit.jEdit;
033: import org.gjt.sp.jedit.ServiceManager;
034: import org.gjt.sp.jedit.bufferio.BufferIORequest;
035: import org.gjt.sp.util.Log;
036:
037: //}}}
038:
039: /**
040: * Some functions for auto detection of I/O stream properties.
041: */
042: public class AutoDetection {
043: //{{{ getMarkedStream() method
044: /**
045: * Returns a marked, rewindable stream.
046: * Calling reset() method rewinds the stream to its beginning.
047: * But reset() can fail if too long bytes were read.
048: */
049: public static BufferedInputStream getMarkedStream(InputStream in) {
050: int bufferSize = BufferIORequest.getByteIOBufferSize();
051: BufferedInputStream markable = new BufferedInputStream(in,
052: bufferSize);
053: assert (markable.markSupported());
054: markable.mark(bufferSize);
055: return markable;
056: } //}}}
057:
058: //{{{ isGzipped() method
059: /**
060: * Returns wheather the stream is gzipped.
061: * This method reads a few bytes from the sample. So a caller
062: * must take care of mark() to reuse the contents. Wraping the
063: * stream by getMarkedStream() is suitable.
064: */
065: public static boolean isGzipped(InputStream sample)
066: throws IOException {
067: int magic1 = GZIPInputStream.GZIP_MAGIC & 0xff;
068: int magic2 = (GZIPInputStream.GZIP_MAGIC >> 8) & 0xff;
069: return sample.read() == magic1 && sample.read() == magic2;
070: } //}}}
071:
072: //{{{ getEncodingDetectors() method
073: /**
074: * Returns the user configured ordered list of encoding detectors.
075: * This method reads property "encodingDetectors".
076: */
077: public static List<EncodingDetector> getEncodingDetectors() {
078: List<EncodingDetector> detectors = new ArrayList<EncodingDetector>();
079: String propName = "encodingDetectors";
080: String selectedDetectors = jEdit.getProperty(propName,
081: "BOM XML-PI");
082: if (selectedDetectors != null && selectedDetectors.length() > 0) {
083: for (String name : selectedDetectors.split("\\s+")) {
084: EncodingDetector service = getEncodingDetectorService(name);
085: if (service != null) {
086: detectors.add(service);
087: } else {
088: Log
089: .log(
090: Log.ERROR,
091: AutoDetection.class,
092: "getEncodingDetectors():"
093: + " No EncodingDetector for the name"
094: + " \"" + name + "\"");
095: }
096: }
097: }
098: return detectors;
099: } //}}}
100:
101: //{{{ getDetectedEncoding() method
102: /**
103: * Returns an auto detected encoding from content of markedStream.
104: * This method assumes that markedStream is wrapped by
105: * getMarkedStream() method.
106: */
107: public static String getDetectedEncoding(
108: BufferedInputStream markedStream) throws IOException {
109: List<EncodingDetector> detectors = getEncodingDetectors();
110: for (EncodingDetector detector : detectors) {
111: // FIXME: Here the method reset() can fail if the
112: // previous detector read more than buffer size of
113: // markedStream.
114: markedStream.reset();
115: // Wrap once more so that calling mark()
116: // or reset() in detectEncoding() don't
117: // alter the mark position of markedStream.
118: String detected = detector
119: .detectEncoding(new BufferedInputStream(
120: markedStream));
121: if (detected != null) {
122: return detected;
123: }
124: }
125: return null;
126: } //}}}
127:
128: //{{{ class Result
129: /**
130: * An utility class to hold the result of some auto detections.
131: */
132: public static class Result {
133: //{{{ Constructor
134: /**
135: * Do some auto detection for a stream and hold the
136: * result in this instance.
137: * @param in the stream
138: */
139: public Result(InputStream in) throws IOException {
140: BufferedInputStream marked = getMarkedStream(in);
141:
142: gzipped = isGzipped(marked);
143: if (gzipped) {
144: marked.reset();
145: marked = getMarkedStream(new GZIPInputStream(marked));
146: }
147:
148: marked.reset();
149: encoding = AutoDetection.getDetectedEncoding(marked);
150:
151: markedStream = marked;
152: } //}}}
153:
154: //{{{ getRewindedStream()
155: /**
156: * Returns the stream which can be read the contents of
157: * the original stream.
158: * Some bytes ware read from original stream for auto
159: * detections. But they are rewinded at this method.
160: */
161: public BufferedInputStream getRewindedStream()
162: throws IOException {
163: markedStream.reset();
164: return markedStream;
165: } //}}}
166:
167: //{{{ streamIsGzipped()
168: /**
169: * Returns true if the stream is gzipped.
170: */
171: public boolean streamIsGzipped() {
172: return gzipped;
173: } //}}}
174:
175: //{{{ getDetectedEncoding()
176: /**
177: * Returns the auto detected encoding.
178: * Returns null if no encoding was detected.
179: */
180: public String getDetectedEncoding() {
181: return encoding;
182: } //}}}
183:
184: //{{{ Private members
185: private final BufferedInputStream markedStream;
186: private final boolean gzipped;
187: private final String encoding;
188: //}}}
189: } //}}}
190:
191: //{{{ Private members
192: /**
193: * Returns a service of EncodingDetector for name.
194: */
195: private static EncodingDetector getEncodingDetectorService(
196: String name) {
197: String serviceClass = "org.gjt.sp.jedit.io.EncodingDetector";
198: Object service = ServiceManager.getService(serviceClass, name);
199: if (service != null && service instanceof EncodingDetector) {
200: return (EncodingDetector) service;
201: } else {
202: return null;
203: }
204: }
205: //}}}
206: }
|