org.eclipse.jdt.internal.compiler.util.ManifestAnalyzer.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jdt.internal.compiler.util.ManifestAnalyzer.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2013 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.compiler.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class ManifestAnalyzer {
    private static final int START = 0, IN_CLASSPATH_HEADER = 1, // multistate
            PAST_CLASSPATH_HEADER = 2, SKIPPING_WHITESPACE = 3, READING_JAR = 4, CONTINUING = 5, SKIP_LINE = 6;
    private static final char[] CLASSPATH_HEADER_TOKEN = "Class-Path:".toCharArray(); //$NON-NLS-1$
    private int classpathSectionsCount;
    private ArrayList calledFilesNames;

    /**
     * Analyzes the manifest contents. The given input stream is read using a UTF-8 encoded reader.
     * If the contents of the input stream is not encoded using a UTF-8 encoding, the analysis will fail.
     * 
     * @param inputStream the given input stream.
     * 
     * @return <code>true</code> if the analysis is successful, <code>false</code> otherwise.
     * @throws IOException if an exception occurs while analyzing the file
     */
    public boolean analyzeManifestContents(InputStream inputStream) throws IOException {
        char[] chars = Util.getInputStreamAsCharArray(inputStream, -1, Util.UTF_8);
        return analyzeManifestContents(chars);
    }

    /**
     * Analyzes the manifest contents.
     * 
     * @param chars the content of the manifest
     * 
     * @return <code>true</code> if the analysis is successful, <code>false</code> otherwise.
     */
    public boolean analyzeManifestContents(char[] chars) {
        int state = START, substate = 0;
        StringBuffer currentJarToken = new StringBuffer();
        int currentChar;
        this.classpathSectionsCount = 0;
        this.calledFilesNames = null;
        for (int i = 0, max = chars.length; i < max;) {
            currentChar = chars[i++];
            if (currentChar == '\r') {
                // skip \r, will consider \n later (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=251079 )
                if (i < max) {
                    currentChar = chars[i++];
                }
            }
            switch (state) {
            case START:
                if (currentChar == CLASSPATH_HEADER_TOKEN[0]) {
                    state = IN_CLASSPATH_HEADER;
                    substate = 1;
                } else {
                    state = SKIP_LINE;
                }
                break;
            case IN_CLASSPATH_HEADER:
                if (currentChar == '\n') {
                    state = START;
                } else if (currentChar != CLASSPATH_HEADER_TOKEN[substate++]) {
                    state = SKIP_LINE;
                } else if (substate == CLASSPATH_HEADER_TOKEN.length) {
                    state = PAST_CLASSPATH_HEADER;
                }
                break;
            case PAST_CLASSPATH_HEADER:
                if (currentChar == ' ') {
                    state = SKIPPING_WHITESPACE;
                    this.classpathSectionsCount++;
                } else {
                    return false;
                }
                break;
            case SKIPPING_WHITESPACE:
                if (currentChar == '\n') {
                    state = CONTINUING;
                } else if (currentChar != ' ') {
                    currentJarToken.append((char) currentChar);
                    state = READING_JAR;
                } else {
                    // >>>>>>>>>>>>>>>>>> Add the latest jar read
                    addCurrentTokenJarWhenNecessary(currentJarToken);
                }
                break;
            case CONTINUING:
                if (currentChar == '\n') {
                    addCurrentTokenJarWhenNecessary(currentJarToken);
                    state = START;
                } else if (currentChar == ' ') {
                    state = SKIPPING_WHITESPACE;
                } else if (currentChar == CLASSPATH_HEADER_TOKEN[0]) {
                    addCurrentTokenJarWhenNecessary(currentJarToken);
                    state = IN_CLASSPATH_HEADER;
                    substate = 1;
                } else if (this.calledFilesNames == null) {
                    // >>>>>>>>>>>>>>>>>> Add the latest jar read
                    addCurrentTokenJarWhenNecessary(currentJarToken);
                    state = START;
                } else {
                    // >>>>>>>>>>>>>>>>>> Add the latest jar read
                    addCurrentTokenJarWhenNecessary(currentJarToken);
                    state = SKIP_LINE;
                }
                break;
            case SKIP_LINE:
                if (currentChar == '\n') {
                    state = START;
                }
                break;
            case READING_JAR:
                if (currentChar == '\n') {
                    // appends token below
                    state = CONTINUING;
                    // >>>>>>>>>>> Add a break to not add the jar yet as it can continue on the next line
                    break;
                } else if (currentChar == ' ') {
                    // appends token below
                    state = SKIPPING_WHITESPACE;
                } else {
                    currentJarToken.append((char) currentChar);
                    break;
                }
                addCurrentTokenJarWhenNecessary(currentJarToken);
                break;
            }
        }
        switch (state) {
        case START:
            return true;
        case IN_CLASSPATH_HEADER:
            return true;
        case PAST_CLASSPATH_HEADER:
            return false;
        case SKIPPING_WHITESPACE:
            // >>>>>>>>>>>>>>>>>> Add the latest jar read
            addCurrentTokenJarWhenNecessary(currentJarToken);
            return true;
        case CONTINUING:
            // >>>>>>>>>>>>>>>>>> Add the latest jar read
            addCurrentTokenJarWhenNecessary(currentJarToken);
            return true;
        case SKIP_LINE:
            if (this.classpathSectionsCount != 0) {
                if (this.calledFilesNames == null) {
                    return false;
                }
            }
            return true;
        case READING_JAR:
            // >>>>>>>>>>>>>>>>>> Add the latest jar read
            return false;
        }
        return true;
    }

    // >>>>>>>>>>>>>>>> Method Extracted from analyzeManifestContents in the READING_JAR Block
    private boolean addCurrentTokenJarWhenNecessary(StringBuffer currentJarToken) {
        if (currentJarToken != null && currentJarToken.length() > 0) {
            if (this.calledFilesNames == null) {
                this.calledFilesNames = new ArrayList();
            }
            this.calledFilesNames.add(currentJarToken.toString());
            currentJarToken.setLength(0);
            return true;
        }
        return false;
    }
    // <<<<<<<<<<<<<<<<<<<<<<

    public int getClasspathSectionsCount() {
        return this.classpathSectionsCount;
    }

    public List getCalledFileNames() {
        return this.calledFilesNames;
    }
}