All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.royale.compiler.filespecs.CombinedFile Maven / Gradle / Ivy

The newest version!
/*
 *
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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 org.apache.royale.compiler.filespecs;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.io.IOUtils;

import org.apache.royale.utils.FilenameNormalization;

/**
 * This is an {@link IFileSpecification} that include multiple source files into
 * one. JFlex-generated tokenizers can skip BOM at the beginning of a file, but
 * not elsewhere. This class skips BOM header in each source file so that the
 * merged file won't have a BOM in the middle of a file.
 */
public class CombinedFile implements IFileSpecification
{

    /**
     * Create a combined file by concatenating {@code includedFilenames}
     * together and append {@code sourceFilename} at the end.
     * 
     * @param includedFilenames included files
     * @param sourceFilename source file
     */
    public CombinedFile(final List includedFilenames, final String sourceFilename)
    {
        this.combinedSource = null;
        this.sourceFilename = FilenameNormalization.normalize(sourceFilename);
        this.fileList = includedFilenames;
        this.fileList.add(sourceFilename);
    }

    private StringBuilder combinedSource;
    private final String sourceFilename;
    private final List fileList;

    /**
     * The path of the combined file is the path of the source file.
     */
    @Override
    public String getPath()
    {
        return sourceFilename;
    }

    /**
     * Create a {@link Reader} from the combined source text.
     * 

* {@inheritDoc} */ @Override public Reader createReader() throws FileNotFoundException { if (combinedSource == null) combineFile(); return new StringReader(combinedSource.toString()); } /** * Get the time stamp of the most recent modified file among the source * files. *

* {@inheritDoc} */ @Override public long getLastModified() { long lastModified = 0; for (final String file : fileList) { final long timestamp = new File(file).lastModified(); lastModified = Math.max(lastModified, timestamp); } return lastModified; } /** * Always return false because the combined file is cached in memory. *

* {@inheritDoc} */ @Override public boolean isOpenDocument() { return false; } /** * Concatenate source files together. The main source file is always at the * end. * * @throws FileNotFoundException error */ private void combineFile() throws FileNotFoundException { assert combinedSource == null : "Do not call combineFile() twice."; combinedSource = new StringBuilder(); for (final String filename : fileList) { Reader reader = null; try { final BufferedInputStream strm = getStreamAndSkipBOM(filename); reader = new InputStreamReader(strm); combinedSource.append(IOUtils.toString(reader)); combinedSource.append(IOUtils.LINE_SEPARATOR); } catch (FileNotFoundException e) { throw e; } catch (IOException e) { throw new RuntimeException(e); } finally { IOUtils.closeQuietly(reader); } } } /** * BOM patterns. * * @see Unicode BOM spec */ public static enum BOM { NONE("UTF-8"), UTF_8("UTF-8", (byte)0xEF, (byte)0xBB, (byte)0xBF), UTF_16_LE("UTF-16LE", (byte)0xFF, (byte)0xFE), UTF_16_BE("UTF-16BE", (byte)0xFE, (byte)0xFF), UTF_32_LE("UTF-32LE", (byte)0xFF, (byte)0xFE, (byte)0x00, (byte)0x00), UTF_32_BE("UTF-32BE", (byte)0x00, (byte)0x00, (byte)0xFE, (byte)0xFF); private BOM(final String charsetName, final byte... pattern) { if (charsetName == null || !Charset.isSupported(charsetName)) this.charset = Charset.defaultCharset(); else this.charset = Charset.forName(charsetName); this.pattern = pattern; } /** * BOM pattern in byte array. */ public final byte pattern[]; /** * The Java {@link Charset} for this BOM header. */ public final Charset charset; } /** * Get the {@link BufferedInputStream} of a file, skipping the BOM. * * @param filename The path to the file. * @return BufferedInputStream */ public static BufferedInputStream getStreamAndSkipBOM(String filename) throws IOException { final File file = new File(filename); BufferedInputStream strm = new BufferedInputStream(new FileInputStream(file)); final BOM bom = getBOM(strm); strm.skip(bom.pattern.length); return strm; } /** * Get the BOM tag of a stream. * * @param strm BufferedInputStream to be checked. * @return {@link BOM} type. * @throws IOException Error. */ public static BOM getBOM(BufferedInputStream strm) throws IOException { assert (strm.markSupported()) : "getBOM call on stream which does not support mark"; // Peek the first 4 bytes. final byte[] peek = new byte[4]; strm.mark(4); strm.read(peek); strm.reset(); // Try matching 4-byte BOM tags. final byte[] quadruplet = Arrays.copyOf(peek, 4); if (Arrays.equals(BOM.UTF_32_BE.pattern, quadruplet)) return BOM.UTF_32_BE; else if (Arrays.equals(BOM.UTF_32_LE.pattern, quadruplet)) return BOM.UTF_32_LE; // Try matching 3-byte BOM tags. final byte[] triplet = Arrays.copyOf(peek, 3); if (Arrays.equals(BOM.UTF_8.pattern, triplet)) return BOM.UTF_8; // Try matching 2-byte BOM tags. final byte[] twin = Arrays.copyOf(peek, 2); if (Arrays.equals(BOM.UTF_16_BE.pattern, twin)) return BOM.UTF_16_BE; else if (Arrays.equals(BOM.UTF_16_LE.pattern, twin)) return BOM.UTF_16_LE; // No BOM tag. return BOM.NONE; } @Override public void setLastModified(long fileDate) { // TODO Auto-generated method stub } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy