/******************************************************************************* * Copyright (c) 2000, 2008 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.utils.coff; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Vector; import org.eclipse.cdt.core.CCorePlugin; /** * The <code>AR</code> class is used for parsing standard ELF archive (ar) files. * * Each object within the archive is represented by an ARHeader class. Each of * of these objects can then be turned into an PE object for performing PE * class operations. * @deprecated - use org.eclipse.cdt.ui.utils.AR * @see ARHeader */ @Deprecated public class PEArchive { protected String filename; protected RandomAccessFile rfile; protected long strtbl_pos = -1; private ARHeader[] headers; public void dispose() { try { if (rfile != null) { rfile.close(); rfile = null; } } catch (IOException e) { } } /** * Do not leak fds. */ @Override protected void finalize() throws Throwable { try { dispose(); } finally { super.finalize(); } } /** * The <code>ARHeader</code> class is used to store the per-object file * archive headers. It can also create an PE object for inspecting * the object file data. */ public class ARHeader { private String object_name; // private String modification_time; // private String uid; // private String gid; // private String mode; private long size; private long elf_offset; /** * Remove the padding from the archive header strings. */ private String removeBlanks(String str) { while (str.charAt(str.length() - 1) == ' ') str = str.substring(0, str.length() - 1); return str; } /** * Look up the name stored in the archive's string table based * on the offset given. * * Maintains <code>rfile</code> file location. * * @param offset * Offset into the string table for first character of the name. * @throws IOException * <code>offset</code> not in string table bounds. */ private String nameFromStringTable(long offset) throws IOException { StringBuffer name = new StringBuffer(0); long pos = rfile.getFilePointer(); try { if (strtbl_pos != -1) { byte temp; rfile.seek(strtbl_pos + offset); while ((temp = rfile.readByte()) != '\n') name.append((char) temp); } } finally { rfile.seek(pos); } return name.toString(); } /** * Creates a new archive header object. * * Assumes that rfile is already at the correct location in the file. * * @throws IOException * There was an error processing the header data from the file. */ public ARHeader() throws IOException { byte[] object_name = new byte[16]; byte[] modification_time = new byte[12]; byte[] uid = new byte[6]; byte[] gid = new byte[6]; byte[] mode = new byte[8]; byte[] size = new byte[10]; byte[] trailer = new byte[2]; // // Read in the archive header data. Fixed sizes. // rfile.read(object_name); rfile.read(modification_time); rfile.read(uid); rfile.read(gid); rfile.read(mode); rfile.read(size); rfile.read(trailer); // // Save this location so we can create the PE object later. // elf_offset = rfile.getFilePointer(); // // Convert the raw bytes into strings and numbers. // this.object_name = removeBlanks(new String(object_name)); // this.modification_time = new String(modification_time); // this.uid = new String(uid); // this.gid = new String(gid); // this.mode = new String(mode); this.size = Long.parseLong(removeBlanks(new String(size))); // // If the name is of the format "/<number>", get name from the // string table. // if (strtbl_pos != -1 && this.object_name.length() > 1 && this.object_name.charAt(0) == '/') { try { long offset = Long.parseLong(this.object_name.substring(1)); this.object_name = nameFromStringTable(offset); } catch (java.lang.Exception e) { } } // // Strip the trailing / from the object name. // int len = this.object_name.length(); if (len > 2 && this.object_name.charAt(len - 1) == '/') { this.object_name = this.object_name.substring(0, len - 1); } } /** Get the name of the object file */ public String getObjectName() { return object_name; } /** Get the size of the object file . */ public long getSize() { return size; } /** * Create an new PE object for the object file. * * @throws IOException * Not a valid PE object file. * @return A new PE object. * @see PE#PE( String, long ) */ public PE getPE() throws IOException { return new PE(filename, elf_offset); } public PE getPE(boolean filter_on) throws IOException { return new PE(filename, elf_offset, filter_on); } public byte[] getObjectData() throws IOException { byte[] temp = new byte[(int) size]; rfile.seek(elf_offset); rfile.read(temp); return temp; } } public static boolean isARHeader(byte[] ident) { if (ident == null || ident.length < 7 || ident[0] != '!' || ident[1] != '<' || ident[2] != 'a' || ident[3] != 'r' || ident[4] != 'c' || ident[5] != 'h' || ident[6] != '>') return false; return true; } /** * Creates a new <code>AR</code> object from the contents of * the given file. * * @param filename The file to process. * @throws IOException The file is not a valid archive. */ public PEArchive(String filename) throws IOException { this.filename = filename; rfile = new RandomAccessFile(filename, "r"); //$NON-NLS-1$ String hdr = rfile.readLine(); if (hdr == null || hdr.compareTo("!<arch>") != 0) { //$NON-NLS-1$ rfile.close(); throw new IOException(CCorePlugin.getResourceString("Util.exception.invalidArchive")); //$NON-NLS-1$ } } /** Load the headers from the file (if required). */ private void loadHeaders() throws IOException { if (headers != null) return; Vector<ARHeader> v = new Vector<ARHeader>(); try { // // Check for EOF condition // while (rfile.getFilePointer() < rfile.length()) { ARHeader header = new ARHeader(); String name = header.getObjectName(); long pos = rfile.getFilePointer(); // // If the name starts with a / it is specical. // if (name.charAt(0) != '/') v.add(header); // // If the name is "//" then this is the string table section. // if (name.compareTo("//") == 0) //$NON-NLS-1$ strtbl_pos = pos; // // Compute the location of the next header in the archive. // pos += header.getSize(); if ((pos % 2) != 0) pos++; rfile.seek(pos); } } catch (IOException e) { } headers = v.toArray(new ARHeader[0]); } /** * Get an array of all the object file headers for this archive. * * @throws IOException * Unable to process the archive file. * @return An array of headers, one for each object within the archive. * @see ARHeader */ public ARHeader[] getHeaders() throws IOException { loadHeaders(); return headers; } private boolean stringInStrings(String str, String[] set) { for (String element : set) if (str.compareTo(element) == 0) return true; return false; } public String[] extractFiles(String outdir, String[] names) throws IOException { Vector<String> names_used = new Vector<String>(); String object_name; int count; loadHeaders(); count = 0; for (ARHeader header : headers) { object_name = header.getObjectName(); if (names != null && !stringInStrings(object_name, names)) continue; object_name = "" + count + "_" + object_name; //$NON-NLS-1$ //$NON-NLS-2$ count++; byte[] data = header.getObjectData(); File output = new File(outdir, object_name); names_used.add(object_name); RandomAccessFile rfile = new RandomAccessFile(output, "rw"); //$NON-NLS-1$ rfile.write(data); rfile.close(); } return names_used.toArray(new String[0]); } public String[] extractFiles(String outdir) throws IOException { return extractFiles(outdir, null); } }