package org.eclipse.cdt.utils.coff;

/*
 * (c) Copyright QNX Software Systems Ltd. 2002.
 * All Rights Reserved.
 */

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Vector;

/**
 *  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.
 *  @see ARHeader
 */
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.
	 */
	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.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");
		String hdr = rfile.readLine();
		if (hdr == null || hdr.compareTo("!<arch>") != 0) {
			rfile.close();
			throw new IOException("Not a valid archive file.");
		}
	}

	/** Load the headers from the file (if required).  */
	private void loadHeaders() throws IOException {
		if (headers != null)
			return;

		Vector v = new Vector();
		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)
					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 = (ARHeader[]) 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 (int i = 0; i < set.length; i++)
			if (str.compareTo(set[i]) == 0)
				return true;
		return false;
	}

	public String[] extractFiles(String outdir, String[] names)
		throws IOException {
		Vector names_used = new Vector();
		String object_name;
		int count;

		loadHeaders();

		count = 0;
		for (int i = 0; i < headers.length; i++) {
			object_name = headers[i].getObjectName();
			if (names != null && !stringInStrings(object_name, names))
				continue;

			object_name = "" + count + "_" + object_name;
			count++;

			byte[] data = headers[i].getObjectData();
			File output = new File(outdir, object_name);
			names_used.add(object_name);

			RandomAccessFile rfile = new RandomAccessFile(output, "rw");
			rfile.write(data);
			rfile.close();
		}

		return (String[]) names_used.toArray(new String[0]);
	}

	public String[] extractFiles(String outdir) throws IOException {
		return extractFiles(outdir, null);
	}

}
