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

PackUriHelper.CreatePartUri

IOpcFactory::CreatePartUri

See 1.1

No equivalent API

IOpcFactory::CreatePackageRootUri

 

PackUriHelper.GetRelationshipPartUri

IOpcUri::GetRelationshipsPartUri

Identical

PackUriHelper.GetRelativeUri

IOpcUri::GetRelativeUri

Identical

PackUriHelper.ResolvePartUri

IOpcUri::CombinePartUri

See 1.2

PackUriHelper.ComparePartUri

IOpcPartUri::ComparePartUri

Identical

PackUriHelper.GetSourcePartUriFromRelationshipPartUri

IOpcPartUri::GetSourceUri

Identical

PackUriHelper.IsRelationshipPartUri

IOpcPartUri::IsRelationshipsPartUri

Identical

PackUriHelper.Create

No equivalent API

 

PackUriHelper.ComparePackUri

No equivalent API

 

PackUriHelper.GetNormalizedPartUri

No equivalent API

 

PackUriHelper.GetPackageUri

No equivalent API

 

PackUriHelper.GetPartUri

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