|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
public interface APDU_Serializable
Interface for data types that can be sent to the card by the OV-chip protocol layer. The OV-chip protocol layer is a OV-chip protocol layer that overcomes the one-APDU restriction of Java Card RMI. In addition it can enforce that certain methods are always called in a certain order. Arguments and results (yes, the OV-chip protocol layer fixes the ridiculous one-result-limitation of Java and permits methods to return multiple results) of these methods must implement the APDU_Serializable interface.
Serialization
In the process of sending and receiving objects to and from the
card the internal state of those objects is converted to and from
a byte array with the methods to_byte_array
and from_byte_array
, respectively. The
conversion into a byte array is called serialization.
The reverse is sometimes called deserialization.
APDU's, which are used as transport medium, are limited to 255
bytes of data. Therefore (de-)serialization can happen in serval pieces.
This applies equally well to short data types, because they might be
so unlucky to lay precisely on an APDU boundary (because, for instance,
the preceeding argument used just 254 bytes).
Compatibility Checks
In principle the arguments and expected results on the
host side must be identical in type and size to those on the card.
However, whether this type equality holds is determined by
is_compatible_with
at runtime, and careful
cheating is permitted here. For instance, arguments of type
Bignat
on the card are usually represented by
APDU_BigInteger
on the host. With this trick
the OV-chip protocol layer performs convenient data-type conversions
almost for free.
The method is_compatible_with
is only
called on those objects that are declared as arguments or results
in the relevant Protocol
descriptions on the host.
It is not called on
the arguments that the host code actually supplies.
And it is never called on the card.
Therefore pure
host data types, such as
APDU_BigInteger
or
Host_modulus
, do not need to
put anything sensible into the body of is_compatible_with
.
The card only checks the size of the byte stream it receives. It does
not perform any further type checks.
Consider, for
an example, a method that takes a Bignat
argument. There will be a Bignat object in the argument array of the
relevant Protocol_step
instance. When the host code calls
this method via the OV-chip protocol layer it might supply an
APDU_BigInteger
object as
argument. The method is_compatible_with
is only invoked on the Bignat object with the APDU_BigInteger object as
argument. It is not invoked on the APDU_BigInteger object.
(The stub code that is generated by the protocol-IDL compiler
performs further type conversions. In the example of the last
paragraph the host driver would supply an BigInteger
as argument to the stub method. The stub
method will wrap an APDU_BigInteger
around it.
Method Summary | |
---|---|
short |
from_byte_array(short len,
short this_index,
byte[] byte_array,
short byte_index)
Deserialization of this object. |
boolean |
is_compatible_with(Object o)
Compatibility check for declared and supplied arguments and results. |
short |
size()
Size in bytes necessary to send or receive this object. |
short |
to_byte_array(short len,
short this_index,
byte[] byte_array,
short byte_index)
Serialization of this object. |
Method Detail |
---|
short size()
For testing purposes only it is possible to change the size of an object. This however requires a certain interplay between the objects that change their size and the protocol descriptions of the OV-chip protocol layer.
boolean is_compatible_with(Object o)
Protocol_step
instance with the actual argument or result
as argument. Should return true precisely if the actual argument/result
is considered binary compatible with the declard one. The
method usually checks for type and size.
The compatibility check is done in some assertion on the host side. So if this method returns false, usually an assertion fails soon afterwards.
This method need not implement a symmetric relation. For instance
some_modulus.is_compatible_with(some_host_modulus)
returns
true if some_modulus
and some_host_modulus
have the
same size. However,
some_host_modulus.is_compatible_with(some_modulus)
always returns false, because Host_modulus
objects should never appear in Protocol_step
instances.
o
- actual argument or result
o
.short to_byte_array(short len, short this_index, byte[] byte_array, short byte_index)
len
bytes of the state of this
object into the byte array byte_array
starting at
index byte_index
. The contents of byte_array
up to
index byte_index -1
must not be modified.
this_index
bytes of the state
have already been written in preceeding calls to this method.
Therefore, the first byte written must be the byte
with index this_index
of the state of this object. If the remaining portion of the state
fits into len
bytes the complete state must be serialized.
If it does not fit, len
bytes must be written now and the
remainder of the state is serialized in succeeding calls to this
method with a suitably adjusted this_index
argument.
If this_index
is 0 then serialization starts with this call.
len
is at least 1, but otherwise arbitrary. It might
equal the expected size of the serialized state, but it might also
equal the remaining available space in byte_array
. If
len
is greater than the number of bytes needed only the bytes
needed for serialization must be written.
In total, precisely this.size()
bytes must be written
before complete serialization is signalled by the return value.
The return value signals wheter serialization completed (or if
this method must be called again) and the actual number of bytes
written. There are three possible situations, depending on the
size of the remaining portion of the state of this object and
the len
parameter:
len
bytes.
len
).
len
bytes.
len
bytes of the remaining portion of the state must be
written. The return value is the number of bytes written,
that is, len
is returned.
len
bytes.
len
bytes. The return
value is len + 1
.
len
- available space in byte_array
, at most len
bytes should be written into byte_array
this_index
- greater than or equal to zero, at most
this.size() -1
, number of bytes that
have already been written in preceeding calls. Serialization
must continue at the byte with index this_index
.byte_array
- data array to serialize the state intobyte_index
- index in byte_array
where the first byte must
be written
len
bytes, in this case len + 1
is
returned.
Equivalently, len
is returned if serialization must
continue after writing len
bytes. Some
x < len
is returned if serialization finished by writing
x
bytes. len + 1
is returned if serialization
finished by writing len
bytes.
short from_byte_array(short len, short this_index, byte[] byte_array, short byte_index)
len
bytes of the state of this
object from the byte array byte_array
starting at
index byte_index
. The byte array byte_array
must not be modified.
this_index
bytes of the state
have already been read in preceeding calls to this method.
Therefore, the first byte read must be the byte with
index this_index
of the state of this object.
If the remaining unitialized portion of the state of this object
requires more than len
bytes then len
bytes
of the state must be read now and deserialization will continues
in succeeding calls to this method
with a suitably adjusted this_index
argument.
If this_index
is 0 then deserialization starts with this call.
len
is at least 1, but otherwise arbitrary. It might
be equal to byte_array.length - byte_index
but it could be
less.
In total, precisely this.size()
bytes must be read
before complete deserialization is signalled by the return value.
The return value signals wheter deserialization completed (or if
this method must be called again) and the actual number of bytes
read from byte_array
.
There are three possible situations, depending on the
size of the remaining uninitialized portion
of the state of this object and
the len
parameter:
len
bytes.
len
).
len
bytes.
len
bytes must be read now and deserialization continues
in the following call to this function.
The return value is the number of bytes read,
that is, len
is returned.
len
bytes.
len
bytes.
The return
value is len + 1
.
len
- number of available bytes in byte_array
starting at index byte_index
, at most len
bytes should be read.this_index
- greater than or equal to zero, at most
this.size() -1
, number of bytes that
have already been read in preceeding calls. Deserialization
must continue at the byte with index this_index
.byte_array
- data array to deserialize the state frombyte_index
- index in byte_array
of the first available
data byte
len
bytes, in this case len + 1
is
returned.
Equivalently, len
is returned if deserialization must
continue after reading len
bytes. Some
x < len
is returned if deserialization
finished by reading
x
bytes. len + 1
is returned if
deserialization
finished by reading len
bytes.
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |