Uno/Remote/Specifications/Uno Remote Protocol
RPC is a convenient but flawed accident of history —Steve Vinoski
Abstract
This document specifies the UNO Remote Protocol version 1.0 (URP). This protocol is used to transmit UNO calls across process boundaries (comparable to IIOP in CORBA).
This protocol was primarily designed to minimize the amount of transferred data for a series of one-way calls. The protocol does not make any assumptions about how the data is transferred.
Basic Data Representation
Data is transferred as sequences of 8-bit bytes. Data is neither aligned nor padded. Multi-byte entities are transferred in network byte order (most significant byte first). Entities like “a 32-bit signed integer” or “a 16-bit unsigned integer” are represented in the obvious way.
There is one special kind of entity that appears at various places in this specification: A compressed number, which denotes a 32-bit unsigned integer, is represented as either one byte or five bytes. If the first byte equals 0xFF
, the following four bytes represent an integer in the range [0 … 232 − 1]. If the first (and only) byte is less than 0xFF
, it represents an integer in the range [0 … 254]. Integers in the range [0 … 254] can thus be represented as either one byte or five bytes; both forms are valid, but the shorter form is preferred.
Blocks and Messages
The largest transferred unit is a block. It consists of a fixed-size block header, followed by one or more messages:
Block header: size message count |
Message 1 |
… |
Message k |
A message may either be a request or a reply. It consists of a header and a body.
Block Header
The block header consists of two 32-bit unsigned integers. The first integer specifies the size of the block in bytes, not counting the eight bytes of the block header. The second integer specifies the number of messages within the block.
The given size must match the actual size exactly (that is, there must not be any excess bytes after the last message in the block). The message count must not be zero.
Messages
Caching Concept
To minimize the amount of transferred data, URP uses caching. This means that URP is optimized for repetitive calls on the same or recently used UNO interfaces.
The following three different kinds of entities are cached:
- Object identifiers (OIDs)
- Thread identifiers (TIDs)
- Types
The caching used is the same for each of the three different kinds; below, it is explained for OIDs only, but TIDs and types are no different.
There are two different caching mechanisms, a first-level cache and a second-level cache.
First-Level Cache
For each of the two directions of an URP bridge, there is a last OID item (actually, there are individual last OID, last TID, and last type items). The two items for the different directions are completely independent of one another. The contents of a last OID item is affected exclusively by the sending side, as detailed below. (Both sides of an URP bridge will have a private copy of a last OID item, where these two copies will always be in sync. But that can be considered an implementation detail.)
Initially, the last OID item is empty.
The header of a request message specifies the OID of the object on which to make a call (correspondingly, it also specifies the TID of the thread from which to make the call, and the interface type on which to make the call). The header contains a flag that specifies whether to use the contents of the last OID item (in which case the last OID item must not be empty), or whether the header contains a new OID (which is then stored in the last OID item, overwriting any old contents).
Second-Level Cache
For each of the two directions of an URP bridge, there is a cache table (actually, there are three individual cache tables for OIDs, TIDs, and types). The two cache tables for the different directions are completely independent of one another. The contents of a cache table is affected exclusively by the sending side, as detailed below. (Both sides of an URP bridge will have a private copy of a cache table, where these two copies will always be in sync. But that can be considered an implementation detail.)
Initially, each cache table is empty.
The caching mechanism uses cache indices, 16-bit unsigned integers. The cache table size is K = 256. (Historically, the cache table size was intended to be dynamically changeable, hence the use of 16-bit qunatities.) An OID can be transferred in either of two ways:
- As an OID together with a cache index. The OID is entered into the cache table at the given index. The cache index must be in the range [0 … K − 1]. (If the cache table already contains an entry for the given index, the old entry is overwritten.) As a special case, if the cache index equals
0xFFFF
, the OID is not entered into the cache table. - As only a cache index. The cache index must be in the range [0 … K − 1], and the cache table must contain an entry for that index. The transferred OID is the cache table entry at the given index.
Objects
Object Life Cycle
See UNO Object Life Cycle Model for an explanation of the object life cycle concept and related terms. An URP bridge has to ensure that an object that has been transferred over the bridge can reliably be detected as done, once the object has transitioned to that state. The following describes the current mechanism to achieve this, but note that it is broken (see below).
In the following, the notion of an object o together with an interface type t implemented by o is used, written as the tuple 〈o, t〉. Each side of an URP bridge maintains a reference count (a non-negative integer) for each tuple 〈o, t〉 that it has sent over the bridge (either as the target of a method call in a request message, or as the value of an interface type among the data of a request or reply message). Also, at any point in time, each side of an URP bridge considers a given tuple 〈o, t〉 as either bridged in or not. A tuple 〈o, t〉 is considered bridged in at one side of a bridge if and only if the corresponding reference count is positive at the other side of the bridge.
A tuple 〈o, t〉 can only be used as the target of a method call in a request message while it is bridged in at the sending side.
Each reference count starts out at zero. When sending the tuple 〈o, t〉 (as the value of an interface type among the data of a request or reply message), the sending side increments its reference count for 〈o, t〉, unless it considers as bridged in any tuple 〈o, t′〉, where t′ is a subtype of t (including t itself). If the same tuple appears multiple times in the data of a message, the corresponding reference count is incremented multiple times.
For every tuple 〈o, t〉 that is bridged in at one side of an URP bridge, that side has to eventually send a release
message for 〈o, t〉 to the other side. Each release
message causes the receiving side to decrement its corresponding reference count by one. It is an error to send a release
message for a tuple while it is not bridged in at the sending side.
When a tuple 〈o, t〉 becomes no longer bridged in at one side of an URP bridge, that side may no longer use that tuple (in particular, send it as the value of an interface type among the data of a message), unless it still has another reference of type t to o. An object o cannot become done as long as any side of any URP bridge has a positive reference count for any tuple 〈o, t〉, with arbitrary t.
The optimization rule (to not increment the reference count for 〈o, t〉 when 〈o, t〉 itself or some subtype tuple 〈o, t′〉 is considered as bridged in) is broken, as it leads to race conditions: Suppose there are three environments, A, B, and C; each two environments are connected via an URP bridge. Environment A has a local UNO object o, and it has sent o to both B and C. Both B and C
have a proxy for o (each of the two proxies forwarding to environment A). Once this setup is established, we only consider the bridge between B and C. Also, we can ignore any interface types (just assume o only implements com.sun.star.uno.XInterface
).
For the bridge between B and C, initially both B and C have a reference count of 0 for the object o, and neither of them considers o to be bridged in.
Assume B sends object o to C. Lets call this Send1. The optimization rule does notapply: B increments its reference count for o to 1 as soon as it sends the message Send1 at time t1, and C considers o to be bridged in as soon as it receives the message at time t2 > t1. (When C does no longer need the o offered by B, it will send back a release
message to B, which will in turn drop its reference count for o back to 0.)
Assume C sends object o to B (lets call this Send2) at about the same time as Send1 happens. C sends the message Send2 at time t3. There are two cases to consider:
- If t3 < t2 (Send1 has not yet reached C), the optimization rule will not apply, and C increments its reference count for o to 1.
- If t3 > t2 (Send1 has already reached C, and C considers o to be bridged in), the optimization rule does apply, and C does not increment its reference count for o (which stays at 0).
But when B receives Send2, it cannot tell which of the two cases occurred. Thus, B does not know whether to send back a release
message to C.
[TODO: This needs to be fixed.]
Object Identifiers
Each UNO object is assigned a globally unique object identifier (OID), which is a non-empty ASCII string. How OIDs are assigned to UNO objects, and how it is ensured that they are globally unique is outside the scope of this document.
Within URP, OIDs are used for four purposes:
- To identify the object that is the target of a method call in a request message.
- To identify an object for which a reference to that object is the value of an interface type among the data of a request or reply message.
- As initial object identifiers in
queryInterface
messages to request initial objects, see ThequeryInterface
Message. - The special OID
UrpProtocolProperties
is used to identify certain special messages; see Protocol Property Messages.
Threads
See UNO Execution Model for a general description of threads in UNO, and for related terminology. Each UNO thread is assigned a globally unique thread identifier (TID), which is a non-empty byte sequence. How TIDs are assigned to UNO threads, and how it is ensured that they are globally unique is outside the scope of this document. (Note that global uniqueness is only required for the TIDs of active threads—an active thread may have the same TID as a done thread, i.e., TIDs may be recycled.)
Generally, URP represents normal UNO interface method invocations as synchronous calls, and one-way UNO interface method invocations as asynchronous calls. This can be overridden with a MUSTREPLY
flag: On the one hand, one-way UNO interface method invocations can be forced to use synchronous instead of asynchronous calls; doing so is in accordance with the specification of the UNO execution model. On the other hand, normal UNO interface method invocations can be forced to use asynchronous instead of synchronous calls (with a MUSTREPLY
flag set to 0); doing so violates the specification of the UNO execution model, and should thus be avoided.
To satisfy the requirements of the UNO execution model, each side of an URP bridge implementation must adhere to certain rules:
- When sending a synchronous request message with the TID of a UNO thread h, the sending side will not execute any computation steps in thread h (especially, it will not send any further request or reply messages with the given TID), until it receives back the corresponding reply message.
- When sending an asynchronous request message with the TID of a UNO thread h, the sending side simply continues to execute computation steps in thread h. It does not wait for any reply message.
- For each TID, the receiving side maintains a queue of pending request messages received with that TID. Upon receiving a synchronous or asynchronous request messages with a given TID, the receiving side enqueues it at the end of the corresponding queue.
- Whenever a synchronous request message becomes the first entry in a queue for a given TID (of some UNO thread h), the receiving side starts to sequentially execute the computation steps corresponding to the requested UNO interface method, in thread h. It uses the TID of thread h for all request messages sent while executing these computation steps. When it is finished with the computation steps, it sends back a reply message (with the given TID), and the synchronous request message is removed from the head of the queue.
- Whenever an asynchronous request message becomes the first entry in a queue for a given TID (of some UNO thread h), the receiving side starts to sequentially execute the computation steps corresponding to the requested UNO interface method, in a new (previously immaterial) thread h′. It uses the TID of thread h′ for all request messages sent while executing these computation steps. When it is finished with the computation steps, thread h′ transitions from active to done, and the asynchronous request message is removed from the head of the queue.
In language bindings that map (conceptual) UNO threads to “real” process threads, it may be useful to share this mapping across all URP bridges within one process (even across different language bindings): Assume that a synchronous request message with a given TID is sent out over some bridge. The process thread corresponding to the given TID will be blocked until a corresponding reply message is received back over that bridge. Further assume that within this time span a synchronous request message with the same TID is received over some other bridge. It is desirable, then, that this message is executed in the blocked process thread (temporarily unblocking it), so that it can share critical resources (e.g., mutices, thread local storage) with the blocked method execution.
Function IDs
The function ID corresponding to a given interface type member function is defined to be the function index the member function maps to (see UNO Type System). It is an error for a function index that is used as a function ID to be outside the range [0 … 216 − 1].
Special Messages
Apart from normal messages (that represent calls of methods on UNO objects), there are various kinds of special messages.
The queryInterface
Message
This message is used to query a UNO object o for a supported interface type t. It is a request message corresponding to a UNO IDL interface method of the form any queryInterface([in] type)
. It uses function ID 0 (which is otherwise reserved). The passed in type must be an interface type. The corresponding reply message contains a value 〈t′, v′〉 of type ANY
. If o does implement the requested type t, t′ must equal t, and v must be a non-null reference of type t to o. Otherwise, t′ must be VOID
.
There is a special sort of queryInterface
messages that request initial objects. Bridges often face a bootstrapping problem, in that neither side of a bridge knows the OID of an object available at the other side, and neither side can send meaningful request messages. To solve this problem, each side of a bridge can define a well-known set of initial object identifiers, which can be used by the other side of the bridge to obtain references to those initial objects. This is done with special queryInterface
messages, where the target OID is the initial object identifier (instead of a real OID), and the requested interface type is com.sun.star.uno.XInterface
. The method call interface type of the request message itself must also be com.sun.star.uno.XInterface
. Using an initial object identifier instead of an OID is only valid in such a special queryInterface
call; the corresponding reply message will return an ANY
containing an object reference with the real OID of the requested initial object (or it will return a VOID
ANY
). How to distinguish a normal queryInterface
message (with a real OID) from such a special queryInterface
message (with an initial object identifier instead of an OID) is left unspecified.
It is unfortunate that initial object identifiers and OIDs share a single name space.
The release
Message
This message is used to control reference counts associated with objects, see Object Life Cycle. It is a request message corresponding to a UNO IDL interface method of the form [oneway] void release()
. It uses function ID 2 (which is otherwise reserved). (Even though this is a one-way method, a MUSTREPLY
flag may require a corresponding reply message, just as with any other one-way method.)
Protocol Property Messages
Properties may be used to customize bridge-internal settings for application-dependent requirements (see Protocol Properties). Properties can be accessed by sending special request messages containing the special OID UrpProtocolProperties
and the interface type com.sun.star.bridge.XProtocolProperties
.
This implies that the OID UrpProtocolProperties
is reserved by URP (but only as a real OID, not necessarily as an initial object identifier). The interface type com.sun.star.bridge.XProtocolProperties
is only used as a—meaningless—tag here; whether or not there is a type of that name (be it an interface type or any other kind of type) is irrelevant.
It is unfortunate that the special OID UrpProtocolProperties
shares a single name space with normal OIDs, and that these special messages use the interface type com.sun.star.bridge.XProtocolProperties
as a tag.
Exchanging requestChange
and commitChange
messages must adhere to a special protocol. For this protocol, each side of the bridge is in one of a number of states at any point in time: initial, requested(n), reply−1, reply0, reply1, commit, committed, or wait. Initially, each side of the bridge is in state initial. Each side of the bridge transitions as follows:
- In state initial, it can send a
requestChange
request with a given random number n, and transition to state requested(n). - In state initial, it can receive a
requestChange
request. It must send back a corresponding reply with return value 1, and transition to state wait. - In state requested(n), it can receive a reply corresponding to its
requestChange
request, with return value 1. It must transition to state commit. - In state requested(n), it can receive a
requestChange
request with a random number n′. It must behave as follows:- If n < n′, it sends back a reply with return value 1, and transitions to state reply0.
- If n = n′, it sends back a reply with return value −1, and transitions to state reply−1.
- If n > n′, it sends back a reply with return value 0, and transitions to state reply1.
- In state reply−1, it will receive a reply corresponding to its
requestChange
request, with return value −1. It must transition to state initial. - In state reply0, it will receive a reply corresponding to its
requestChange
request, with return value 0. It must transition to state wait. - In state reply1, it will receive a reply corresponding to its
requestChange
request, with return value 1. It must transition to state commit. - In state commit, it must send a
commitChange
request, and transition to state committed. - In state committed, it will receive a reply corresponding to its
commitChange
request. It must transition to state initial. - After sending the
commitChange
request in state commit, this side of the bridge must not send any messages, until it has received the corresponding reply in state committed. (This implies that the sentcommitChange
request must be the last message in a block.) - In state wait, it will receive a
commitChange
request. It must send back a corresponding reply, and transition to state initial.
Any behaviour of one side of a bridge that does not conform to this protocol is an error. What other messages, besides requestChange
and commitChange
requests and replies, are sent at what times is not controlled by this protocol (except for the limitation to not send any messages while a commitChange
is in transit).
This protocol can lead to livelock if both sides of a bridge continuously send requestChange
messages with identical random numbers.
The requestChange
Message
This message is used to initiate a change of protocol properties. It is a request message corresponding to a UNO IDL interface method of the form
long requestChange([in] long randomNumber);
|
The function ID to use for this message is 4.
The parameter randomNumber
is used in case both sides of the bridge send a requestChange
message at the same time. The general idea is that the side that supplies the larger number is allowed to proceed with a commitChange
message.
The corresponding reply message contains a LONG
. Possible values are 1, 0, and −1; it is an error if any other value is returned. The general idea is that 1 indicates that the receiver can proceed and send a commitChange
message, 0 indicates that the other side supplied a larger random number, and −1 indicates that both sides supplied the same random number.
The commitChange
Message
This message is used to commit changes of protocol properties. It is a request message corresponding to a UNO IDL interface method of the form
void commitChange([in] sequence< com::sun::star::bridge::ProtocolProperty > newValues)
|
The function ID to use for this message is 5.
The sequence newValues
may only contain defined properties, and only those properties that are contained in newValues
will be changed. The corresponding reply message will signal an InvalidProtocolChangeException
if the other side of the bridge fails to change at least one of the properties, for whatever reason. In that case, no properties are changed at all. To try to change properties again, a new requestChange
message must be send.
On either side of the bridge, the new property values take effect immediately after the (successful) reply to commitChange
has been sent or received, respectively. Thus, the reply message itself must still be sent using the old property values.
Message Headers
Each message starts with one or two flag bytes. The most significant bit of the first flag byte specifies whether the message has a long or a short header:
Bit name | Value | Description |
---|---|---|
7 LONGHEADER
|
1 | The first byte contains flags with further information about the message. |
0 | The message is a short request message with default flags. | |
… | … |
For a long message header, the second most significant bit of the first flag byte specifies whether the message is a request or a reply:
Bit name | Value | Description |
---|---|---|
7 LONGHEADER
|
1 | |
6 REQUEST
|
1 | The message is a request. |
0 | The message is a reply. | |
… | … |
A short request message encodes the function ID in the flag bytes (a short request message can only be used if the function ID is in the range [0 … 214 − 1]; otherwise, a regular request message must be used). It implicitly uses the first-level caching mechanism for types, OIDs, and TIDs. Its header consists of the one or two flag bytes only:
Bit name | Value | Description |
---|---|---|
7 LONGHEADER
|
0 | |
6 FUNCTIONID14
|
1 | The message header consists of two flag bytes. The lower order 6 bits of the first byte contain the higher order bits of the function ID, and the 8 bits of the second byte contain the lower order bits of the function ID. |
0 | The message header consists of only one flag byte. The lower order 6 bits of the byte contain the function ID. | |
… | … |
Request Messages
A request message represents the call of a method m of an interface type t at an object o (with a given OID); the call is made from some UNO thread h (with a given TID). The method m has a fixed sequence of parameters 〈x1 t1, …, xk tk〉, k ≥ 0, where each xi designates the parameter as either in, out, or in-out, and each ti is a non-void, non-exception type. If the method m is not defined as a one-way method (or if a MUSTREPLY
flag requires a reply nonetheless), the request message will be followed by a reply message with the same TID, sent in the opposite direction.
Bit name | Value | Description |
---|---|---|
7 LONGHEADER
|
1 | |
6 REQUEST
|
1 | |
5 NEWTYPE
|
1 | The interface type t of the method call is given explicitly, as part of the message header. |
0 | The interface type t of the method call is given implicitly, using the first-level caching mechanism for types. | |
4 NEWOID
|
1 | The OID of the method call is given explicitly, as part of the message header. |
0 | The OID of the method call is given implicitly, using the first-level caching mechanism for OIDs. | |
3 NEWTID
|
1 | The TID of the method call is given explicitly, as part of the message header. |
0 | The TID of the method call is given implicitly, using the first-level caching mechanism for TIDs. | |
2 FUNCTIONID16
|
1 | The function ID is represented as a 16-bit unsigned integer. |
0 | The function ID is represented as an 8-bit unsigned integer. | |
1 reserved | 0 | When sending, this bit must be set to 0; when receiving, the value of this bit should be ignored. |
0 MOREFLAGS
|
1 | This byte is followed by a second flag byte. |
0 | This byte is the only flag byte. |
If a second flag byte follows, it specifies whether or not a reply is sent back (flag MUSTREPLY
), and whether the call is executed synchronously or asynchronously (flag SYNCHRONOUS
), overriding any one-way definition of the method m. If no second flag byte follows, the settings of the flags MUSTREPLY
and SYNCHRONOUS
is specified by the definition of m: if m is defined as a one-way method, both MUSTREPLY
and SYNCHRONOUS
are implicitly set to 0; if m is defined as a normal (not one-way) method, both MUSTREPLY
and SYNCHRONOUS
are implicitly set to 1. It is an error if MUSTREPLY
and SYNCHRONOUS
are not set either both to 0 or both to 1.
It seems to be a historic mistake that there are two redundant bits, MUSTREPLY
and SYNCHRONOUS
, that must always have the same value.
Bit name | Value | Description |
---|---|---|
7 MUSTREPLY
|
1 | A reply must be sent back. |
0 | No reply must be sent back. (For a method that would originally be synchronous, setting this bit to 1 means that information about the return value, the output values of out and in-out parameters, and thrown exceptions is effectively lost.) | |
6 SYNCHRONOUS
|
1 | Execute the call synchronously. |
0 | Execute the call asynchronously. | |
0–5 reserved | 0 | When sending, these bits must be set to 0; when receiving, the values of these bits should be ignored. |
The flag bytes are followed by the function ID, either a 16-bit or an 8-bit unsigned integer.
If the NEWTYPE
flag is set, then the interface type t follows, represented as a value of type TYPE
.
If the NEWOID
flag is set, then the OID follows. For its representation, the second-level caching mechanism for OIDs is used. An OID d is a non-empty ASCII string, and hence also a non-empty Unicode string. The OID is represented as the representation of a Unicode string d′ of type STRING
, followed by a cache index. If d′ is the empty string, the OID is taken from the OID cache table. Otherwise, d = d′ is the OID. Conversely, it is an error if the Unicode string d′ is not also an ASCII string that is a valid OID. (This also implies that no valid OID may be the empty ASCII string.)
If the NEWTID
flag is set, then the TID follows. For its representation, the second-level caching mechanism for TIDs is used. A TID d, which is a non-empty byte sequence, is represented as the representation of a sequence d′ of component type BYTE
, followed by a cache index. If d′ is the empty sequence, the TID is taken from the TID cache table. Otherwise, d = d′ is the TID.
The message header is finished then. The message body contains the input values of any in and in-out parameters from 〈x1 t1, …, xk tk〉, in that order. Each relevant value vi is represented as a value of type ti, for 1 ≤ i ≤ k.
Reply Messages
Each reply message corresponds to a request message. It represents the data (return value and output values of any out and in-out parameters, or any thrown exception) returned from the call represented by the corresponding request message. Apart from the fixed sequence of parameters 〈x1 t1, …, xk tk〉, k ≥ 0, the method m has a return value type t0 (which must be a non-exception type), and a set of exception specifications {e1, …, el}, l ≥ 0 (where each ei must be an exception type).
A reply message header has only one flag byte:
Bit name | Value | Description |
---|---|---|
7 LONGHEADER
|
1 | |
6 REQUEST
|
0 | |
5 EXCEPTION
|
1 | The call terminated abnormally, by throwing an exception. |
0 | The call terminated normally. | |
4 reserved | 0 | When sending, this bit must be set to 0; when receiving, the value of this bit should be ignored. |
3 NEWTID
|
1 | The TID of the method call is given explicitly, as part of the message header. |
0 | The TID of the method call is given implicitly, using the first-level caching mechanism for TIDs. | |
0–2 reserved | 0 | When sending, these bits must be set to 0; when receiving, the values of these bits should be ignored. |
If the NEWTID
flag is set, the flag byte is followed by the TID, as described for request messages above. The message header is finished then.
If the EXCEPTION
flag is set, the message body contains the thrown exception, represented as a value 〈t′, v′〉 of type ANY
. The type t′ must be an exception type that matches the set of exception specifications {e1, …, el}.
If the EXCEPTION
flag is not set, the message body contains the return value v0, represented as a value of type t0, followed by the output values of any out and in-out parameters from 〈x1 t1, …, xk tk〉, in that order. Each relevant value vi is represented as a value of type ti, for 1 ≤ i ≤ k.
UNO Data Representation
See UNO Type System for a description of the UNO type system and related terms. Assume that v is a value of type t. The following specifies the representation of v of type t′, where t′ is determined by context, and will always be the same as t, except for struct, exception, and interface types.
Basic Types
A value of a basic type t is represented as zero or more bytes, in the obvious way (values of type BOOLEAN
are represented as numeric values 0 denoting false
and 1 denoting true
; it is an error to use any other numeric values):
Type | Bytes |
---|---|
VOID
|
0 |
BOOLEAN
|
1 |
BYTE
|
1 |
SHORT
|
2 |
UNSIGNED SHORT
|
2 |
LONG
|
4 |
UNSIGNED LONG
|
4 |
HYPER
|
8 |
UNSIGNED HYPER
|
8 |
FLOAT
|
4 |
DOUBLE
|
8 |
CHAR
|
2 |
STRING
A string is first converted into a sequence of bytes, using UTF-8. Let k ≥ 0 be the length of that sequence. The string is represented as the compressed number k, followed by the UTF-8–converted bytes. It is an error if k ≥ 232. Conversely, it is an error if the bytes do not form a valid UTF-8 encoding.
TYPE
A type is represented as one or more bytes. The seven lower order bits of the first byte (b &
0x7F
) specify the type class (see also the enum type com.sun.star.uno.TypeClass
):
Type | b & 0x7F
|
---|---|
VOID
|
0 |
BOOLEAN
|
2 |
BYTE
|
3 |
SHORT
|
4 |
UNSIGNED SHORT
|
5 |
LONG
|
6 |
UNSIGNED LONG
|
7 |
HYPER
|
8 |
UNSIGNED HYPER
|
9 |
FLOAT
|
10 |
DOUBLE
|
11 |
CHAR
|
1 |
STRING
|
12 |
TYPE
|
13 |
ANY
|
14 |
sequence types | 20 |
enum types | 15 |
struct types | 17 |
exception types | 19 |
interface types | 22 |
It is an error if the seven lower order bits have a value not listed above. The higher order bit of the first byte (b &
0x80
) is a cache flag.
For a simple type, only the first byte is needed. The cache flag must be set to 0.
For a complex type, the second-level caching mechanism for types is used. The first byte is followed by a cache index. If the cache flag is zero, the type is taken from the type cache table. If the cache flag is one, the name of the type follows, represented as a value of type STRING
.
The decision to represent complex types by both type class and name leads to some redundancy. For sequence types, for example, a better approach would be to represent a sequence type as the type class byte 20 followed by the encoding of the component type.
ANY
Let v = 〈t1, v1〉 be a value of type ANY
. It is represented as the representation of t1 of type TYPE
, followed by the representation of v1 of type t1.
Sequence Types
Let v = (v1, …, vk), k ≥ 0, be a value of the sequence type with component type tc. It is represented as the compressed number k, followed by the representations of v1, …, vk of type tc, in that order. It is an error if k ≥ 232.
Enum Types
Let v = n, n ∈ [−231 … 231 − 1], be a value of an enum type. It is represented as the 32-bit signed integer n. Conversely, it is an error if a 32-bit signed integer n shall represent a value of some enum type, and that enum type does not contain a member with numeric value n.
Struct and Exception Types
Let v = 〈v1, …, vk〉 be a value of the struct or exception type t = 〈t1, …, tk〉, k ≥ 0 (where the ti include any members inherited from a possible parent type). Assume that v is to be represented as a value of type t′, where t′ = 〈t1, … tl〉, 0 ≤ l ≤ k, is a supertype of t. The value v is first converted into a value v′ = 〈v1, …, vl〉 of type t′, by slicing it. The value v′ is then represented as the combination of the representation of vi of type ti, for i from 1 to l.
Interface Types
Let v be a reference of interface type t, either the null reference or a reference to a UNO object o with OID d. Assume that v is to be represented as a value of type t′, where t′ is a supertype of t (but note that this type t′ is irrelevant for the representation of v). If v is the null reference, it is represented as the representation of the empty STRING
, followed by the special cache index 0xFFFF
. Otherwise, it is represented as the representation of the OID d, as described for request messages above.
Protocol Properties
Properties may be used to customize bridge-internal settings. Special messages are used to change protocol properties (see Protocol Property Messages).
Name | Type | Description |
---|---|---|
CurrentContext
|
ANY
|
Changing this property (to an arbitrary ANY value) enables a mode in which the UNO current context is passed across URP.An implementation of an URP bridge may fail to change this property (i.e., raise a com::sun::star::bridge::InvalidProtocolChangeException exception in response to a commitChange message). Each implementation of an URP bridge should try to change this property as soon as the bridge is established. (Early bridge implementations failed to pass the current context across the bridge, and that needed to be changed in a compatible way.)When the current context mode is enabled, the message body of every request message that is not a special release or protocol property message is prefixed by the UNO current context (in the respective thread) as a value of type com::sun::star::uno::XCurrentContext . (It appears to be a historic mistake that the special queryInterface messages are not also exempted.)
|