// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/corba/com/bbn/openmap/util/corba/IOR.java,v $
// $RCSfile: IOR.java,v $
// $Revision: 1.5 $
// $Date: 2005/08/09 21:04:41 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.util.corba;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
/**
* Utility class that reads and decodes CORBA IOR files. For debugging
* purposes.
*/
public class IOR {
static boolean debug = false;
static boolean verbose = false;
byte[] hex;
IOR(byte[] rawIOR) {
hex = rawIOR;
}
/**
* The first four bytes are 'IOR:' The rest of the bytes are an
* encapsulation of an IOR encoded in hex. So we first unencode
* the hex, to create a new byte array that is the encapsulated
* IOR.
*
* Encapsulation is defined in the CORBA Spec, section 12.3.3 The
* first byte indicates byte order: TRUE for BigEndian, False for
* LittleEndian. In practice, it seems to be encoded as a 4-byte
* value.
*
* Next comes a type_id string. Strings are encoded as a long (4
* bytes) indicating length, followed by n bytes of ascii text.
* The nth byte is the null byte, for the benefit of C programs.
*
* Next is a sequence of profiles. Sequences are encoded as a long
* followed by n objects. In this case, a Profile consists of a
* ProfileID (long, 4 bytes) followed by a IIOP::ProfileBody.
*
* The ProfileID (see section 10.6) is either IOP or
* MultipleComponents. I don't know anything about
* MultipleComponents, as they are intended to be opaque. This
* program only parses IOP Profiles, although it successfully
* skips over Multiple Component Profiles.
*
* An IOP Profile is a ProfileBody, defined in 12.7.2 of CORBA
* spec. A ProfileBody consists of: A version, major and minor.
* Spec'ed as two chars, in practice two shorts. A host string A
* port (2 bytes) An object key. This is an opaque sequence of
* bytes for use by the CORBA implementation that produced the
* IOR.
*
*/
void parse(PrintWriter out) {
// Make sure first four bytes are 'IOR:'
String prefix = new String(hex, 0, 4);
if (!prefix.equals("IOR:")) {
System.err.println("Invalid IOR");
System.err.println("The first four bytes should be: 'IOR:'");
System.err.println("Found: " + prefix);
System.exit(1);
}
int iorLength = (hex.length - 4) / 2;
byte[] ior = new byte[iorLength];
for (int hexIndex = 4, iorIndex = 0; hexIndex < hex.length; hexIndex += 2, iorIndex++) {
try {
ior[iorIndex] = (byte) ((hexByteToInt(hex[hexIndex]) << 4) + (hexByteToInt(hex[hexIndex + 1])));
} catch (NumberFormatException e) {
System.err.println("Index: " + hexIndex);
System.err.println(e);
return;
}
}
if (debug) {
// print out all the bytes
for (int i = 0; i < iorLength; i++) {
System.out.println(i + ": " + ior[i] + ", " + (char) ior[i]);
}
}
DataPointer dp = new DataPointer(debug);
int endian = getLongAt(dp, ior);
if (endian == 0)
out.println("Big Endian");
else
out.println("Little Endian");
int type_id_length = getLongAt(dp, ior);
if (verbose) {
out.println("type id length = " + type_id_length);
}
String type_id = getStringAt(dp, ior, type_id_length);
out.println("Type ID = \"" + type_id + "\"");
int nProfiles = getLongAt(dp, ior);
if (nProfiles < 0) {
System.err.println("Found " + nProfiles + " profiles. Aborting");
System.exit(1);
}
if (verbose) {
if (nProfiles == 0) {
out.println("There are no profiles.");
} else if (nProfiles == 1) {
out.println("There is 1 profile.");
} else {
out.println("There are " + nProfiles + " profiles.");
}
}
for (int p = 0; p < nProfiles; p++) {
int ProfileID = getLongAt(dp, ior);
out.println("Profile " + p + ": ");
if (ProfileID == 0) {
out.println("\tID: TAG_INTERNET_IOP");
int profileDataLength = getLongAt(dp, ior);
if (verbose) {
out.println("\tProfile length: " + profileDataLength);
}
int major = getShortAt(dp, ior);
int minor = getShortAt(dp, ior);
out.println("\tIIOP Version: " + major + "." + minor);
int hostLength = getLongAt(dp, ior);
String host = getStringAt(dp, ior, hostLength);
out.println("\tHost: " + host);
int port = getShortAt(dp, ior);
out.println("\tPort: " + port);
int objectKeyLength = getLongAt(dp, ior);
if (verbose) {
out.println("\tObject Key Length: " + objectKeyLength);
}
String objectKey = getStringAt(dp, ior, objectKeyLength);
out.println("\tObject Key: \"" + objectKey + "\"");
} else if (ProfileID == 1) {
out.println("\tID: TAG_MULTIPLE_COMPONENTS");
int profileDataLength = getLongAt(dp, ior);
out.println("\tProfile length: " + profileDataLength);
dp.incPointer(profileDataLength);
} else {
out.println("Unknown, value is " + ProfileID);
return;
}
}
if (dp.getPointer() == iorLength) {
out.println("IOR read successfully");
} else if (dp.getPointer() > iorLength) {
System.err.println("Failure! Overran buffer.");
} else if (dp.getPointer() < iorLength) {
System.err.println("Failure! Incomplete read.");
} else {
System.err.println("Failure! Unknown state.");
}
}
int hexByteToInt(byte b) {
char hex = (char) b;
if (('0' <= hex) && (hex <= '9')) {
return (int) (hex - '0');
} else if (('a' <= hex) && (hex <= 'f')) {
return (int) (10 + (hex - 'a'));
} else if (('A' <= hex) && (hex <= 'F')) {
return (int) (10 + (hex - 'A'));
} else {
throw new NumberFormatException("byte: " + b);
}
}
// public static int getIntAt (int idx, byte[] b) {
// // gets an int at the specified location.
// return 0;
// }
int getInt4At(DataPointer dp, byte[] b) {
// gets a 4 byte integer off the byte array at index dp
dp.align(4);
int i = dp.getPointer();
int x = ((b[i] << 24) + (b[i + 1] << 16) + (b[i + 2] << 8) + (b[i + 3] << 0));
dp.incPointer(4);
return x;
}
int getInt2At(DataPointer dp, byte[] b) {
// gets a 2 byte integer off the byte array at index i
dp.align(2);
int i = dp.getPointer();
int x = (b[i] << 8) + (b[i + 1] & 0xff);
dp.incPointer(2);
return x;
}
int getShortAt(DataPointer dp, byte[] b) {
return getInt2At(dp, b);
}
int getLongAt(DataPointer dp, byte[] b) {
return getInt4At(dp, b);
}
String getStringAt(DataPointer dp, byte[] b, int length) {
// gets a string of length 'length' off the byte array at
// index dp
dp.align(1);
int end = dp.getPointer() + length - 1; // Ignore the final
// null
StringBuffer buf = new StringBuffer(length);
for (int j = dp.getPointer(); j < end; j++) {
buf.append((char) b[j]);
}
dp.incPointer(length);
return buf.toString();
}
public static void printUsage() {
System.err.println("usage: java ior [-verbose] [-debug] filename");
}
/*
* bytes 0-3 = 'IOR:' bytes 4-n are hex representation of IOR.
*
*
*/
public static void main(String args[]) {
if (args.length == 0) {
printUsage();
System.exit(1);
}
String filename = null;
// Parse the arguments
for (int a = 0; a < args.length; a++) {
if (args[a].charAt(0) == '-') {
if (args[a].equals("-verbose"))
verbose = true;
else if (args[a].equals("-debug"))
debug = true;
else {
printUsage();
System.exit(1);
}
} else if (filename == null) {
filename = args[a];
} else {
printUsage();
System.exit(1);
}
}
if (verbose || debug) {
System.out.println("-------------------------------------------");
System.out.println("verbose = " + verbose);
System.out.println("debug = " + debug);
System.out.println("filename = " + filename);
System.out.println("-------------------------------------------");
System.out.println();
}
byte[] contents = null;
File f = new File(filename);
try {
FileInputStream fis = new FileInputStream(f);
int nAvail = fis.available();
contents = new byte[nAvail];
/*int length = */fis.read(contents);
fis.close();
new IOR(contents).parse(new PrintWriter(System.out, true));
} catch (java.io.FileNotFoundException e) {
System.err.println("File not found: " + f);
return;
} catch (java.io.IOException e) {
System.err.println("Error reading file " + f);
return;
}
}
/**
* An abstraction of a pointer into a byte array. This pointer
* allows its clients to align the pointer on arbitrary byte
* boundaries, and increment freely.
*
* It is particularly useful in Java where you can't pass
* arguments by reference. By passing a DataPointer, a function
* can align and increment the pointer transparently to its
* clients.
*/
class DataPointer {
int ptr;
boolean debug;
DataPointer() {
ptr = 0;
debug = false;
}
DataPointer(boolean dbg) {
ptr = 0;
debug = dbg;
}
void incPointer(int increment) {
if (debug)
System.out.print("ptr: " + ptr + "+" + increment + " = ");
ptr += increment;
if (debug)
System.out.println(ptr);
}
int getPointer() {
return ptr;
}
void align(int boundary) {
while ((ptr % boundary) != 0) {
if (debug)
System.out.println("ptr: align: " + ptr + ", " + boundary);
ptr++;
}
}
}
}