
org.jinterop.dcom.core.JIVariant Maven / Gradle / Ivy
/** j-Interop (Pure Java implementation of DCOM protocol)
* Copyright (C) 2006 Vikram Roopchand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* Though a sincere effort has been made to deliver a professional,
* quality product,the library itself is distributed WITHOUT ANY WARRANTY;
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
package org.jinterop.dcom.core;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import ndr.NetworkDataRepresentation;
import org.jinterop.dcom.common.JIErrorCodes;
import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.common.JIRuntimeException;
import org.jinterop.dcom.common.JISystem;
import org.jinterop.dcom.impls.automation.IJIDispatch;
/**
* < p>
* Class representing the VARIANT
datatype.
*
* Please use the byRef
flag based constructors for by
* reference
* parameters in COM calls. For [optional]
parameters use the
* {@link #OPTIONAL_PARAM()}
*
* In case of direct calls to COM server using JICallBuilder
, if
* the byRef
flag is set then that variant should also be added as
* the [out]
parameter in the JICallBuilder
. For
* developers using the IJIDispatch
this is not required and
* variant would be returned back to them via JIVariant[]
* associated with IJIDispatch
apis.
*
*
* An important note for Boolean
Arrays
* (JIArray
of Boolean
), please set the
* JIFlag.FLAG_REPRESENTATION_VARIANT_BOOL
using the
* {@link #setFlag(int)} method before making a call on this object. This is
* required since in DCOM , VARIANT_BOOL
are 2 bytes and standard
* boolean
s are 1 byte in length.
*
*
* @since 1.0
*/
public final class JIVariant implements Serializable {
private static final long serialVersionUID = 5101290038004040628L;
private static final class EMPTY {
}
private static final class NULL {
}
private static final class SCODE {
}
public static final int VT_NULL = 0x00000001;
public static final int VT_EMPTY = 0x00000000;
public static final int VT_I4 = 0x00000003;
public static final int VT_UI1 = 0x00000011;
public static final int VT_I2 = 0x00000002;
public static final int VT_R4 = 0x00000004;
public static final int VT_R8 = 0x00000005;
public static final int VT_VARIANT = 0x0000000c;
public static final int VT_BOOL = 0x0000000b;
public static final int VT_ERROR = 0x0000000a;
public static final int VT_CY = 0x00000006;
public static final int VT_DATE = 0x00000007;
public static final int VT_BSTR = 0x00000008;
public static final int VT_UNKNOWN = 0x0000000d;
public static final int VT_DECIMAL = 0x0000000e;
public static final int VT_DISPATCH = 0x00000009;
public static final int VT_ARRAY = 0x00002000;
public static final int VT_BYREF = 0x00004000;
public static final int VT_BYREF_VT_UI1 = VT_BYREF | VT_UI1;//0x00004011;
public static final int VT_BYREF_VT_I2 = VT_BYREF | VT_I2;//0x00004002;
public static final int VT_BYREF_VT_I4 = VT_BYREF | VT_I4;//0x00004003;
public static final int VT_BYREF_VT_R4 = VT_BYREF | VT_R4;//0x00004004;
public static final int VT_BYREF_VT_R8 = VT_BYREF | VT_R8;//0x00004005;
public static final int VT_BYREF_VT_BOOL = VT_BYREF | VT_BOOL;//0x0000400b;
public static final int VT_BYREF_VT_ERROR = VT_BYREF | VT_ERROR;//0x0000400a;
public static final int VT_BYREF_VT_CY = VT_BYREF | VT_CY;//0x00004006;
public static final int VT_BYREF_VT_DATE = VT_BYREF | VT_DATE;//0x00004007;
public static final int VT_BYREF_VT_BSTR = VT_BYREF | VT_BSTR;//0x00004008;
public static final int VT_BYREF_VT_UNKNOWN = VT_BYREF | VT_UNKNOWN;//0x0000400d;
public static final int VT_BYREF_VT_DISPATCH = VT_BYREF | VT_DISPATCH;//0x00004009;
public static final int VT_BYREF_VT_ARRAY = VT_BYREF | VT_ARRAY;//0x00006000;
public static final int VT_BYREF_VT_VARIANT = VT_BYREF | VT_VARIANT;//0x0000400c;
public static final int VT_I1 = 0x00000010;
public static final int VT_UI2 = 0x00000012;
public static final int VT_UI4 = 0x00000013;
public static final int VT_I8 = 0x00000014;
public static final int VT_INT = 0x00000016;
public static final int VT_UINT = 0x00000017;
public static final int VT_BYREF_VT_DECIMAL = VT_BYREF | VT_DECIMAL;//0x0000400e;
public static final int VT_BYREF_VT_I1 = VT_BYREF | VT_I1;//0x00004010;
public static final int VT_BYREF_VT_UI2 = VT_BYREF | VT_UI2;//0x00004012;
public static final int VT_BYREF_VT_UI4 = VT_BYREF | VT_UI4;//0x00004013;
public static final int VT_BYREF_VT_I8 = VT_BYREF | VT_I8;//0x00004014;
public static final int VT_BYREF_VT_INT = VT_BYREF | VT_INT;//0x00004016;
public static final int VT_BYREF_VT_UINT = VT_BYREF | VT_UINT;//0x00004017;
public static final int FADF_AUTO = 0x0001;
/* array is allocated on the stack */
public static final int FADF_STATIC = 0x0002;
/* array is staticly allocated */
public static final int FADF_EMBEDDED = 0x0004;
/* array is embedded in a structure */
public static final int FADF_FIXEDSIZE = 0x0010;
/* may not be resized or reallocated */
public static final int FADF_RECORD = 0x0020;
/* an array of records */
public static final int FADF_HAVEIID = 0x0040;
/* with FADF_DISPATCH, FADF_UNKNOWN */
/* array has an IID for interfaces */
public static final int FADF_HAVEVARTYPE = 0x0080;
/* array has a VT type */
public static final int FADF_BSTR = 0x0100;
/* an array of BSTRs */
public static final int FADF_UNKNOWN = 0x0200;
/* an array of IUnknown* */
public static final int FADF_DISPATCH = 0x0400;
/* an array of IDispatch* */
public static final int FADF_VARIANT = 0x0800;
/* an array of VARIANTs */
public static final int FADF_RESERVED = 0xF008;
/* reserved bits */
static HashMap supportedTypes = new HashMap();
static HashMap supportedTypes_classes = new HashMap();
static HashMap outTypesMap = new HashMap();
static {
//CAUTION NO PTR TYPE SHOULD BE PART OF THIS MAP !!!
outTypesMap.put(int.class, new Integer(0));
outTypesMap.put(Integer.class, new Integer(0));
outTypesMap.put(short.class, new Short((short) 0));
outTypesMap.put(Short.class, new Short((short) 0));
outTypesMap.put(float.class, new Float(0.0));
outTypesMap.put(Float.class, new Float(0.0));
outTypesMap.put(double.class, new Double(0.0));
outTypesMap.put(Double.class, new Double(0.0));
outTypesMap.put(boolean.class, Boolean.FALSE);
outTypesMap.put(Boolean.class, Boolean.FALSE);
outTypesMap.put(String.class, "");
outTypesMap.put(JICurrency.class, new JICurrency("0.0"));
outTypesMap.put(Date.class, new Date());
outTypesMap.put(char.class, new Character('9'));
outTypesMap.put(Character.class, new Character('9'));
outTypesMap.put(JIUnsignedByte.class, JIUnsignedFactory.getUnsigned(new Short((short) 0), JIFlags.FLAG_REPRESENTATION_UNSIGNED_BYTE));
outTypesMap.put(JIUnsignedShort.class, JIUnsignedFactory.getUnsigned(new Integer(0), JIFlags.FLAG_REPRESENTATION_UNSIGNED_SHORT));
outTypesMap.put(JIUnsignedInteger.class, JIUnsignedFactory.getUnsigned(new Long(0), JIFlags.FLAG_REPRESENTATION_UNSIGNED_INT));
outTypesMap.put(long.class, new Long(0));
outTypesMap.put(Long.class, new Long(0));
supportedTypes.put(Object.class, new Integer(VT_VARIANT));
supportedTypes.put(JIVariant.class, new Integer(VT_VARIANT));
supportedTypes.put(Integer.class, new Integer(VT_I4));
supportedTypes.put(JIUnsignedInteger.class, new Integer(VT_UI4));
supportedTypes.put(Float.class, new Integer(VT_R4));
supportedTypes.put(Boolean.class, new Integer(VT_BOOL));
supportedTypes.put(Double.class, new Integer(VT_R8));
supportedTypes.put(Short.class, new Integer(VT_I2));
supportedTypes.put(JIUnsignedShort.class, new Integer(VT_UI2));
supportedTypes.put(Byte.class, new Integer(VT_I1));
supportedTypes.put(Character.class, new Integer(VT_I1));
supportedTypes.put(JIUnsignedByte.class, new Integer(VT_UI1));
supportedTypes.put(JIString.class, new Integer(VT_BSTR));
// supportedTypes.put(IJIUnknown.class,new Integer(VT_UNKNOWN));
// supportedTypes.put(IJIDispatch.class,new Integer(VT_DISPATCH));
supportedTypes.put(JIVariant.SCODE.class, new Integer(VT_ERROR));
supportedTypes.put(JIVariant.EMPTY.class, new Integer(VT_EMPTY));
supportedTypes.put(JIVariant.NULL.class, new Integer(VT_NULL));
supportedTypes.put(VariantBody.SCODE.class, new Integer(VT_ERROR));
supportedTypes.put(VariantBody.EMPTY.class, new Integer(VT_EMPTY));
supportedTypes.put(VariantBody.NULL.class, new Integer(VT_NULL));
supportedTypes.put(JIArray.class, new Integer(VT_ARRAY));
// supportedTypes.put(JIComObjectImpl.class,new Integer(VT_UNKNOWN));
// supportedTypes.put(JIDispatchImpl.class,new Integer(VT_DISPATCH));
supportedTypes.put(Date.class, new Integer(VT_DATE));
supportedTypes.put(JICurrency.class, new Integer(VT_CY));
supportedTypes.put(Long.class, new Integer(VT_I8));
supportedTypes_classes.put(new Integer(VT_DATE), Date.class);
supportedTypes_classes.put(new Integer(VT_CY), JICurrency.class);
supportedTypes_classes.put(new Integer(VT_VARIANT), JIVariant.class);
supportedTypes_classes.put(new Integer(VT_I4), Integer.class);
supportedTypes_classes.put(new Integer(VT_INT), Integer.class);
supportedTypes_classes.put(new Integer(VT_UI4), JIUnsignedInteger.class);
supportedTypes_classes.put(new Integer(VT_UINT), JIUnsignedInteger.class);
supportedTypes_classes.put(new Integer(VT_R4), Float.class);
supportedTypes_classes.put(new Integer(VT_BOOL), Boolean.class);
supportedTypes_classes.put(new Integer(VT_R8), Double.class);
supportedTypes_classes.put(new Integer(VT_I2), Short.class);
supportedTypes_classes.put(new Integer(VT_UI2), JIUnsignedShort.class);
supportedTypes_classes.put(new Integer(VT_I1), Character.class);
supportedTypes_classes.put(new Integer(VT_UI1), JIUnsignedByte.class);
supportedTypes_classes.put(new Integer(VT_BSTR), JIString.class);
supportedTypes_classes.put(new Integer(VT_ERROR), JIVariant.SCODE.class);
supportedTypes_classes.put(new Integer(VT_EMPTY), EMPTY.class);
supportedTypes_classes.put(new Integer(VT_NULL), NULL.class);
supportedTypes_classes.put(new Integer(VT_ARRAY), JIArray.class);
supportedTypes_classes.put(new Integer(VT_UNKNOWN), IJIComObject.class);
supportedTypes_classes.put(new Integer(VT_DISPATCH), IJIComObject.class);
supportedTypes_classes.put(new Integer(VT_I8), Long.class);
//for by ref types, do it at runtime.
}
public static JIVariant OUTPARAMforType(Class c, boolean isArray) {
JIVariant variant = null;
if (!isArray) {
try {
variant = makeVariant(outTypesMap.get(c), true);
} catch (Exception e) {
//eaten and now try from other types
}
if (c.equals(IJIDispatch.class)) {
return OUT_IDISPATCH();
} else if (c.equals(IJIComObject.class)) {
return OUT_IUNKNOWN();
} else if (c.equals(JIVariant.class)) {
return EMPTY_BYREF();
} else if (c.equals(JIString.class)) {
return new JIVariant("", true);
}
} else {
try {
Object oo = outTypesMap.get(c);
if (oo != null) {
//we will always send a single dimension array.
Object x = Array.newInstance(c, 1);
Array.set(x, 0, oo);
variant = new JIVariant(new JIArray(x, true), true);
}
} catch (Exception e) {
//eaten and now try from other types
}
if (c.equals(IJIDispatch.class)) {
IJIComObject[] arry = new IJIComObject[]{new JIComObjectImpl(null, new JIInterfacePointer(null, -1, null))};
variant = new JIVariant(new JIArray(arry, true), true);
variant.setFlag(JIFlags.FLAG_REPRESENTATION_IDISPATCH_NULL_FOR_OUT | JIFlags.FLAG_REPRESENTATION_SET_JIINTERFACEPTR_NULL_FOR_VARIANT);
} else if (c.equals(IJIComObject.class)) {
IJIComObject[] arry = new IJIComObject[]{new JIComObjectImpl(null, new JIInterfacePointer(null, -1, null))};
variant = new JIVariant(new JIArray(arry, true), true);
variant.setFlag(JIFlags.FLAG_REPRESENTATION_IUNKNOWN_NULL_FOR_OUT | JIFlags.FLAG_REPRESENTATION_SET_JIINTERFACEPTR_NULL_FOR_VARIANT);
} else if (c.equals(JIVariant.class)) {
return VARIANTARRAY();
} else if (c.equals(JIString.class) || c.equals(String.class)) {
return BSTRARRAY();
}
}
return variant;
}
/**
* Returns a JIVariant (of the right type) based on the
* o.getClass()
*
* @param o
* @return
*/
public static JIVariant makeVariant(Object o) {
return makeVariant(o, false);
}
/**
* Returns a JIVariant (of the right type) based on the
* o.getClass()
*
* @param o
* @param isByRef
* @return
*/
public static JIVariant makeVariant(Object o, boolean isByRef) {
if (o == null || o.getClass().equals(Object.class)) {
if (isByRef) {
return JIVariant.EMPTY_BYREF();
} else {
return JIVariant.EMPTY();
}
}
Class c = o.getClass();
if (c.isArray()) {
throw new IllegalArgumentException(JISystem.getLocalizedMessage(0x00001029));
}
if (c.equals(JIVariant.class)) {
return new JIVariant((JIVariant) o);
}
try {
Constructor ctor = null;
//now we look at the class and return a JIVariant.
if (c.equals(Boolean.class)) {
ctor = JIVariant.class.getConstructor(new Class[]{boolean.class, boolean.class});
} else if (c.equals(Character.class)) {
ctor = JIVariant.class.getConstructor(new Class[]{char.class, boolean.class});
} else if (c.equals(Byte.class)) {
ctor = JIVariant.class.getConstructor(new Class[]{byte.class, boolean.class});
} else if (c.equals(Short.class)) {
ctor = JIVariant.class.getConstructor(new Class[]{short.class, boolean.class});
} else if (c.equals(Integer.class)) {
ctor = JIVariant.class.getConstructor(new Class[]{int.class, boolean.class});
} else if (c.equals(Long.class)) {
ctor = JIVariant.class.getConstructor(new Class[]{long.class, boolean.class});
} else if (c.equals(Float.class)) {
ctor = JIVariant.class.getConstructor(new Class[]{float.class, boolean.class});
} else if (c.equals(Double.class)) {
ctor = JIVariant.class.getConstructor(new Class[]{double.class, boolean.class});
} else if (o instanceof IJIComObject) {
ctor = JIVariant.class.getConstructor(new Class[]{IJIComObject.class, boolean.class});
} else {
//should cover all the rest cases.
ctor = JIVariant.class.getConstructor(new Class[]{c, boolean.class});
}
return (JIVariant) ctor.newInstance(new Object[]{o, Boolean.valueOf(isByRef)});
} catch (Exception e) {
if (JISystem.getLogger().isLoggable(Level.WARNING)) {
JISystem.getLogger().log(Level.WARNING, "Could not create Variant for {0} , isByRef {1}", new Object[]{o, isByRef});
}
}
return null;
}
static Class getSupportedClass(Integer type) {
return (Class) supportedTypes_classes.get(type);
}
static Integer getSupportedType(Class c, int FLAG) {
Integer retVal = (Integer) supportedTypes.get(c);
if (retVal == null && IJIComObject.class.equals(c)) {
retVal = new Integer(VT_UNKNOWN);
}
if (retVal == null && IJIDispatch.class.equals(c)) {
retVal = new Integer(VT_DISPATCH);
}
//means that if retval came back as VT_I4, we should make that VT_INT
if (retVal.intValue() == VT_I4
&& (FLAG & JIFlags.FLAG_REPRESENTATION_VT_INT) == JIFlags.FLAG_REPRESENTATION_VT_INT) {
retVal = new Integer(VT_INT);
} else if (retVal.intValue() == VT_UI4
&& (FLAG & JIFlags.FLAG_REPRESENTATION_VT_UINT) == JIFlags.FLAG_REPRESENTATION_VT_UINT) {
retVal = new Integer(VT_UINT);
}
return retVal;
}
static Integer getSupportedType(Object o, int defaultType) {
Class c = o.getClass();
Integer retval = (Integer) supportedTypes.get(c);
// Order is important since IJIDispatch derieves from IJIComObject
if (retval == null && o instanceof IJIDispatch) {
retval = new Integer(VT_DISPATCH);
}
if (retval == null && o instanceof IJIComObject) {
retval = new Integer(VT_UNKNOWN);
}
return retval;
}
/**
* EMPTY VARIANT
*/
static final JIVariant EMPTY = new JIVariant(new EMPTY());
/**
* EMPTY VARIANT
. This is not Thread Safe , hence a new
* instance must be taken each time.
*
*/
public static JIVariant EMPTY() {
return new JIVariant(new EMPTY());
}
/**
* EMPTY BYREF VARIANT
*/
static final JIVariant EMPTY_BYREF = new JIVariant(EMPTY);
/**
* EMPTY BYREF VARIANT
. This is not Thread Safe , hence a new
* instance must be taken each time. Used for a [out] VARIANT*
* .
*
*/
public static JIVariant EMPTY_BYREF() {
return new JIVariant(EMPTY());
}
/**
* VARIANT
for ([out] IUnknown*)
. This is not
* Thread Safe , hence a new instance must be taken each time.
*/
public static JIVariant OUT_IUNKNOWN() {
JIVariant retval = new JIVariant(new JIComObjectImpl(null, new JIInterfacePointer(null, -1, null)), true);
retval.setFlag(JIFlags.FLAG_REPRESENTATION_IUNKNOWN_NULL_FOR_OUT | JIFlags.FLAG_REPRESENTATION_SET_JIINTERFACEPTR_NULL_FOR_VARIANT);
return retval;
}
/**
* VARIANT
for ([out] IDispatch*)
. This is not
* Thread Safe , hence a new instance must be taken each time.
*
Note that this must also be used when the interface pointer is a
* subclass of IDispatch
i.e. supports automation (or is a
* dispinterface
).
*/
public static JIVariant OUT_IDISPATCH() {
JIVariant retval = new JIVariant(new JIComObjectImpl(null, new JIInterfacePointer(null, -1, null)), true);
retval.setFlag(JIFlags.FLAG_REPRESENTATION_IDISPATCH_NULL_FOR_OUT | JIFlags.FLAG_REPRESENTATION_SET_JIINTERFACEPTR_NULL_FOR_VARIANT);
return retval;
}
/**
* NULL VARIANT
*/
static final JIVariant NULL = new JIVariant(new NULL());
/**
* NULL VARIANT
. This is not Thread Safe , hence a new
* instance must be taken each time.
*
*/
public static JIVariant NULL() {
return new JIVariant(new NULL());
}
/**
* OPTIONAL PARAM. Pass this when a parameter is optional for a COM api
* call.
*/
static final JIVariant OPTIONAL_PARAM = new JIVariant(JIVariant.SCODE, JIErrorCodes.DISP_E_PARAMNOTFOUND);
/**
* OPTIONAL PARAM. Pass this when a parameter is [optional]
for
* a COM call. This is not Thread Safe , hence a new instance must be taken
* each time.
*
*/
public static JIVariant OPTIONAL_PARAM() {
return new JIVariant(JIVariant.SCODE, JIErrorCodes.DISP_E_PARAMNOTFOUND);
}
/**
* SCODE VARIANT
*/
public static final SCODE SCODE = new SCODE();
/**
* Helper method for creating an array of BSTR
s , IDL signature
* [in, out] SAFEARRAY(BSTR) *p
. The return value can directly
* be used in an IJIDispatch
call.
*
* @return
*/
public static JIVariant BSTRARRAY() {
return new JIVariant(new JIArray(new JIString[]{new JIString("")}, true), true);
}
/**
* Helper method for creating an array of VARIANT
s , IDL
* signature [in, out] SAFEARRAY(VARIANT) *p
OR
* [in,out] VARIANT *pArray
. The return value can directly be
* used in an IJIDispatch
call.
*
* @return
*/
public static JIVariant VARIANTARRAY() {
return new JIVariant(new JIArray(new JIVariant[]{JIVariant.EMPTY()}, true), true);
}
JIPointer member = null;
private JIVariant() {
}
//The class of the object determines its type.
// /**
// * Setting up a VARIANT
with an object. Used via serializing the VARIANT
.
// *
// * @param obj
// */
private void init(Object obj) {
init(obj, false);
}
// /** For internal use only !. Please do not call this directly from outside. It will lead to unexpected results.
// *
// * @exclude
// * @param obj
// * @param isByRef
// */
// public JIVariant(Object obj, boolean isByRef)
// {
// init(obj,isByRef);
// }
private void init(Object obj, boolean isByRef) {
if (obj != null && obj.getClass().isArray()) {
throw new IllegalArgumentException(JISystem.getLocalizedMessage(JIErrorCodes.JI_VARIANT_ONLY_JIARRAY_EXCEPTED));
}
if (obj != null && obj.getClass().equals(JIInterfacePointer.class)) {
throw new IllegalArgumentException(JISystem.getLocalizedMessage(JIErrorCodes.JI_VARIANT_TYPE_INCORRECT));
}
//this case comes only for SCODE and EMPTY, and in these cases the isByRef flag will be set in the
//previous call itself.
if (obj instanceof VariantBody) {
member = new JIPointer(obj);
} else {
VariantBody variantBody = new VariantBody(obj, isByRef);
member = new JIPointer(variantBody);
// if (obj != null && obj instanceof JIVariant)
// {
// VariantBody var = (VariantBody)((JIVariant)obj).member.getReferent();
// try {
// variantBody.variantType = var.getVariantType() + 3 + 1;
// } catch (JIException e) {
// throw new JIRuntimeException(e.getErrorCode());
// }
// }
}
member.setReferent(0x72657355);//"User" in LEndian.
}
/**
* Called when this variant is nested
*
* @param deffered
*/
void setDeffered(boolean deffered) {
if (member != null && !member.isReference()) {
member.setDeffered(deffered);
}
}
/**
* Sets a JIFlags
value to be used while encoding (marshalling)
* this Variant.
*
* @param FLAG
*/
public void setFlag(int FLAG) {
VariantBody variantBody = ((VariantBody) member.getReferent());
variantBody.FLAG |= FLAG;
}
/**
* Returns the flag value for this variant.
*
* @return
*/
public int getFlag() {
VariantBody variantBody = ((VariantBody) member.getReferent());
return variantBody.FLAG;
}
/**
* Returns whether this variant is a NULL
variant.
*
* @return true
if the variant is a NULL
*/
public boolean isNull() {
if (member == null) {
return true;
}
VariantBody variantBody = ((VariantBody) member.getReferent());
return variantBody == null ? true : variantBody.isNull();
}
/**
* Setting up a VARIANT
as reference to another. Used via
* serializing the VARIANT
.
*
* @param variant
*/
public JIVariant(JIVariant variant) {
init(variant, true);
}
/**
* Setting up a VARIANT
with an int
. Used via
* serializing the VARIANT
. Used when the variant type is
* VT_I4.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. LONG*
*/
public JIVariant(int value, boolean isByRef) {
init(new Integer(value), isByRef);
}
/**
* Setting up a VARIANT
with a long
. Used via
* serializing the VARIANT
. Used when the variant type is
* VT_I8.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer.
*/
public JIVariant(long value, boolean isByRef) {
init(new Long(value), isByRef);
}
/**
* Setting up a VARIANT
with a float
. Used via
* serializing the VARIANT
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. FLOAT*
*/
public JIVariant(float value, boolean isByRef) {
init(new Float(value), isByRef);
}
/**
* Setting up a VARIANT
with a boolean
. Used via
* serializing the VARIANT
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. VARIANT_BOOL*
*/
public JIVariant(boolean value, boolean isByRef) {
init(Boolean.valueOf(value), isByRef);
}
/**
* Setting up a VARIANT
with a double
. Used via
* serializing the VARIANT
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. DOUBLE*
*/
public JIVariant(double value, boolean isByRef) {
init(new Double(value), isByRef);
}
/**
* Setting up a VARIANT
with a short
. Used via
* serializing the VARIANT
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. SHORT*
*/
public JIVariant(short value, boolean isByRef) {
init(new Short(value), isByRef);
}
/**
* Setting up a VARIANT
with a char
. Used via
* serializing the VARIANT
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. CHAR*
*/
public JIVariant(char value, boolean isByRef) {
init(new Character(value), isByRef);
}
/**
* Setting up a VARIANT
with a JIString
. Used via
* serializing the VARIANT
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. BSTR*
*/
public JIVariant(JIString value, boolean isByRef) {
init(value, isByRef);
}
/**
* Setting up a VARIANT
with a String
. Used via
* serializing the VARIANT
. Internally a JIString
* is formed with it's default type BSTR
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. BSTR*
*/
public JIVariant(String value, boolean isByRef) {
init(new JIString(value), isByRef);
}
/**
* Setting up a VARIANT
with a String
. Used via
* serializing the VARIANT
. Internally a JIString
* is formed with it's default type BSTR
.
*
* @param value
*/
public JIVariant(String value) {
this(new JIString(value));
}
// /**Setting up a VARIANT
with a IJIDispatch. Used via serializing the VARIANT
.
// *
// * @param value
// * @param isByRef true if the value is to be represented as a pointer. IJIDispatch**
// */
// public JIVariant(IJIDispatch value, boolean isByRef)
// {
// this((Object)value,isByRef);
// }
/**
* Setting up a VARIANT
with an IJIComObject
. Used
* via serializing the VARIANT
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. IJIComObject**
*/
public JIVariant(IJIComObject value, boolean isByRef) {
init(value, isByRef);
if (value instanceof IJIDispatch) {
setFlag(JIFlags.FLAG_REPRESENTATION_USE_IDISPATCH_IID);
} else {
setFlag(JIFlags.FLAG_REPRESENTATION_USE_IUNKNOWN_IID);
}
}
/**
* Setting up a VARIANT
with a SCODE
value and
* it's errorCode
. Used via serializing the
* VARIANT
.
*
*
* @param value
* @param errorCode
* @param isByRef true
if the value is to be represented as a
* pointer. SCODE*
*/
public JIVariant(SCODE value, int errorCode, boolean isByRef) {
init(new VariantBody(VariantBody.SCODE, errorCode, isByRef), isByRef);
}
/**
* Setting up a VARIANT
with an int
. Used via
* serializing the VARIANT
.
*
* @param value
*/
public JIVariant(int value) {
this(value, false);
}
/**
* Setting up a VARIANT
with a float
. Used via
* serializing the VARIANT
.
*
* @param value
*/
public JIVariant(float value) {
this(value, false);
}
/**
* Setting up a VARIANT
with a boolean
. Used via
* serializing the VARIANT
.
*
* @param value
*/
public JIVariant(boolean value) {
this(value, false);
}
/**
* Setting up a VARIANT
with a double
. Used via
* serializing the VARIANT
.
*
* @param value
*/
public JIVariant(double value) {
this(value, false);
}
/**
* Setting up a VARIANT
with a short
. Used via
* serializing the VARIANT
.
*
* @param value
*/
public JIVariant(short value) {
this(value, false);
}
/**
* Setting up a VARIANT
with a char
. Used via
* serializing the VARIANT
.
*
* @param value
*/
public JIVariant(char value) {
this(value, false);
}
/**
* Setting up a VARIANT
with a JIString
. Used via
* serializing the VARIANT
.
*
* @param value
*/
public JIVariant(JIString value) {
this(value, false);
}
// /**Setting up a VARIANT
with a IJIDispatch. Used via serializing the VARIANT
.
// *
// * @param value
// */
// public JIVariant(IJIDispatch value)
// {
// this((Object)value);
// }
/**
* Setting up a VARIANT
with an IJIComObject
. Used
* via serializing the VARIANT
.
*
* @param value
*/
public JIVariant(IJIComObject value) {
this(value, false);
if (value instanceof IJIDispatch) {
setFlag(JIFlags.FLAG_REPRESENTATION_USE_IDISPATCH_IID);
} else {
setFlag(JIFlags.FLAG_REPRESENTATION_USE_IUNKNOWN_IID);
}
}
/**
* Setting up a VARIANT
with an java.util.Date
.
* Used via serializing the VARIANT
.
*
* @param value
*/
public JIVariant(Date value) {
this(value, false);
}
/**
* Setting up a VARIANT
with an java.util.Date
.
* Used via serializing the VARIANT
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. Date*
*/
public JIVariant(Date value, boolean isByRef) {
init(value, isByRef);
}
/**
* Setting up a VARIANT
with a JICurrency
. Used
* via serializing the VARIANT
.
*
* @param value
*/
public JIVariant(JICurrency value) {
this(value, false);
}
/**
* Setting up a VARIANT
with a JICurrency
. Used
* via serializing the VARIANT
.
*
* @param value
* @param isByRef true
if the value is to be represented as a
* pointer. JICurrency*
*/
public JIVariant(JICurrency value, boolean isByRef) {
init(value, isByRef);
}
/**
* Setting up a VARIANT
with an EMPTY
value. Used
* via serializing the VARIANT
.
*
* @param value
*/
private JIVariant(EMPTY value) {
init(null);
}
/**
* Setting up a VARIANT
with a NULL
value. Used
* via serializing the VARIANT
.
*
* @param value
*/
private JIVariant(NULL value) {
init(new VariantBody(VariantBody.NULL));
}
/**
* Setting up a VARIANT
with a SCODE
value and
* it's errorCode
. Used via serializing the
* VARIANT
.
*
* @param value
* @param errorCode
*/
public JIVariant(SCODE value, int errorCode) {
init(new VariantBody(VariantBody.SCODE, errorCode, false));
}
/**
* Setting up a VARIANT
with a JIArray
. Used via
* serializing the VARIANT
. Only 1 and 2 dimensional array is
* supported.
*
* @param array
* @param FLAG JIFlag value
*/
public JIVariant(JIArray array, int FLAG) {
this(array, false, FLAG);
}
/**
* Setting up a VARIANT
with a JIArray
. Used via
* serializing the VARIANT
. Only 1 and 2 dimensional array is
* supported.
*
* @param array
* @param isByRef
* @param FLAG JIFlag value
*/
public JIVariant(JIArray array, boolean isByRef, int FLAG) {
initArrays(array, isByRef, FLAG);
}
/**
* Setting up a VARIANT
with a JIArray
. Used via
* serializing the VARIANT
. Only 1 and 2 dimensional array is
* supported.
*
* @param array
* @param isByRef
*/
public JIVariant(JIArray array, boolean isByRef) {
initArrays(array, isByRef, JIFlags.FLAG_NULL);
}
private final static List arryInits = new ArrayList();
static {
arryInits.add(JIString.class);
arryInits.add(JIPointer.class);
// arryInits.add(JIComObjectImpl.class);
// arryInits.add(JIDispatchImpl.class);
// arryInits.add(IJIUnknown.class);
arryInits.add(IJIComObject.class);
arryInits.add(IJIDispatch.class); //this can only happen in case of an array
}
private void initArrays(JIArray array, boolean isByRef, int FLAG) {
VariantBody variant2 = null;
JIArray array2 = null;
Class c = null;
Object[] newArrayObj = null;
boolean is2Dim = false;
if (array == null) {
init(null, false);
return;
}
switch (array.getDimensions()) {
case 1:
Object[] obj = (Object[]) array.getArrayInstance();
newArrayObj = obj;
c = obj.getClass().getComponentType();
break;
case 2:
/* The 2 dimensional array is serialized like this first the index [0,0] and then [1,0] then [0,1] then [1,1], then [0,2] then [1,2]
* and so on . so what i will do here is that create a single dimension flat array of the members in the order specified above, after examining this Object[][] and let the
* 1 dimension serializing logic take over. */
Object[][] obj2 = (Object[][]) array.getArrayInstance();
//variants = new JIVariant[array.getNumElementsInAllDimensions()];
String name = obj2.getClass().getName();
Object subArray = obj2;
name = name.substring(1);
int firstDim = ((Object[]) subArray).length;
subArray = Array.get(subArray, 0);
int secondDim = ((Object[]) subArray).length;
int k = 0;
newArrayObj = (Object[]) Array.newInstance(subArray.getClass().getComponentType(), array.getNumElementsInAllDimensions());
for (int i = 0; i < secondDim; i++) {
for (int j = 0; j < firstDim; j++) {
newArrayObj[k++] = obj2[j][i];
}
}
c = subArray.getClass().getComponentType();
is2Dim = true;
break;
default:
throw new IllegalArgumentException(JISystem.getLocalizedMessage(JIErrorCodes.JI_VARIANT_VARARRAYS_2DIMRES));
}
array2 = new JIArray(newArrayObj, true); //should always be conformant since this is part of a safe array.
JIStruct safeArray = new JIStruct();
try {
safeArray.addMember(new Short((short) array.getDimensions()));//dim
int elementSize = -1;
short flags = JIVariant.FADF_HAVEVARTYPE;
if (c.equals(JIVariant.class)) {
flags = (short) (flags | JIVariant.FADF_VARIANT);
elementSize = 16; //(Variant is pointer whose size is 16)
} else if (arryInits.contains(c)) {
if (c.equals(JIString.class)) {
flags = (short) (flags | JIVariant.FADF_BSTR);
} else if (c.equals(IJIComObject.class)) {
flags = (short) (flags | JIVariant.FADF_UNKNOWN);
FLAG |= JIFlags.FLAG_REPRESENTATION_USE_IUNKNOWN_IID;
} else if (c.equals(IJIDispatch.class)) {
flags = (short) (flags | JIVariant.FADF_DISPATCH);
FLAG |= JIFlags.FLAG_REPRESENTATION_USE_IDISPATCH_IID;
}
elementSize = 4; //Since all these are pointers inherently
} else {
//JStruct and JIUnions are expected to be encapsulated within pointers...they usually are :)
elementSize = JIMarshalUnMarshalHelper.getLengthInBytes(c, null, c == Boolean.class ? JIFlags.FLAG_REPRESENTATION_VARIANT_BOOL : JIFlags.FLAG_NULL); //All other types, basic types
}
JIStruct safeArrayBound = null;
int upperBounds[] = array.getUpperBounds();
JIStruct[] arrayOfSafeArrayBounds = new JIStruct[array.getDimensions()];
for (int i = 0; i < array.getDimensions(); i++) {
safeArrayBound = new JIStruct();
safeArrayBound.addMember(new Integer(upperBounds[i]));
safeArrayBound.addMember(new Integer(0)); //starts at 0
arrayOfSafeArrayBounds[i] = safeArrayBound;
}
JIArray arrayOfSafeArrayBounds2 = new JIArray(arrayOfSafeArrayBounds, true);
safeArray.addMember(new Short(flags));//flags
if (elementSize > 0) {
safeArray.addMember(new Integer(elementSize));
} else {
elementSize = JIMarshalUnMarshalHelper.getLengthInBytes(c, null, FLAG);
safeArray.addMember(new Integer(elementSize));//size
}
safeArray.addMember(new Short((short) 0));//locks
safeArray.addMember(new Short(JIVariant.getSupportedType(c, FLAG).shortValue()));//variant array, safearrayunion
//peculiarity here, windows seems to be sending the signed type in VarType32...
if (c.equals(JIUnsignedByte.class)) {
safeArray.addMember(JIVariant.getSupportedType(Byte.class, FLAG));//safearrayunion
} else if (c.equals(JIUnsignedShort.class)) {
safeArray.addMember(JIVariant.getSupportedType(Short.class, FLAG));//safearrayunion
} else if (c.equals(JIUnsignedInteger.class)) {
safeArray.addMember(JIVariant.getSupportedType(Integer.class, FLAG));//safearrayunion
} else if (c.equals(Boolean.class)) {
safeArray.addMember(JIVariant.getSupportedType(Short.class, FLAG));//safearrayunion
} else if (c.equals(Double.class)) {
safeArray.addMember(JIVariant.getSupportedType(Long.class, FLAG));//safearrayunion
} else if (c.equals(Float.class)) {
safeArray.addMember(JIVariant.getSupportedType(Integer.class, FLAG));//safearrayunion
} else {
safeArray.addMember(JIVariant.getSupportedType(c, FLAG));//safearrayunion
}
safeArray.addMember(new Integer(array2.getNumElementsInAllDimensions()));//size in safearrayunion
JIPointer ptr2RealArray = new JIPointer(array2);
safeArray.addMember(ptr2RealArray);
safeArray.addMember(arrayOfSafeArrayBounds2);
} catch (JIException e) {
throw new JIRuntimeException(e.getErrorCode());
}
variant2 = new VariantBody(safeArray, c, is2Dim, isByRef, FLAG);
init(variant2, false);
}
/**
* Setting up a VARIANT
with a JIArray
. Used via
* serializing the VARIANT
.
* Only 1 and 2 dimensional array is supported.
*
* @param array
*/
public JIVariant(JIArray array) {
this(array, false);
}
/**
* Setting up a VARIANT
with a unsigned
value.
* Used via serializing the VARIANT
.
*
* @param number
*/
public JIVariant(IJIUnsigned number) {
init(number);
}
/**
* Setting up a VARIANT
with a unsigned
value.
* Used via serializing the VARIANT
.
*
* @param number
* @param isByRef true
if the value is to be represented as a
* pointer.
*/
public JIVariant(IJIUnsigned number, boolean isByRef) {
init(number, isByRef);
}
/**
* Returns the contained object.
*
* @return
* @throws JIException
*/
public Object getObject() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObject();
}
/**
* Retrieves the contained object as int
.
*
* @return
* @throws JIException
*/
public int getObjectAsInt() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsInt();
}
/**
* Retrieves the contained object as float
.
*
* @return
* @throws JIException
*/
public float getObjectAsFloat() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsFloat();
}
/**
* Retrieves the contained objects errorCode.
*
* @return
* @throws JIException
*/
public int getObjectAsSCODE() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsSCODE();
}
/**
* Retrieves the contained object as double
.
*
* @return
* @throws JIException
*/
public double getObjectAsDouble() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsDouble();
}
/**
* Retrieves the contained object as short
.
*
* @return
* @throws JIException
*/
public short getObjectAsShort() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsShort();
}
/**
* Retrieves the contained object as boolean
.
*
* @return
* @throws JIException
*/
public boolean getObjectAsBoolean() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsBoolean();
}
/**
* Retrieves the contained object as JIString
.
*
* @return
* @throws JIException
*/
public JIString getObjectAsString() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsString();
}
/**
* Retrieves the contained object as String
.
*
* @return
* @throws JIException
*/
public String getObjectAsString2() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsString().getString();
}
/**
* Retrieves the contained object as java.util.Date
.
*
* @return
* @throws JIException
*/
public Date getObjectAsDate() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsDate();
}
/**
* Retrieves the contained object as char
.
*
* @return
* @throws JIException
*/
public char getObjectAsChar() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsChar();
}
// /**Retrieves the contained object as JIInterfacePointer.
// *
// * @return
// * @throws JIException
// * @deprecated Please use getObjectAsComObject instead.
// */
// public JIInterfacePointer getObjectAsInterfacePointer() throws JIException
// {
// checkValidity();
// return ((VariantBody)member.getReferent()).getObjectAsInterfacePointer();
// }
// /**Retrieves the contained object as IJIComObject. Return value can be safely typecasted to the expected type. for e.g. :- If expected type is an IJIDispatch ,
// * then the return value can be safely type casted to it.
// *
// * @param template IJIComObject
whose basic parameters such as JIComServer
will be used while creating the new Instance.
// * @return
// * @throws JIException
// * @deprecated
// */
// public IJIComObject getObjectAsComObject(IJIComObject template) throws JIException
// {
// checkValidity();
// return JIObjectFactory.createCOMInstance(template,((VariantBody)member.getReferent()).getObjectAsInterfacePointer());
// }
/**
* Retrieves the contained object as IJIComObject
. Return value
* must be "narrowed" to get the expected type.
*
* for example :- If expected type is an IJIDispatch
, then the
* return value must pass through
* JIObjectFactory.narrowInstance(IJIComObject)
to get to the
* right type.
*
* @return
* @throws JIException
*/
public IJIComObject getObjectAsComObject() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsComObject();
}
/**
* Retrieves the contained object as JIVariant
.
*
* @return
* @throws JIException
*/
public JIVariant getObjectAsVariant() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsVariant();
}
/**
* Retrieves the contained object as JIArray
. Only 1 and 2 dim
* arrays are supported currently. Please note that this array is not
* backed by this variant and is a new copy. If the array is
* IJIComObject
s, please make sure to use
* JIObjectFactory.narrowObject()
to get the right instance.
*
* @return
* @throws JIException
*/
public JIArray getObjectAsArray() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getArray();
}
/**
* Retrieves the contained object as long
, used when the
* expected type is VT_I8.
*
* @return
* @throws JIException
*/
public long getObjectAsLong() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsLong();
}
/**
* Retrieves the contained object as unsigned
number.
*
* @return
* @throws JIException
*/
public IJIUnsigned getObjectAsUnsigned() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getObjectAsUnsigned();
}
void encode(NetworkDataRepresentation ndr, List defferedPointers, int FLAG) {
member.setDeffered(true);//this is since this could be part of an array or a struct...for normal calls
//as soon as this call finishes a call will be given from JICallobject for it's variantbody.
JIMarshalUnMarshalHelper.serialize(ndr, member.getClass(), member, defferedPointers, FLAG);
}
static JIVariant decode(NetworkDataRepresentation ndr, List defferedPointers, int FLAG, Map additionalData) {
JIVariant variant = new JIVariant();
JIPointer ref = new JIPointer(VariantBody.class);
ref.setDeffered(true);//this is since this could be part of an array or a struct...for normal calls
//as soon as this call finishes a call will be given from JICallobject for it's variantbody.
variant.member = (JIPointer) JIMarshalUnMarshalHelper.deSerialize(ndr, ref, defferedPointers, FLAG, additionalData);
return variant;
}
public boolean isArray() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).isArray();
}
int getLengthInBytes(int FLAG) throws JIException {
checkValidity();
return JIMarshalUnMarshalHelper.getLengthInBytes(member.getClass(), member, FLAG);
}
public boolean isByRefFlagSet() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).isByRef();
}
/**
* Returns the referent as integer. This can be used along with the
* JIVariant.VT_XX
flags to find out the type of the
* referent.
*
* For example :-
*
*
* switch(variant.getType())
* {
* case JIVariant.VT_VARIANT: value = variant.getObjectAsVariant();
* break;
* case JIVariant.VT_NULL: ...
* break;
* }
*
*
* @return
* @throws JIException
*/
public int getType() throws JIException {
checkValidity();
return ((VariantBody) member.getReferent()).getType();
}
private void checkValidity() throws JIException {
if (member == null || member.isNull()) {
throw new JIException(JIErrorCodes.JI_VARIANT_IS_NULL);
}
}
@Override
public String toString() {
return member == null ? "[null]" : "[" + member.toString() + "]";
}
}
class VariantBody implements Serializable {
private static final long serialVersionUID = -8484108480626831102L;
public static final short VT_PTR = 0x1A;
public static final short VT_SAFEARRAY = 0x1B;
public static final short VT_CARRAY = 0x1C;
public static final short VT_USERDEFINED = 0x1D;
static final class EMPTY {
}
static final class NULL {
}
static final class SCODE {
private int errorCode;
private SCODE() {
}
private SCODE(int errorCode) {
this.errorCode = errorCode;
}
}
/**
* EMPTY VARIANT
*/
public static final EMPTY EMPTY = new EMPTY();
/**
* NULL VARIANT
*/
public static final NULL NULL = new NULL();
/**
* SCODE VARIANT
*/
public static final SCODE SCODE = new SCODE();
private boolean is2Dimensional = false;
private Object obj = null;
private int type = -1;
//private JIArray objArray = null;
private JIStruct safeArrayStruct = null;
private boolean isArray = false;
private boolean isScode = false;
private boolean isNull = false;
private Class nestedArraysRealClass = null;
private static ArrayList type3 = new ArrayList();
private boolean isByRef = false;
int FLAG = JIFlags.FLAG_NULL;
// int variantType = 0x1d; //base jump
static {
type3.add(Integer.class);
type3.add(Short.class);
type3.add(Float.class);
type3.add(Boolean.class);
type3.add(Character.class);
type3.add(Byte.class);
type3.add(EMPTY.class);
type3.add(NULL.class);
type3.add(SCODE.class);
type3.add(JIUnsignedByte.class);
type3.add(JIUnsignedShort.class);
type3.add(JIUnsignedInteger.class);
}
boolean isByRef() {
return isByRef;
}
boolean isNull() {
return isNull;
}
int getType() {
return isArray ? JIVariant.VT_ARRAY | type : type;
}
//The class of the object determines its type.
/**
* Setting up a VARIANT
with an object. Used via serializing
* the VARIANT
.
*
* @param referent
*/
VariantBody(Object referent, boolean isByRef) {
this(referent, isByRef, -1);
}
private VariantBody(Object referent, boolean isByRef, int dataType) {
this.obj = referent == null ? VariantBody.EMPTY : referent;
if (obj instanceof JIString && ((JIString) obj).getType() != JIFlags.FLAG_REPRESENTATION_STRING_BSTR) {
throw new JIRuntimeException(JIErrorCodes.JI_VARIANT_BSTR_ONLY);
}
if (obj instanceof Boolean) {
FLAG = JIFlags.FLAG_REPRESENTATION_VARIANT_BOOL;
}
this.isByRef = isByRef;
// variantType = getMaxLength(this.obj.getClass(),isByRef,obj);
//for an unsupported type this could be null
//but then this is my bug, any thread entering this ctor , will support a type.
Integer types = JIVariant.getSupportedType(obj, dataType);
if (types != null) {
type = types.intValue() | (isByRef ? JIVariant.VT_BYREF : 0);
} else {
throw new JIRuntimeException(JIErrorCodes.JI_VARIANT_UNSUPPORTED_TYPE);
}
// if (JISystem.getLogger().isLoggable(Level.INFO))
// {
// JISystem.getLogger().info("In VariantBody(Object,boolean,int) : dataType is " + dataType + " , referent class is " + this.obj.getClass() + " , byRef is " + isByRef);
// }
if (dataType == JIVariant.VT_NULL) {
isNull = true;
obj = new Integer(0);
}
}
/**
* Setting up a VARIANT
with a NULL value. Used via serializing
* the VARIANT
.
*
* @param value
*/
VariantBody(NULL value) {
this(new Integer(0), false);
isNull = true;
type = JIVariant.VT_NULL;
}
/**
* Setting up a VARIANT
with a SCODE value and it's errorCode.
* Used via serializing the VARIANT
.
*
* @param value
* @param errorCode
*/
VariantBody(SCODE value, int errorCode, boolean isByRef) {
this(new Integer(errorCode), isByRef);
isScode = true;
type = JIVariant.VT_ERROR;
}
VariantBody(JIStruct safeArray, Class nestedClass, boolean is2Dimensional, boolean isByRef, int FLAG) {
this.FLAG = FLAG;
//can't convert the array here , since this will have deffered pointers which may not be complete.
safeArrayStruct = safeArray;
isArray = true;
if (safeArrayStruct == null) {
isNull = true;
}
this.nestedArraysRealClass = nestedClass;
this.is2Dimensional = is2Dimensional;
//please remember JIVariant is a pointer and VariantBody is just the referent part of that.
//for an unsupported type this could be null
//but then this is my bug, any thread entering this ctor , will support a type.
this.isByRef = isByRef;
Integer types = JIVariant.getSupportedType(nestedClass, FLAG);
if (types != null) {
type = types.intValue() | (isByRef ? JIVariant.VT_BYREF : 0);
} else {
throw new JIRuntimeException(JIErrorCodes.JI_VARIANT_UNSUPPORTED_TYPE);
}
}
// VariantBody(JIArray obj, Class nestedClass, boolean is2Dimensional,boolean isByRef)
// {
//
// this.objArray = obj;
// isArray = true;
// this.nestedArraysRealClass = nestedClass;
// this.is2Dimensional = is2Dimensional;
// //please remember JIVariant is a pointer and VariantBody is just the referent part of that.
//
//
// //for an unsupported type this could be null
// //but then this is my bug, any thread entering this ctor , will support a type.
// this.isByRef = isByRef;
// Integer types = ((Integer)JIVariant.supportedTypes.get(obj.getClass()));
// if (types != null)
// {
// type = types.intValue() | (isByRef ? JIVariant.VT_BYREF:0);
// }
//
// }
/**
* Returns the contained object.
*
* @return
*/
Object getObject() throws JIException {
return obj == null ? getArray() : obj;
}
JIArray getArray() throws JIException {
JIArray retVal = null;
//TODO convert it to the right type based on the variantType before returning it.
//everything is sent encapsulated in a variant(in safearray) , so an Integer[] will
//go as a variant array for each integer, only the variantType = arry of ints. so convert the
//array in the right format before returning it to the user. That is he must get Int[] within a JIArray
//back.
if (safeArrayStruct != null) {
retVal = (JIArray) ((JIPointer) safeArrayStruct.getMember(7)).getReferent();
if (is2Dimensional) {
Object[] obj3 = (Object[]) retVal.getArrayInstance(); //these will all be variants
//correct the array here , i.e reform the 2 dimensional array before returning back.
JIArray safeArrayBound = (JIArray) safeArrayStruct.getMember(8);
JIStruct[] safeArrayBound2 = (JIStruct[]) safeArrayBound.getArrayInstance();
//should only be 2 since we support only 2 dim.
int firstDim = ((Number) safeArrayBound2[0].getMember(0)).intValue();
int secondDim = ((Number) safeArrayBound2[1].getMember(0)).intValue();
Object obj = Array.newInstance(nestedArraysRealClass, new int[]{firstDim, secondDim});
Object[][] obj2 = (Object[][]) obj;
int k = 0;
for (int i = 0; i < secondDim; i++) {
for (int j = 0; j < firstDim; j++) {
// if (nestedArraysRealClass == JIVariant.class)
// {
// obj2[j][i] = ((JIVariant[])obj3)[k++];
// }
// else
// {
// obj2[j][i] = ((JIVariant[])obj3)[k++].getObject();
// }
obj2[j][i] = obj3[k++];
}
}
retVal = new JIArray(obj2);
} else {
if (nestedArraysRealClass != null) {
Object[] obj = (Object[]) retVal.getArrayInstance(); //these will all be variants
Object obj2 = Array.newInstance(nestedArraysRealClass, obj.length);
System.arraycopy(obj, 0, (Object[]) obj2, 0, obj.length);// if (nestedArraysRealClass == JIVariant.class)
// {
// Array.set(obj2,i,((JIVariant[])obj)[i]);//should be the native type
// }
// else
// {
// Array.set(obj2,i,((JIVariant[])obj)[i].getObject());//should be the native type
// }
//Array.set(obj2,i,obj[i]);
retVal = new JIArray(obj2);
} else {
throw new JIException(JIErrorCodes.JI_VARIANT_UNSUPPORTED_TYPE);
}
}
}
return retVal;
}
/**
* Retrieves the contained object as int.
*
* @return
*/
int getObjectAsInt() {
try {
return ((Number) obj).intValue();
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
long getObjectAsLong() {
try {
return ((Number) obj).longValue();
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
IJIUnsigned getObjectAsUnsigned() {
try {
return ((IJIUnsigned) obj);
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
int getObjectAsSCODE() {
try {
return ((SCODE) obj).errorCode;
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
/**
* Retrieves the contained object as float.
*
* @return
*/
float getObjectAsFloat() {
try {
return ((Number) obj).floatValue();
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
/**
* Retrieves the contained object as double.
*
* @return
*/
double getObjectAsDouble() {
try {
return ((Number) obj).doubleValue();
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
/**
* Retrieves the contained object as short.
*
* @return
*/
short getObjectAsShort() {
try {
return ((Number) obj).shortValue();
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
/**
* Retrieves the contained object as boolean.
*
* @return
*/
boolean getObjectAsBoolean() {
try {
return ((Boolean) obj).booleanValue();
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
/**
* Retrieves the contained object as JIString.
*
* @return
*/
JIString getObjectAsString() {
try {
return ((JIString) obj);
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
/**
* Retrieves the contained object as Date.
*
* @return
*/
Date getObjectAsDate() {
try {
return ((Date) obj);
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
/**
* Retrieves the contained object as char.
*
* @return
*/
char getObjectAsChar() {
try {
return ((Character) obj).charValue();
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
/**
* Retrieves the contained object as Variant.
*
* @return
*/
JIVariant getObjectAsVariant() {
try {
return ((JIVariant) obj);
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
IJIComObject getObjectAsComObject() {
try {
return ((IJIComObject) obj);
} catch (ClassCastException e) {
throw new IllegalStateException(e.getMessage());
}
}
void encode(NetworkDataRepresentation ndr, List defferedPointers, int FLAG) {
// try
{
FLAG |= this.FLAG;
//align with 8 boundary
double index = new Integer(ndr.getBuffer().getIndex()).doubleValue();
if (index % 8.0 != 0) {
long i = (i = Math.round(index % 8.0)) == 0 ? 0 : 8 - i;
ndr.writeOctetArray(new byte[(int) i], 0, (int) i);
}
int start = ndr.getBuffer().getIndex();
// if (safeArrayStruct != null)
// {
// //length for the array
// length = fillArrayType(ndr);
// }
// else
// {
// ndr.writeUnsignedLong(variantType);
// }
//just a place holder for length
ndr.writeUnsignedLong(0xFFFFFFFF);
ndr.writeUnsignedLong(0);
//Type
int varType = getVarType(obj != null ? obj.getClass() : nestedArraysRealClass, obj);
//For IUnknown , since the inner object is a JIComObjectImpl it will be fine.
if ((FLAG & JIFlags.FLAG_REPRESENTATION_IDISPATCH_NULL_FOR_OUT) == JIFlags.FLAG_REPRESENTATION_IDISPATCH_NULL_FOR_OUT) {
varType = isByRef ? 0x4000 | JIVariant.VT_DISPATCH : JIVariant.VT_DISPATCH;
}
ndr.writeUnsignedShort(varType);
//reserved bytes
ndr.writeUnsignedSmall(0xCC);
ndr.writeUnsignedSmall(0xCC);
ndr.writeUnsignedSmall(0xCC);
ndr.writeUnsignedSmall(0xCC);
ndr.writeUnsignedSmall(0xCC);
ndr.writeUnsignedSmall(0xCC);
if (obj != null) {
ndr.writeUnsignedLong(varType);
} else {
if (!isByRef) {
ndr.writeUnsignedLong(JIVariant.VT_ARRAY);
} else {
ndr.writeUnsignedLong(JIVariant.VT_BYREF_VT_ARRAY);
}
}
if (isByRef) {
int flag = -1;
if (isArray) //object arrays will come here....
{
flag = 4;
} else {
//no idea what these flags are but 0x10 is for variant, 0x8 for date, and 0x4 is for others
switch (type) {
case JIVariant.VT_BYREF_VT_VARIANT:
flag = 0x10;
break;
case JIVariant.VT_BYREF_VT_DATE:
case JIVariant.VT_BYREF_VT_CY:
flag = 8;
break;
default:
flag = 4;
}
}
ndr.writeUnsignedLong(flag);
}
//we should not use the deffered pointers here, but pass our own one, so that only they are written...
List varDefferedPointers = new ArrayList();
//we should use FLAG here, since the decision should be based on this only.
setValue(ndr, obj, varDefferedPointers, FLAG);
//making changes to write the deffered pointers here itself , since we need to put the entire Variant completed to the length
//as in varType.
int x = 0;
while (x < varDefferedPointers.size()) {
ArrayList newList = new ArrayList();
JIMarshalUnMarshalHelper.serialize(ndr, JIPointer.class, varDefferedPointers.get(x), newList, FLAG);
x++; //incrementing index
varDefferedPointers.addAll(x, newList);
}
int currentIndex = 0;
int length = (currentIndex = ndr.getBuffer().getIndex()) - start;
int value = length / 8;
if (length % 8.0 != 0) //entire variant is aligned by 8 bytes.
{
value++;
}
ndr.getBuffer().setIndex(start);
ndr.writeUnsignedLong(value);
ndr.getBuffer().setIndex(currentIndex);
if (JISystem.getLogger().isLoggable(Level.FINEST)) {
JISystem.getLogger().log(Level.FINEST, "Variant length is {0} , value {1} , variant type{2}", new Object[]{length, value, type});
}
// if (safeArrayStruct != null && isArray)
// {
// //SafeArray have the alignment rule , that all Size <=4 are aligned by 4 and size 8 is aligned by 8.
// //Variant is aligned by 4, Interface pointers are aligned by 4 as well.
// //but this should not exceed the length
// index = new Integer(ndr.getBuffer().getIndex()).doubleValue();
// length = length * 8 + start;
// if (index < length)
// {
// Integer size = (Integer)safeArrayStruct.getMember(2);
// long i = 0;
// if (size.intValue() == 8)
// {
// if (index%8.0 != 0)
// {
// i = (i=Math.round(index%8.0)) == 0 ? 0 : 8 - i ;
// if (index + i <= length)
// {
// ndr.writeOctetArray(new byte[(int)i],0,(int)i);
// }
// else
// {
// ndr.writeOctetArray(new byte[(length - (int)index)],0,(int)(length - (int)index));
// }
// }
// }
// else
// {
// //align by 4...
// //TODO this needs to be tested for Structs and Unions.
// if (index%4.0 != 0)
// {
// i = (i=Math.round(index%4.0)) == 0 ? 0 : 4 - i ;
// if (index + i <= length)
// {
// ndr.writeOctetArray(new byte[(int)i],0,(int)i);
// }
// else
// {
// ndr.writeOctetArray(new byte[(length - (int)index)],0,(int)(length - (int)index));
// }
// }
// }
//
//
// }
// }
}
// catch (JIException e)
// {
// throw new JIRuntimeException(e.getErrorCode());
// }
}
//multiple of 8.
// private int getMaxLength(Class c, boolean isByRef, Object obj)
// {
// int length = 3; //Empty
// if (type3.contains(c))
// {
// length = 3;
// if (isByRef)
// {
// length = length + 1; //for the pointer
// }
// }
// else
// if(c.equals(Long.class) || c.equals(Double.class) || c.equals(Date.class) || c.equals(JICurrency.class))
// {
// length = 4;
// //here the byref can be left out since it will cover 24 bytes properly
// }
// else
// if(c.equals(JIString.class))
// {
//
// int strlen = 0;
// if (obj != null && ((JIString)obj).getString() != null)
// {
// strlen = ((JIString)obj).getString().length();
// }
//
// //20 is of variant, 4+4+4+4 of bstr(user,maxlen,actlen,offset) , (strlen*2) of the actual array
// double value = 20 + 16 + strlen*2;
// if (isByRef)
// {
// value = value + 4;
// }
// double d = value%8.0;
// length = (int)value/8;
// if (d != 0.0)
// {
// length++;
// }
//
//
// }else // for Interface pointers without
// if((obj instanceof IJIComObject))
// {
// double value = ((IJIComObject)obj).internal_getInterfacePointer().getLength();
// if (isByRef)
// {
// value = value + 4;
// }
//
// value = value + 20 + 4 + 4 + 4; //20 of variant , 4 of the ptr, 4 of max count, 4 of actual count
//
// double d = value%8.0;
// length = (int)value/8;
// if (d != 0.0)
// {
// length++;
// }
// //length += 4;
// //double a = ((IJIComObject)obj).getInterfacePointer().getLength()/8.0;
// //length = 4 + (int)Math.ceil(a);
// }
//
//
// return length;
//
// }
//returns the length in bytes
private int getMaxLength2(Class c, Object obj) {
int length = 0;
//since this is getMaxLength2 and hence will either contain
//proper type 3 elements and not EMPTY,NULL,SCODE since these are parts of Variant.
//and not simple types like Integer, JIUnsignedXXX or Float etc.
if (type3.contains(c)) {
length = JIMarshalUnMarshalHelper.getLengthInBytes(c, obj, FLAG);
} else if (c.equals(Long.class) || c.equals(Double.class) || c.equals(Date.class) || c.equals(JICurrency.class)) {
length = 8;
} else if (c.equals(JIString.class)) {
length = JIMarshalUnMarshalHelper.getLengthInBytes(c, obj, FLAG);
} else // for Interface pointers without
if (obj instanceof IJIComObject) {
double value = ((IJIComObject) obj).internal_getInterfacePointer().getLength();
value = value + 4 + 4 + 4; //20 of variant , 4 of the ptr, 4 of max count, 4 of actual count
}
return length;
}
// int getVariantType() throws JIException
// {
// return safeArrayStruct == null ? variantType : getArrayLengthForVarType();
// }
// private int fillArrayType(NetworkDataRepresentation ndr) throws JIException
// {
// int length = getArrayLengthForVarType();
// ndr.writeUnsignedLong(length);
// return length;
// }
private int getArrayLengthForVarType() throws JIException {
//now the array will be of variants, nestedArraysRealClass identifies the class itself
//for iteration we need the variants and then there members.
JIArray objArray = (JIArray) ((JIPointer) safeArrayStruct.getMember(7)).getReferent();
Object[] array = (Object[]) objArray.getArrayInstance();
double length = 20;//variant
if (isByRef) {
length += 4;//byref
}
//SafeArray is 44
length += 44;
boolean isVariantArray = (((Short) safeArrayStruct.getMember(1)).shortValue() & JIVariant.FADF_VARIANT) == JIVariant.FADF_VARIANT;
if (array != null) {
length += 4; //for max count of the array.
if (isVariantArray) {
//each variant is 3 (size 20 = 20/8 = 3)
for (int i = 0; i < array.length; i++) {
JIVariant variant = (JIVariant) array[i];
length += variant.getLengthInBytes(FLAG);//* 8;//((VariantBody)(variant.member.getReferent())).variantType * 8;
}
//now for the "user" pointer part
//length = length + array.length * 4;
} else {
//normal non variant array has been sent...
for (int i = 0; i < array.length; i++) {
length += getMaxLength2(array[i].getClass(), array[i]);
}
}
} else {
length += 4; //for the null 0000.
}
int value = (int) length / 8;
if (length % 8.0 != 0) {
value++;
}
return value;
}
static VariantBody decode(NetworkDataRepresentation ndr, List defferedPointers, int FLAG, Map additionalData) {
//boolean readLong = false;
double index = new Integer(ndr.getBuffer().getIndex()).doubleValue();
if (index % 8.0 != 0) {
long i = (i = Math.round(index % 8.0)) == 0 ? 0 : 8 - i;
ndr.readOctetArray(new byte[(int) i], 0, (int) i);
}
int start = ndr.getBuffer().getIndex();
int length = ndr.readUnsignedLong(); //read the potential length
ndr.readUnsignedLong(); //read the reserved byte
int variantType = ndr.readUnsignedShort(); //varType
//read reserved bytes
ndr.readUnsignedShort();
ndr.readUnsignedShort();
ndr.readUnsignedShort();
ndr.readUnsignedLong(); //32 bit varType
VariantBody variant = null;
List varDefferedPointers = new ArrayList();
if ((variantType & JIVariant.VT_ARRAY) == 0x2000) {
boolean isByRef = (variantType & JIVariant.VT_BYREF) != 0;
//the struct may be null if the array has nothing
JIStruct safeArray = getDecodedValueAsArray(ndr, varDefferedPointers, variantType & ~JIVariant.VT_ARRAY, isByRef, additionalData, FLAG);
int type2 = variantType;
if (isByRef) {
type2 &= ~JIVariant.VT_BYREF; //so that actual type can be determined
}
type2 &= 0x0FFF;
int flagofFlags = FLAG;
if (type2 == JIVariant.VT_INT) {
flagofFlags |= JIFlags.FLAG_REPRESENTATION_VT_INT;
} else if (type2 == JIVariant.VT_UINT) {
flagofFlags |= JIFlags.FLAG_REPRESENTATION_VT_UINT;
} else if (type2 == JIVariant.VT_BOOL) {
FLAG = flagofFlags |= JIFlags.FLAG_REPRESENTATION_VARIANT_BOOL;
}
if (safeArray != null) {
variant = new VariantBody(safeArray, JIVariant.getSupportedClass(new Integer(type2 & ~JIVariant.VT_ARRAY)), (((Object[]) ((JIArray) safeArray.getMember(8)).getArrayInstance()).length > 1), isByRef, flagofFlags);
} else {
variant = new VariantBody(null, JIVariant.getSupportedClass(new Integer(type2 & ~JIVariant.VT_ARRAY)), false, isByRef, flagofFlags);
}
variant.FLAG = flagofFlags;
} else {
boolean isByRef = (variantType & JIVariant.VT_BYREF) != 0;
variant = new VariantBody(getDecodedValue(ndr, varDefferedPointers, variantType, isByRef, additionalData, FLAG), isByRef, variantType);
int type2 = variantType & 0x0FFF;
if (type2 == JIVariant.VT_INT) {
variant.FLAG = JIFlags.FLAG_REPRESENTATION_VT_INT;
} else if (type2 == JIVariant.VT_UINT) {
variant.FLAG = JIFlags.FLAG_REPRESENTATION_VT_UINT;
}
}
int x = 0;
while (x < varDefferedPointers.size()) {
ArrayList newList = new ArrayList();
JIPointer replacement = (JIPointer) JIMarshalUnMarshalHelper.deSerialize(ndr, varDefferedPointers.get(x), newList, FLAG, additionalData);
((JIPointer) varDefferedPointers.get(x)).replaceSelfWithNewPointer(replacement); //this should replace the value in the original place.
x++;
varDefferedPointers.addAll(x, newList);
}
if (variant.isArray && variant.safeArrayStruct != null) {
//SafeArray have the alignment rule , that all Size <=4 are aligned by 4 and size 8 is aligned by 8.
//Variant is aligned by 4, Interface pointers are aligned by 4 as well.
//but this should not exceed the length
index = new Integer(ndr.getBuffer().getIndex()).doubleValue();
length = length * 8 + start;
if (index < length) {
JIStruct safeArrayStruct = variant.safeArrayStruct;
Integer size = (Integer) safeArrayStruct.getMember(2);
long i = 0;
if (size.intValue() == 8) {
if (index % 8.0 != 0) {
i = (i = Math.round(index % 8.0)) == 0 ? 0 : 8 - i;
if (index + i <= length) {
ndr.readOctetArray(new byte[(int) i], 0, (int) i);
} else {
ndr.readOctetArray(new byte[(length - (int) index)], 0, (length - (int) index));
}
}
} else {
//align by 4...
//TODO this needs to be tested for Structs and Unions.
if (index % 4.0 != 0) {
i = (i = Math.round(index % 4.0)) == 0 ? 0 : 4 - i;
if (index + i <= length) {
ndr.readOctetArray(new byte[(int) i], 0, (int) i);
} else {
ndr.readOctetArray(new byte[(length - (int) index)], 0, (length - (int) index));
}
}
}
}
//SafeArray is complete
JIArray array = null;
try {
array = variant.getArray();
} catch (JIException e) {
throw new JIRuntimeException(e.getErrorCode());
}
JIVariant variantMain = new JIVariant(array, variant.isByRef, variant.FLAG);
variant = (VariantBody) variantMain.member.getReferent();
}
return variant;
}
//Variants need specialised handling and the standard serializers may or maynot be used.
private static Class getVarClass(int type) {
Class c = null;
//now first to check if this is a pointer or not.
type &= 0x0FFF; //0x4XXX & 0x0FFF = real type
switch (type) {
case 0: //VT_EMPTY , Not specified.
c = VariantBody.EMPTY.class;
break;
case 1: // VT_NULL , Null.
c = VariantBody.NULL.class;
break;
case 10:
c = VariantBody.SCODE.class; //VT_ERROR,Scodes.
break;
default:
c = JIVariant.getSupportedClass(new Integer(type));
if (c == null) {
//TODO log this , what has come that i don't support.
}
break;
}
return c;
}
private int getVarType(Class c, Object obj) {
int type = 0; //EMPTY
if (obj instanceof IJIDispatch) {
return isByRef ? 0x4000 | JIVariant.VT_DISPATCH : JIVariant.VT_DISPATCH;
}
if (obj instanceof IJIComObject) {
return isByRef ? 0x4000 | JIVariant.VT_UNKNOWN : JIVariant.VT_UNKNOWN;
}
if (c != null) {
Integer type2 = JIVariant.getSupportedType(c, FLAG);
if (type2 != null) {
type = type2.intValue();
} else {
JISystem.getLogger().log(Level.WARNING, "In getVarType: Unsupported Type found ! {0} , please add this to the supportedType map ! ", c);
//make that an array of variants
type2 = JIVariant.getSupportedType(JIVariant.class, FLAG);
}
if (isNull) {
type = 1;
} else if (isScode) {
type = 10; //scode
} else if (isArray) {
type = (int) 0x2000 | type; //0xC; should not assume an array of variants anymore
}
}
if (isByRef && type != 0 && !c.equals(JIArray.class)) {
//then it is a pointer. have to set it correctly
type |= 0x4000;
}
return type;
}
private static Object getDecodedValue(NetworkDataRepresentation ndr, List defferedPointers, int type, boolean isByRef, Map additionalData, int FLAG) {
Object obj = null;
Class c = getVarClass(type);
if (c != null) {
if (isByRef) {
ndr.readUnsignedLong(); //Read the Pointer
}
if (c.equals(VariantBody.SCODE.class)) {
obj = JIMarshalUnMarshalHelper.deSerialize(ndr, Integer.class, null, FLAG, additionalData);
obj = new SCODE(((Number) obj).intValue());
type = JIVariant.VT_ERROR;
} else if (c.equals(VariantBody.NULL.class)) {
//have read 20 bytes
//JIMarshalUnMarshalHelper.deSerialize(ndr,Integer.class,null,JIFlags.FLAG_NULL);//read the last 4 bytes, since there could be parameters before this.
obj = NULL;
type = JIVariant.VT_NULL;
} else if (c.equals(VariantBody.EMPTY.class)) //empty is 20 bytes
{
obj = VariantBody.EMPTY;
type = JIVariant.VT_EMPTY;
} else if (c.equals(JIString.class)) {
obj = new JIString(JIFlags.FLAG_REPRESENTATION_STRING_BSTR);
obj = ((JIString) obj).decode(ndr, null, FLAG, additionalData);
} else if (c.equals(Boolean.class)) {
obj = JIMarshalUnMarshalHelper.deSerialize(ndr, c, defferedPointers, FLAG | JIFlags.FLAG_REPRESENTATION_VARIANT_BOOL, additionalData);
} else {
obj = JIMarshalUnMarshalHelper.deSerialize(ndr, c, defferedPointers, FLAG, additionalData);
}
}
return obj;
}
private static JIStruct getDecodedValueAsArray(NetworkDataRepresentation ndr, List defferedPointers, int type, boolean isByRef, Map additionalData, int FLAG) {
//int newFLAG = FLAG;
if (isByRef) {
ndr.readUnsignedLong();//read the pointer
type &= ~JIVariant.VT_BYREF; //so that actual type can be determined
}
if (ndr.readUnsignedLong() == 0)//read pointer referent id
{
return null;
}
ndr.readUnsignedLong();//1
JIStruct safeArray = new JIStruct();
try {
safeArray.addMember(Short.class);//dim
JIStruct safeArrayBound = new JIStruct();
safeArrayBound.addMember(Integer.class);
safeArrayBound.addMember(Integer.class); //starts at 0
safeArray.addMember(Short.class);//flags
safeArray.addMember(Integer.class);//size
safeArray.addMember(Short.class);//locks
safeArray.addMember(Short.class);//locks
safeArray.addMember(Integer.class);//safearrayunion
safeArray.addMember(Integer.class);//size in safearrayunion
Class c = (Class) JIVariant.supportedTypes_classes.get(new Integer(type));
if (c == null) {
if (JISystem.getLogger().isLoggable(Level.WARNING)) {
JISystem.getLogger().log(Level.WARNING, "From JIVariant: while decoding an Array, type {0} , was not found in supportedTypes_classes map , hence using JIVariant instead...", type);
}
//not available , lets try with JIVariant.
//This is a bug, I should have the type.
c = JIVariant.class;
}
if (c == Boolean.class) {
FLAG |= JIFlags.FLAG_REPRESENTATION_VARIANT_BOOL;
}
//HARDCODING to JIVariant...kindof forgotten why I even wrote the code below.
//since all of the examples I have come across always return a Variant array.
//then why did I typify this thing to it's class (like JIString), it produces an
//exception when the result is returned back is not an array of strings...
//c = JIVariant.class;
JIArray values = null;
if (c == JIString.class) {
values = new JIArray(new JIString(JIFlags.FLAG_REPRESENTATION_STRING_BSTR), null, 1, true);
safeArray.addMember(new JIPointer(values));//single dimension array, will convert it into the
//[] or [][] after inspecting dimension read.
} else {
values = new JIArray(c, null, 1, true);
safeArray.addMember(new JIPointer(values));//single dimension array, will convert it into the
//[] or [][] after inspecting dimension read.
}
safeArray.addMember(new JIArray(safeArrayBound, null, 1, true));
safeArray = (JIStruct) JIMarshalUnMarshalHelper.deSerialize(ndr, safeArray, defferedPointers, FLAG, additionalData);
//now set the right class after examining the flags , only set for JIVariant.class now., the BSTR would already be set previously.
Short features = (Short) safeArray.getMember(1);
//this condition is being kept in the front since the feature flags can be a combination of FADF_VARIANT and the
//other flags , in which case the Variant takes priority (since they will all be wrapped as variants).
if ((features.shortValue() & JIVariant.FADF_VARIANT) == JIVariant.FADF_VARIANT) {
values.updateClazz(JIVariant.class);
} else if (((features.shortValue() & JIVariant.FADF_DISPATCH) == JIVariant.FADF_DISPATCH)
|| ((features.shortValue() & JIVariant.FADF_UNKNOWN) == JIVariant.FADF_UNKNOWN)) {
values.updateClazz(IJIComObject.class);
}
//For JIStrings , it will be done before these above conditions are examined.
} catch (JIException e) {
throw new JIRuntimeException(e.getErrorCode());
}
return safeArray;
}
private void setValue(NetworkDataRepresentation ndr, Object obj, List defferedPointers, int FLAG) {
if (isNull) {
return; //null , is only 20 bytes
}
if (obj != null) {
Class c = obj.getClass();
if (c.equals(EMPTY.class)) //20 bytes
{
} // else
// if (c.equals(Boolean.class))
// {
// ndr.writeUnsignedShort(((Boolean)obj).booleanValue() == true ? 0xFFFF: 0x0000);
// ndr.writeUnsignedShort(0);
// }
else {
if (obj instanceof IJIComObject) {
c = IJIComObject.class;
}
JIMarshalUnMarshalHelper.serialize(ndr, c, obj, defferedPointers, FLAG);
}
} else {
ndr.writeUnsignedLong(new Object().hashCode());//pointer referentId
ndr.writeUnsignedLong(1);
JIMarshalUnMarshalHelper.serialize(ndr, JIStruct.class, safeArrayStruct, defferedPointers, FLAG);
}
}
boolean isArray() {
return isArray;
}
int getLengthInBytes() {
if (safeArrayStruct == null && obj.getClass().equals(VariantBody.EMPTY.class)) {
return 28;
}
if (isArray) {
int length = 0;
// JIArray objArray = (JIArray)((JIPointer)safeArrayStruct.getMember(7)).getReferent();
// Object[] array = (Object[])objArray.getArrayInstance();
// for (int i = 0; i < array.length; i++)
// {
// Class c = array[i].getClass();
// length = length + JIMarshalUnMarshalHelper.getLengthInBytes(c,array[i],FLAG);
// }
// return length;
try {
length = getArrayLengthForVarType() * 8;
} catch (JIException e) {
throw new RuntimeException(e);
}
return length;
} else {
Class c = obj.getClass();
if (obj instanceof IJIComObject) {
c = IJIComObject.class;
} else if (c.equals(VariantBody.SCODE.class)) {
return 24 + 4; //4 for integer scode.
} else if (c.equals(VariantBody.NULL.class) || c.equals(VariantBody.EMPTY.class)) {
return 24;
}
return 24 + JIMarshalUnMarshalHelper.getLengthInBytes(c, obj, FLAG);
}
}
@Override
public String toString() {
String retVal = "";
if (obj == null) {
retVal += "obj is null , ";
} else {
retVal += obj.toString();
}
if (isArray) {
if (is2Dimensional) {
retVal += "2 dimensional array , ";
} else {
retVal = "1 dimensional array , ";
}
if (safeArrayStruct != null) {
retVal += safeArrayStruct.toString();
}
}
return retVal;
}
}