HRESULT set_input( WS_XML_READER *reader, char *data, ULONG size ) { WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8}; WS_XML_READER_BUFFER_INPUT buf; buf.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER; buf.encodedData = data; buf.encodedDataSize = size; return WsSetInput( reader, &text.encoding, &buf.input, NULL, 0, NULL ); }
// Main entry point int __cdecl wmain() { HRESULT hr = S_OK; WS_ERROR* error = NULL; WS_METADATA* metadata = NULL; WS_CHANNEL* channel = NULL; WS_XML_READER* reader = NULL; WS_HEAP* heap = NULL; // Declare constraints on what policy is acceptable // Require HTTP WS_CHANNEL_BINDING channelBinding = WS_HTTP_CHANNEL_BINDING; // Set up channel property contraints that override the default constraints WS_CHANNEL_PROPERTY_CONSTRAINT channelPropertyConstraints[3]; // Allow text encodings WS_ENCODING allowedEncodings[] = { WS_ENCODING_XML_UTF8, WS_ENCODING_XML_UTF16LE, WS_ENCODING_XML_UTF16BE }; channelPropertyConstraints[0].id = WS_CHANNEL_PROPERTY_ENCODING; channelPropertyConstraints[0].allowedValues = allowedEncodings; channelPropertyConstraints[0].allowedValuesSize = sizeof(allowedEncodings); // Allow addressing 1.0 WS_ADDRESSING_VERSION allowedAddressingVersions[] = { WS_ADDRESSING_VERSION_1_0, }; channelPropertyConstraints[1].id = WS_CHANNEL_PROPERTY_ADDRESSING_VERSION; channelPropertyConstraints[1].allowedValues = allowedAddressingVersions; channelPropertyConstraints[1].allowedValuesSize = sizeof(allowedAddressingVersions); // Allow SOAP 1.1 or SOAP 1.2 WS_ENVELOPE_VERSION allowedEnvelopeVersions[] = { WS_ENVELOPE_VERSION_SOAP_1_1, WS_ENVELOPE_VERSION_SOAP_1_2, }; channelPropertyConstraints[2].id = WS_CHANNEL_PROPERTY_ENVELOPE_VERSION; channelPropertyConstraints[2].allowedValues = allowedEnvelopeVersions; channelPropertyConstraints[2].allowedValuesSize = sizeof(allowedEnvelopeVersions); // Set up security property contraints that override the default constraints WS_SECURITY_PROPERTY_CONSTRAINT securityPropertyConstraints[1]; // Allow with/without a timestamp WS_SECURITY_TIMESTAMP_USAGE allowedTimestampValues[] = { WS_SECURITY_TIMESTAMP_USAGE_NEVER, WS_SECURITY_TIMESTAMP_USAGE_ALWAYS, }; securityPropertyConstraints[0].id = WS_SECURITY_PROPERTY_TIMESTAMP_USAGE; securityPropertyConstraints[0].allowedValues = allowedTimestampValues; securityPropertyConstraints[0].allowedValuesSize = sizeof(allowedTimestampValues); // Set up the ssl security binding constraint structure WS_SSL_TRANSPORT_SECURITY_BINDING_CONSTRAINT sslSecurityBindingConstraint = { }; sslSecurityBindingConstraint.bindingConstraint.type = WS_SSL_TRANSPORT_SECURITY_BINDING_CONSTRAINT_TYPE; // Set up the X.509 security binding constraint structure WS_CERT_MESSAGE_SECURITY_BINDING_CONSTRAINT certSecurityBindingConstraint = { }; certSecurityBindingConstraint.bindingConstraint.type = WS_CERT_MESSAGE_SECURITY_BINDING_CONSTRAINT_TYPE; certSecurityBindingConstraint.bindingUsage = WS_SUPPORTING_MESSAGE_SECURITY_USAGE; // Set up the set of security binding constraints WS_SECURITY_BINDING_CONSTRAINT* securityBindingConstraints[] = { &sslSecurityBindingConstraint.bindingConstraint, &certSecurityBindingConstraint.bindingConstraint }; // Set up the security constraint structure WS_SECURITY_CONSTRAINTS securityConstraints = { }; securityConstraints.securityPropertyConstraints = securityPropertyConstraints; securityConstraints.securityPropertyConstraintCount = WsCountOf(securityPropertyConstraints); securityConstraints.securityBindingConstraints = securityBindingConstraints; securityConstraints.securityBindingConstraintCount = WsCountOf(securityBindingConstraints); // Set up the policy constraint structure WS_POLICY_CONSTRAINTS policyConstraints = { }; policyConstraints.channelBinding = channelBinding; policyConstraints.channelPropertyConstraints = channelPropertyConstraints; policyConstraints.channelPropertyConstraintCount = WsCountOf(channelPropertyConstraints); policyConstraints.securityConstraints = &securityConstraints; // Set up port type to match static const WS_XML_STRING desiredPortTypeName = WS_XML_STRING_VALUE("IPingService"); static const WS_XML_STRING desiredPortTypeNs = WS_XML_STRING_VALUE("http://example.com"); // Create an error object for storing rich error information hr = WsCreateError( NULL, 0, &error); if (FAILED(hr)) { goto Exit; } // Create object that will hold metadata documents hr = WsCreateMetadata(NULL, 0, &metadata, error); if (FAILED(hr)) { goto Exit; } // Create an XML reader hr = WsCreateReader( NULL, 0, &reader, error); if (FAILED(hr)) { goto Exit; } // Set the input of the reader to the policy text WS_XML_READER_BUFFER_INPUT bufferInput; ZeroMemory(&bufferInput, sizeof(bufferInput)); bufferInput.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER; bufferInput.encodedData = wsdlXml.bytes; bufferInput.encodedDataSize = wsdlXml.length; WS_XML_READER_TEXT_ENCODING textEncoding; ZeroMemory(&textEncoding, sizeof(textEncoding)); textEncoding.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_TEXT; textEncoding.charSet = WS_CHARSET_AUTO; hr = WsSetInput(reader, &textEncoding.encoding, &bufferInput.input, NULL, 0, error); if (FAILED(hr)) { goto Exit; } // Read the metadata into the metadata object. hr = WsReadMetadata(metadata, reader, &wsdlUrl, error); if (FAILED(hr)) { goto Exit; } // After adding a document to the metadata object, it can be queried // to determine the address of any documents which have been referenced // but have not yet been added. WS_ENDPOINT_ADDRESS* missingAddress; hr = WsGetMissingMetadataDocumentAddress(metadata, &missingAddress, error); if (FAILED(hr)) { goto Exit; } if (missingAddress != NULL) { // We only support one document in this example hr = E_FAIL; goto Exit; } // Get the endpoints from the metadata object WS_METADATA_ENDPOINTS endpoints; hr = WsGetMetadataEndpoints(metadata, &endpoints, error); if (FAILED(hr)) { goto Exit; } BOOL foundEndpoint = FALSE; WS_METADATA_ENDPOINT* endpoint = NULL; // Search for port types for (ULONG i = 0; i < endpoints.endpointCount; i++) { // Get the endpoint from the array of endpoints endpoint = &endpoints.endpoints[i]; // See if the port type name matches hr = WsXmlStringEquals(endpoint->portTypeName, &desiredPortTypeName, error); if (FAILED(hr)) { goto Exit; } if (hr == S_FALSE) { continue; } // See if the port type namespace matches hr = WsXmlStringEquals(endpoint->portTypeNs, &desiredPortTypeNs, error); if (FAILED(hr)) { goto Exit; } if (hr == S_FALSE) { continue; } foundEndpoint = TRUE; break; } if (!foundEndpoint) { // No matching port types hr = E_FAIL; goto Exit; } // Get the policy for the endpoint WS_POLICY* policy; policy = endpoint->endpointPolicy; // Get the number of policy alternatives available in the policy object ULONG alternativeCount; hr = WsGetPolicyAlternativeCount( policy, &alternativeCount, error); if (FAILED(hr)) { goto Exit; } // Create a heap used to allocate fields of initialized values hr = WsCreateHeap(/* maxSize */ 16*1024, /* trimSize */ 2*1024, NULL, 0, &heap, error); if (FAILED(hr)) { goto Exit; } BOOL matchFound = FALSE; // For each alternative in the policy object for (ULONG alternativeIndex = 0; alternativeIndex < alternativeCount; alternativeIndex++) { // This example uses FALSE for the matchRequired parameter to WsMatchPolicyAlternative // which means that the function will return S_FALSE if there is not a match. // If diagnosing why a policy can not be matched, it may be useful to instead set // matchRequired to TRUE meaning an error will be returned (and the error object // will contain information about why the policy did not match). BOOL matchRequired = FALSE; // Try to match policy given the constraints hr = WsMatchPolicyAlternative( policy, alternativeIndex, &policyConstraints, matchRequired, heap, error); if (FAILED(hr)) { goto Exit; } if (hr == S_OK) { // The policy met the constraints matchFound = TRUE; break; } } if (!matchFound) { // None of the policy alternatives matched hr = E_FAIL; goto Exit; } // Initialize channel properties based on the values found in the policy WS_CHANNEL_PROPERTY channelProperties[4]; channelProperties[0] = channelPropertyConstraints[0].out.channelProperty; channelProperties[1] = channelPropertyConstraints[1].out.channelProperty; channelProperties[2] = channelPropertyConstraints[2].out.channelProperty; // Initialize additional channel properties that specify local behavior // that is not part of policy. WS_TRANSFER_MODE transferMode = WS_BUFFERED_TRANSFER_MODE; channelProperties[3].id = WS_CHANNEL_PROPERTY_TRANSFER_MODE; channelProperties[3].value = &transferMode; channelProperties[3].valueSize = sizeof(transferMode); // Initialize security properties based on values extracted from policy WS_SECURITY_PROPERTY securityProperties[1]; securityProperties[0] = securityPropertyConstraints[0].out.securityProperty; // Set up SSL security binding WS_SSL_TRANSPORT_SECURITY_BINDING sslSecurityBinding; ZeroMemory(&sslSecurityBinding, sizeof(sslSecurityBinding)); sslSecurityBinding.binding.bindingType = WS_SSL_TRANSPORT_SECURITY_BINDING_TYPE; if (sslSecurityBindingConstraint.out.clientCertCredentialRequired) { // Server wants a client cert, but this example does not have one hr = E_FAIL; goto Exit; } else { sslSecurityBinding.localCertCredential = NULL; } // The runtime does not support X.509 binding hence use a WS_XML_TOKEN_MESSAGE_SECURITY_BINDING to create a channel WS_XML_TOKEN_MESSAGE_SECURITY_BINDING xmlTokenSecurityBinding; ZeroMemory(&xmlTokenSecurityBinding, sizeof(xmlTokenSecurityBinding)); xmlTokenSecurityBinding.binding.bindingType = WS_XML_TOKEN_MESSAGE_SECURITY_BINDING_TYPE; xmlTokenSecurityBinding.bindingUsage = certSecurityBindingConstraint.bindingUsage; // To obtain a security token to specify for the xmlToken field, use the following steps: // - Find the appropriate certificate and create a X.509 token // - Use WsCreateXmlSecurityToken and to create a security token with the keys from the above X.509 token xmlTokenSecurityBinding.xmlToken = NULL; // Set up security bindings WS_SECURITY_BINDING* securityBindings[2]; securityBindings[0] = &sslSecurityBinding.binding; securityBindings[1] = &xmlTokenSecurityBinding.binding; // Set up security description WS_SECURITY_DESCRIPTION securityDescription; securityDescription.securityBindings = securityBindings; securityDescription.securityBindingCount = WsCountOf(securityBindings); securityDescription.properties = securityProperties; securityDescription.propertyCount = WsCountOf(securityProperties); // Create a channel or proxy to the service using the accumulated binding information: // - channelBinding // - channelProperties // - securityDecription Exit: if (FAILED(hr)) { // Print out the error PrintError(hr, error); } if (metadata != NULL) { WsFreeMetadata(metadata); } if (channel != NULL) { WsFreeChannel(channel); } if (reader != NULL) { WsFreeReader(reader); } if (heap != NULL) { WsFreeHeap(heap); } if (error != NULL) { WsFreeError(error); } fflush(stdout); return SUCCEEDED(hr) ? 0 : -1; }
// Main entry point int __cdecl wmain() { HRESULT hr = S_OK; WS_ERROR* error = NULL; WS_XML_READER* xmlReader = NULL; // Create an error object for storing rich error information hr = WsCreateError( NULL, 0, &error); if (FAILED(hr)) { goto Exit; } // Create an XML reader hr = WsCreateReader( NULL, 0, &xmlReader, error); if (FAILED(hr)) { goto Exit; } // Setup the source input WS_XML_READER_BUFFER_INPUT bufferInput; ZeroMemory(&bufferInput, sizeof(bufferInput)); bufferInput.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER; bufferInput.encodedData = (BYTE*)xml; bufferInput.encodedDataSize = (ULONG)strlen(xml); // Setup the source encoding WS_XML_READER_TEXT_ENCODING textEncoding; ZeroMemory(&textEncoding, sizeof(textEncoding)); textEncoding.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_TEXT; textEncoding.charSet = WS_CHARSET_AUTO; // Setup the reader hr = WsSetInput(xmlReader, &textEncoding.encoding, &bufferInput.input, NULL, 0, error); if (FAILED(hr)) { goto Exit; } hr = WsReadToStartElement(xmlReader, &orders, &nameSpace, NULL, error); if (FAILED(hr)) { goto Exit; } hr = WsReadStartElement(xmlReader, error); if (FAILED(hr)) { goto Exit; } for (;;) { BOOL found; hr = WsReadToStartElement(xmlReader, &purchaseOrder, &nameSpace, &found, error); if (FAILED(hr)) { goto Exit; } if (!found) { break; } // The attribute we're looking for is from the empty namespace ULONG index; hr = WsFindAttribute(xmlReader, &id, &emptyNamespace, TRUE, &index, error); if (FAILED(hr)) { goto Exit; } hr = WsReadStartAttribute(xmlReader, index, error); if (FAILED(hr)) { goto Exit; } __int32 value; hr = WsReadValue(xmlReader, WS_INT32_VALUE_TYPE, &value, sizeof(value), error); if (FAILED(hr)) { goto Exit; } printf("Id='%d'\n", value); hr = WsReadEndAttribute(xmlReader, error); if (FAILED(hr)) { goto Exit; } hr = WsSkipNode(xmlReader, error); if (FAILED(hr)) { goto Exit; } } hr = WsReadEndElement(xmlReader, error); if (FAILED(hr)) { goto Exit; } Exit: if (FAILED(hr)) { // Print out the error PrintError(hr, error); } if (xmlReader != NULL) { WsFreeReader(xmlReader); } if (error != NULL) { WsFreeError(error); } fflush(stdout); return SUCCEEDED(hr) ? 0 : -1; }
HRESULT CreateXmlSecurityToken( __deref_out WS_SECURITY_TOKEN** xmlSecurityToken, __in_opt WS_ERROR* error) { HRESULT hr = S_OK; WS_HEAP* heap = NULL; WS_XML_READER* reader = NULL; WS_XML_BUFFER* buffer = NULL; // The username/password are included in code for the simplicity // of the sample. This should NOT be done for real applications. char* securityTokenWireXmlForm = "<x:UsernameToken xmlns:x='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'><x:Username>usr1</x:Username><x:Password>pwd1</x:Password></x:UsernameToken>"; // create an XML reader hr = WsCreateReader( NULL, 0, &reader, error); if (FAILED(hr)) { goto Exit; } // define the input and encoding for the XML reader WS_XML_READER_BUFFER_INPUT readerInput; ZeroMemory(&readerInput, sizeof(readerInput)); readerInput.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER; readerInput.encodedData = securityTokenWireXmlForm; readerInput.encodedDataSize = (ULONG)strlen(securityTokenWireXmlForm); WS_XML_READER_TEXT_ENCODING readerEncoding; ZeroMemory(&readerEncoding, sizeof(readerEncoding)); readerEncoding.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_TEXT; readerEncoding.charSet = WS_CHARSET_UTF8; // set the input and encoding for the XML reader hr = WsSetInput( reader, &readerEncoding.encoding, &readerInput.input, NULL, 0, error); if (FAILED(hr)) { goto Exit; } // create a heap to read the security token XML form into an XML buffer allocated on that heap hr = WsCreateHeap( 2048, 512, NULL, 0, &heap, error); if (FAILED(hr)) { goto Exit; } // read the security token XML form into an XML buffer hr = WsReadType( reader, WS_ELEMENT_TYPE_MAPPING, WS_XML_BUFFER_TYPE, NULL, WS_READ_REQUIRED_POINTER, heap, &buffer, sizeof(buffer), error); if (FAILED(hr)) { goto Exit; } // create an XML security token from the token's wire form available in the XML buffer hr = WsCreateXmlSecurityToken( buffer, NULL, NULL, 0, xmlSecurityToken, error); Exit: // The heap, and the XML buffer allocated on it, need not be kept // alive once the token creation call returns. Note that the XML // buffer allocated on the heap is automatically freed along with // the heap, and is never freed directly. if (heap != NULL) { WsFreeHeap( heap); } if (reader != NULL) { WsFreeReader( reader); } return hr; }
// Main entry point int __cdecl wmain() { HRESULT hr = S_OK; WS_ERROR* error = NULL; WS_XML_WRITER* writer = NULL; WS_XML_READER* reader = NULL; WS_HEAP* heap = NULL; // Create an error object for storing rich error information hr = WsCreateError( NULL, 0, &error); if (FAILED(hr)) { goto Exit; } // Create a heap to store deserialized data hr = WsCreateHeap( /*maxSize*/ 2048, /*trimSize*/ 512, NULL, 0, &heap, error); if (FAILED(hr)) { goto Exit; } // Create an XML writer hr = WsCreateWriter( NULL, 0, &writer, error); if (FAILED(hr)) { goto Exit; } // Setup the output WS_XML_WRITER_BUFFER_OUTPUT bufferOutput; ZeroMemory(&bufferOutput, sizeof(bufferOutput)); bufferOutput.output.outputType = WS_XML_WRITER_OUTPUT_TYPE_BUFFER; // Setup the encoding WS_XML_WRITER_BINARY_ENCODING writerEncoding; ZeroMemory(&writerEncoding, sizeof(writerEncoding)); writerEncoding.encoding.encodingType = WS_XML_WRITER_ENCODING_TYPE_BINARY; writerEncoding.staticDictionary = &objectsDictionary.dictionary; writerEncoding.dynamicStringCallback = DynamicStringCallback; writerEncoding.dynamicStringCallbackState = NULL; // Setup the writer hr = WsSetOutput( writer, &writerEncoding.encoding, &bufferOutput.output, NULL, 0, error); if (FAILED(hr)) { goto Exit; } hr = WsWriteStartElement( writer, NULL, &objectsDictionary.objects, &objectsDictionary.ns, error); if (FAILED(hr)) { goto Exit; } // Write some xml using strings from all the dictionaries static const WS_XML_STRING* shapes[3] = { &shapeDictionary.triangle, &shapeDictionary.square, &shapeDictionary.circle }; static const WS_XML_STRING* colors[3] = { &colorDictionary.green, &colorDictionary.blue, &colorDictionary.red }; for (ULONG i = 0; i < 3; i++) { hr = WsWriteStartElement( writer, NULL, shapes[i], &objectsDictionary.ns, error); if (FAILED(hr)) { goto Exit; } hr = WsWriteStartAttribute( writer, NULL, &objectsDictionary.color, &objectsDictionary.ns, FALSE, error); if (FAILED(hr)) { goto Exit; } hr = WsWriteType( writer, WS_ATTRIBUTE_TYPE_MAPPING, WS_XML_STRING_TYPE, NULL, WS_WRITE_REQUIRED_VALUE, colors[i], sizeof(*colors[i]), error); if (FAILED(hr)) { goto Exit; } hr = WsWriteEndAttribute( writer, error); if (FAILED(hr)) { goto Exit; } hr = WsWriteEndElement( writer, error); if (FAILED(hr)) { goto Exit; } } hr = WsWriteEndElement( writer, error); if (FAILED(hr)) { goto Exit; } WS_BYTES bytes; hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, sizeof(bytes), error); if (FAILED(hr)) { goto Exit; } // Create an XML reader hr = WsCreateReader( NULL, 0, &reader, error); if (FAILED(hr)) { goto Exit; } // Setup the input WS_XML_READER_BUFFER_INPUT bufferInput; ZeroMemory(&bufferInput, sizeof(bufferInput)); bufferInput.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER; bufferInput.encodedData = bytes.bytes; bufferInput.encodedDataSize = bytes.length; // Setup the encoding WS_XML_READER_BINARY_ENCODING readerEncoding; ZeroMemory( &readerEncoding, sizeof(readerEncoding)); readerEncoding.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_BINARY; readerEncoding.staticDictionary = &objectsDictionary.dictionary; readerEncoding.dynamicDictionary = &mergedDictionary.dictionary; // Setup the reader hr = WsSetInput( reader, &readerEncoding.encoding, &bufferInput.input, NULL, 0, error); if (FAILED(hr)) { goto Exit; } hr = WsReadToStartElement( reader, &objectsDictionary.objects, &objectsDictionary.ns, NULL, error); if (FAILED(hr)) { goto Exit; } hr = WsReadStartElement( reader, error); if (FAILED(hr)) { goto Exit; } for (;;) { BOOL found; hr = WsReadToStartElement( reader, NULL, NULL, &found, error); if (FAILED(hr)) { goto Exit; } if (!found) { break; } const WS_XML_NODE* node; hr = WsGetReaderNode( reader, &node, error); if (FAILED(hr)) { goto Exit; } const WS_XML_ELEMENT_NODE* elementNode = (WS_XML_ELEMENT_NODE*)node; printf("%.*s: ", elementNode->localName->length, elementNode->localName->bytes); ULONG index; hr = WsFindAttribute( reader, &objectsDictionary.color, &objectsDictionary.ns, TRUE, &index, error); if (FAILED(hr)) { goto Exit; } hr = WsReadStartAttribute( reader, index, error); if (FAILED(hr)) { goto Exit; } WS_XML_STRING color; hr = WsReadType( reader, WS_ATTRIBUTE_TYPE_MAPPING, WS_XML_STRING_TYPE, NULL, WS_READ_REQUIRED_VALUE, heap, &color, sizeof(color), error); if (FAILED(hr)) { goto Exit; } printf( "%.*s\n", color.length, color.bytes); hr = WsReadEndAttribute( reader, error); if (FAILED(hr)) { goto Exit; } hr = WsSkipNode( reader, error); if (FAILED(hr)) { goto Exit; } } hr = WsReadEndElement( reader, error); if (FAILED(hr)) { goto Exit; } Exit: if (FAILED(hr)) { // Print out the error PrintError(hr, error); } if (writer != NULL) { WsFreeWriter(writer); } if (reader != NULL) { WsFreeReader(reader); } if (heap != NULL) { WsFreeHeap(heap); } if (error != NULL) { WsFreeError(error); } fflush(stdout); return SUCCEEDED(hr) ? 0 : -1; }
// Main entry point int __cdecl wmain() { HRESULT hr = S_OK; WS_ERROR* error = NULL; WS_XML_READER* xmlReader = NULL; // Create an error object for storing rich error information hr = WsCreateError( NULL, 0, &error); if (FAILED(hr)) { goto Exit; } // Create an XML reader hr = WsCreateReader( NULL, 0, &xmlReader, error); if (FAILED(hr)) { goto Exit; } char* xml = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" "<Orders xmlns='http://example.com'>" "<!-- Order #1 -->" "<PurchaseOrder id='1'>" "<Quantity>42</Quantity>" "<ProductName>Toaster</ProductName>" "</PurchaseOrder>" "<!-- Order #2 -->" "<PurchaseOrder id='2'>" "<Quantity>5</Quantity>" "<ProductName><![CDATA[Block&Tackle]]></ProductName>" "</PurchaseOrder>" "</Orders>"; BYTE* bytes = (BYTE*) xml; ULONG byteCount = (ULONG)strlen(xml); // Setup the source input WS_XML_READER_BUFFER_INPUT bufferInput; ZeroMemory(&bufferInput, sizeof(bufferInput)); bufferInput.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER; bufferInput.encodedData = bytes; bufferInput.encodedDataSize = byteCount; // Setup the source encoding WS_XML_READER_TEXT_ENCODING textEncoding; ZeroMemory(&textEncoding, sizeof(textEncoding)); textEncoding.encoding.encodingType = WS_XML_READER_ENCODING_TYPE_TEXT; textEncoding.charSet = WS_CHARSET_AUTO; // Setup the reader hr = WsSetInput(xmlReader, &textEncoding.encoding, &bufferInput.input, NULL, 0, error); if (FAILED(hr)) { goto Exit; } WS_CHARSET charSet; hr = WsGetReaderProperty(xmlReader, WS_XML_READER_PROPERTY_CHARSET, &charSet, sizeof(charSet), error); if (FAILED(hr)) { goto Exit; } switch (charSet) { case WS_CHARSET_UTF8: printf("charSet=utf-8\n"); break; case WS_CHARSET_UTF16LE: printf("charSet=utf-16LE\n"); break; case WS_CHARSET_UTF16BE: printf("charSet=utf-16BE\n"); break; default: printf("<error: Unexpected charset>\n"); hr = E_FAIL; goto Exit; } ULONG depth = 0; for (;;) { // Get the current node of the reader const WS_XML_NODE* node; hr = WsGetReaderNode(xmlReader, &node, error); if (FAILED(hr)) { goto Exit; } for (ULONG i = 0; i < depth; i++) { printf(" "); } // Print out the type of node and its contents switch (node->nodeType) { case WS_XML_NODE_TYPE_ELEMENT: { const WS_XML_ELEMENT_NODE* elementNode = (const WS_XML_ELEMENT_NODE*) node; printf("WS_XML_NODE_TYPE_ELEMENT(prefix='"); PrintString(elementNode->prefix); printf("', localName='"); PrintString(elementNode->localName); printf("', ns='"); PrintString(elementNode->ns); printf("', attributes={"); for (ULONG i = 0; i < elementNode->attributeCount; i++) { if (i != 0) { printf(", "); } const WS_XML_ATTRIBUTE* attribute = elementNode->attributes[i]; if (attribute->isXmlNs) { printf("(isXmlNs=TRUE, prefix='"); PrintString(attribute->prefix); printf("', ns='"); PrintString(attribute->ns); printf("')"); } else { printf("(isXmlNs=FALSE, prefix='"); PrintString(attribute->prefix); printf("', localName='"); PrintString(attribute->localName); printf("', ns='"); PrintString(attribute->ns); printf("', value="); PrintText(attribute->value); printf(")"); } } printf("})\n"); } depth++; break; case WS_XML_NODE_TYPE_END_ELEMENT: printf("WS_XML_NODE_TYPE_END_ELEMENT\n"); depth--; break; case WS_XML_NODE_TYPE_TEXT: { const WS_XML_TEXT_NODE* textNode = (const WS_XML_TEXT_NODE*) node; printf("WS_XML_NODE_TYPE_TEXT(value="); PrintText(textNode->text); printf(")\n"); } break; case WS_XML_NODE_TYPE_CDATA: printf("WS_XML_NODE_TYPE_CDATA\n"); depth++; break; case WS_XML_NODE_TYPE_END_CDATA: printf("WS_XML_NODE_TYPE_END_CDATA\n"); depth--; break; case WS_XML_NODE_TYPE_COMMENT: { const WS_XML_COMMENT_NODE* commentNode = (const WS_XML_COMMENT_NODE*) node; printf("WS_XML_NODE_TYPE_COMMENT(value='"); PrintString(&commentNode->value); printf("')\n"); } break; case WS_XML_NODE_TYPE_BOF: printf("WS_XML_NODE_TYPE_BOF\n"); depth++; break; case WS_XML_NODE_TYPE_EOF: printf("WS_XML_NODE_TYPE_EOF\n"); depth--; break; default: printf("<error: Unexpected nodeType>\n"); hr = E_FAIL; goto Exit; } // See if we've reached the end of the document if (node->nodeType == WS_XML_NODE_TYPE_EOF) { break; } // Advance the reader hr = WsReadNode(xmlReader, error); if (FAILED(hr)) { goto Exit; } } Exit: if (FAILED(hr)) { // Print out the error PrintError(hr, error); } if (xmlReader != NULL) { WsFreeReader(xmlReader); } if (error != NULL) { WsFreeError(error); } fflush(stdout); return SUCCEEDED(hr) ? 0 : -1; }