/* * Copyright 2000-2011 JetBrains s.r.o. * * Licensed 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 jetbrains.buildServer.tools.checkers; import jetbrains.buildServer.tools.CheckAction; import jetbrains.buildServer.tools.ErrorKind; import jetbrains.buildServer.tools.ErrorReporting; import jetbrains.buildServer.tools.java.JavaVersion; import jetbrains.buildServer.tools.ScanFile; import org.jetbrains.annotations.NotNull; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; /** * @author Eugene Petrenko (eugene.petrenko@gmail.com) * Date: 08.11.11 14:37 */ public class ClassFileChecker implements CheckAction { private final JavaVersion myVersion; public ClassFileChecker(@NotNull final JavaVersion version) { myVersion = version; } public void process(@NotNull ScanFile file, @NotNull ErrorReporting reporting) throws IOException { checkVersion(file, reporting); } private void checkVersion(@NotNull final ScanFile file, @NotNull final ErrorReporting reporting) throws IOException { final InputStream stream = new BufferedInputStream(file.openStream()); try { if (!checkCAFEBABE(file, stream, reporting)) { return; } //noinspection ResultOfMethodCallIgnored stream.read(); //noinspection ResultOfMethodCallIgnored stream.read(); final int v = stream.read() * 256 + stream.read(); final JavaVersion version = JavaVersion.find(v); if (version == null) { reporting.postCheckError(file, ErrorKind.VERSION, "version is unknown ( " + v + ")"); return; } if (!version.canRunOn(myVersion)) { reporting.postCheckError(file, ErrorKind.VERSION, "version is " + version + " but expected to be <= " + myVersion); } } finally { stream.close(); } } private boolean checkCAFEBABE(@NotNull ScanFile file, @NotNull InputStream stream, @NotNull final ErrorReporting reporting) throws IOException { int[] data = new int[4]; for (int i = 0; i < data.length; i++) { data[i] = stream.read(); } if (data[0] != 0xCA || data[1] != 0xFE || data[2] != 0xBA || data[3] != 0xBE) { reporting.postCheckError(file, ErrorKind.VERSION, "Class file must start with 0xCAFEBABE, but was: " + byteToHex(data)); return false; } return true; } private String byteToHex(int[] data) { StringBuilder sb = new StringBuilder(); for (int b : data) { sb.append(toHex(b)); } return sb.toString(); } private String toHex(int v) { if (v == 0) return "0"; String s = ""; if (v < 0) { s = "-"; v = -v; } while (v > 0) { int h = v % 16; v /= 16; if (h < 10) { s = h + s; } else { s = (char) (h - 10 + 'a') + s; } } return s; } }