ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen/*
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * CDDL HEADER START
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen *
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * The contents of this file are subject to the terms of the
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * Common Development and Distribution License (the "License").
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * You may not use this file except in compliance with the License.
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen *
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * See LICENSE.txt included in this distribution for the specific
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * language governing permissions and limitations under the License.
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen *
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * When distributing Covered Code, include this CDDL HEADER in each
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * file and include the License file at LICENSE.txt.
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * If applicable, add the following below this CDDL HEADER, with the
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * fields enclosed by brackets "[]" replaced with your own identifying
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * information: Portions Copyright [yyyy] [name of copyright owner]
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen *
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen * CDDL HEADER END
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen */
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen/*
eb11fe3584b7b243fb0641da4ab2e157610bb767Lubos Kosco * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen */
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlenpackage org.opensolaris.opengrok.analysis.archive;
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlenimport java.io.IOException;
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlenimport java.io.InputStream;
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlenimport org.opensolaris.opengrok.analysis.FileAnalyzer;
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlenimport org.opensolaris.opengrok.analysis.FileAnalyzer.Genre;
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlenimport org.opensolaris.opengrok.analysis.FileAnalyzerFactory;
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlenimport org.opensolaris.opengrok.analysis.executables.JarAnalyzerFactory;
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen
3af7cb62d32b222d39b8af3ebf691892502eba15Jorgen Austvikpublic final class ZipAnalyzerFactory extends FileAnalyzerFactory {
eb11fe3584b7b243fb0641da4ab2e157610bb767Lubos Kosco
eb11fe3584b7b243fb0641da4ab2e157610bb767Lubos Kosco private static final String name = "Zip";
eb11fe3584b7b243fb0641da4ab2e157610bb767Lubos Kosco
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen private static final String[] SUFFIXES = {
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen "ZIP"
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen };
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen
b30e5871823d614f9fc46cdaea08387ec62cabf8Jorgen Austvik private static final byte[] MAGIC = {'P', 'K', 3, 4};
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen // Derived from /usr/src/cmd/file/file.c in OpenSolaris
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen private static final Matcher MATCHER = new Matcher() {
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen private static final int LOCHDRSIZ = 30;
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen private int CH(byte[] b, int n) {
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen return b[n] & 0xff;
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen private int SH(byte[] b, int n) {
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen return CH(b, n) | (CH(b, n+1) << 8);
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen private int LOCNAM(byte[] b) {
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen return SH(b, 26);
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen private int LOCEXT(byte[] b) {
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen return SH(b, 28);
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen private static final int XFHSIZ = 4;
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
eb11fe3584b7b243fb0641da4ab2e157610bb767Lubos Kosco @Override
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen public FileAnalyzerFactory isMagic(byte[] contents, InputStream in)
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen throws IOException {
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen assert in.markSupported();
01e5aab81f6cffa82602ab52af92d01c4bad2408Trond Norbye if (contents.length < MAGIC.length) {
01e5aab81f6cffa82602ab52af92d01c4bad2408Trond Norbye return null;
01e5aab81f6cffa82602ab52af92d01c4bad2408Trond Norbye }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen for (int i = 0; i < MAGIC.length; i++) {
01e5aab81f6cffa82602ab52af92d01c4bad2408Trond Norbye if (contents[i] != MAGIC[i]) {
01e5aab81f6cffa82602ab52af92d01c4bad2408Trond Norbye return null;
01e5aab81f6cffa82602ab52af92d01c4bad2408Trond Norbye }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen byte[] buf = new byte[1024];
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen in.mark(buf.length);
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen int len = in.read(buf);
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen in.reset();
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen int xoff = LOCHDRSIZ + LOCNAM(buf);
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen int xoff_end = Math.min(len, xoff + LOCEXT(buf));
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen while ((xoff < xoff_end) && (len - xoff >= XFHSIZ)) {
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen int xfhid = SH(buf, xoff);
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen if (xfhid == 0xCAFE) {
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen return JarAnalyzerFactory.DEFAULT_INSTANCE;
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen int xfdatasiz = SH(buf, xoff + 2);
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen xoff += XFHSIZ + xfdatasiz;
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen return ZipAnalyzerFactory.DEFAULT_INSTANCE;
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen }
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen };
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen public static final ZipAnalyzerFactory DEFAULT_INSTANCE =
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen new ZipAnalyzerFactory();
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen
23d7d0b65bed750a74caa1b2efc2c4121e84e965Knut Anders Hatlen private ZipAnalyzerFactory() {
eb11fe3584b7b243fb0641da4ab2e157610bb767Lubos Kosco super(null, null, SUFFIXES, null, MATCHER, null, Genre.XREFABLE, name);
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen }
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen @Override
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen protected FileAnalyzer newAnalyzer() {
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen return new ZipAnalyzer(this);
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen }
ca13a2073cb9936daab594cd277550783ac2e6b6Knut Anders Hatlen}