Comparing the OPC managed-code and native-code Part URI helper APIs
Windows 7 includes new native-code APIs that provide functionality to compose and parse Part URIs. These APIs are provided through the IOpcUri and IOpcPartUri interfaces. Managed-code provides similar functionality with the System.IO.Packaging PackUriHelper class.
A difference between the two API sets is that while the managed-code PackUriHelper APIs support both Pack URIs and Part URIs (also called "part names"), the native-code IOpcFactory::CreatePartUri and IOpcPartUri APIs only provide functionality to create and manage Part URIs. The native-code Packaging APIs do not provide any functionality to access packages or package content as external resources, and therefore only supports Part URIs to address part content within the immediate package.
The managed-code PackUriHelper and native-code CreatePartUri/IOpcPartUri APIs are both designed to be ECMA 376-2 (2006) compliant.
The table below shows a comparison between the managed-code and native-code APIs, and which APIs provide similar functionality:
Managed API |
Equivalent Native API |
Parity |
See 1.1 |
||
No equivalent API |
||
Identical |
||
Identical |
||
See 1.2 |
||
Identical |
||
Identical |
||
Identical |
||
No equivalent API |
||
No equivalent API |
||
No equivalent API |
||
No equivalent API |
||
No equivalent API |
1. API differences
1.1 IOpcFactory::CreatePartUri differences from PackUriHelper.CreatePartUri
The functionality of the native-code IOpcFactory::CreatePartUri API, follows the rules provided in ECMA 376-2 OPC standard, Appendix A.3 for resolving a relative reference to a valid Part URI (part name). The IOpcFactory::CreatePartUri and IOpcUri::CombinePartUri native-code APIs both produce the same output ("Native-code Behavior" below).
Input |
Native-code CreatePartUri Behavior |
Managed-code CreatePartUri Behavior |
Contains bad UTF-8 encoding e.g. '%FC': |
Leaves %FC unchanged in output. |
Changes to valid UTF-8 output %C3%BC. (See * below) |
Contains empty segments i.e. multiple forward slashes |
Collapses multiple forward slashes to a single forward slash. |
Does not collapse. (This is OPC rule violation). |
Begins with 2 or more forward slashes |
Collapses multiple forward slashes to a single forward slash. |
Fails, throws an "ArgumentException". |
Contains a single trailing forward slash |
Removes trailing slash. |
Fails, throws an "ArgumentException". |
Contains a percent-encoded NULL (%00) |
Returns an "E_UNEXPECTED" HRESULT error. |
Percent-encoded NULL is kept unchanged, and returns a valid part name. |
* - Characters above 0x7F are required to be escaped using UTF-8. For example, if the input URI contains %FC, which is not a legal UTF-8 sequence, the rules provided in RFC 3987 section 3.1, require leaving the input unchanged. The PackUriHelper.CreatePartUri method however, decodes %FC as UTF-16 to its octet <FC> (character 'ü') and then re-encodes it to the valid UTF-8, '%C3%BC'. Unfortunately, this approach is incompliant with RFC rules. [Note: If the relative reference contains a %FC, both IOpcUri::CombinePartUri and PackUriHelper.ResolvePartUri leave it unchanged.]
1.2 IOpcUri::CombinePartUri differences from PackUriHelper.ResolvePartUri
The managed-code PackUriHelper.ResolvePartUri API differs from the native-code IOpcUri::CombinePartUri API in that it resolves the input relative reference against a base URI, but it does not ensure that the result is a valid part name. In contrast, the native-code IOpcUri::CombinePartUri API both resolves the input and ensures that the result is a valid part name.
Input |
Native-code CombinePartUri Behavior |
Managed-code ResolvePartUri Behavior |
Contains percent-encoded unreserved characters |
Un-encodes unreserved characters, resulting in a valid part name. |
Leaves characters in encoded form resulting in an invalid part name. |
Contains empty segments i.e. multiple forward slashes |
Collapses multiple slashes to a single forward slash, resulting in a valid part name. |
Does not collapse empty segments, resulting in an invalid part name. |
Begins with 2 or more forward slashes |
Collapses multiple slashes to a single forward slash, resulting in a valid part name |
Fails, throws an "ArgumentException". |
Contains a single trailing forward slash |
Removes trailing slash. |
Does not remove trailing slash resulting in an invalid part name. |
Contains a percent-encoded NULL (%00) |
Returns an " E_UNEXPECTED " HRESULT error. |
Percent-encoded NULL is kept unchanged, and returns a valid part name. |
- Ali Naqvi