| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_ucb.hxx" |
| |
| #include <string.h> |
| //#include <ne_xml.h> |
| #include <osl/diagnose.h> |
| #include <rtl/ustrbuf.hxx> |
| #include "UCBDeadPropertyValue.hxx" |
| |
| using namespace http_dav_ucp; |
| using namespace ::com::sun::star; |
| |
| ////////////////////////////////////////////////////////////////////////// |
| |
| struct UCBDeadPropertyValueParseContext |
| { |
| rtl::OUString * pType; |
| rtl::OUString * pValue; |
| |
| UCBDeadPropertyValueParseContext() : pType( 0 ), pValue( 0 ) {} |
| ~UCBDeadPropertyValueParseContext() { delete pType; delete pValue; } |
| }; |
| |
| // static |
| const rtl::OUString UCBDeadPropertyValue::aTypeString |
| = rtl::OUString::createFromAscii( "string" ); |
| const rtl::OUString UCBDeadPropertyValue::aTypeLong |
| = rtl::OUString::createFromAscii( "long" ); |
| const rtl::OUString UCBDeadPropertyValue::aTypeShort |
| = rtl::OUString::createFromAscii( "short" ); |
| const rtl::OUString UCBDeadPropertyValue::aTypeBoolean |
| = rtl::OUString::createFromAscii( "boolean" ); |
| const rtl::OUString UCBDeadPropertyValue::aTypeChar |
| = rtl::OUString::createFromAscii( "char" ); |
| const rtl::OUString UCBDeadPropertyValue::aTypeByte |
| = rtl::OUString::createFromAscii( "byte" ); |
| const rtl::OUString UCBDeadPropertyValue::aTypeHyper |
| = rtl::OUString::createFromAscii( "hyper" ); |
| const rtl::OUString UCBDeadPropertyValue::aTypeFloat |
| = rtl::OUString::createFromAscii( "float" ); |
| const rtl::OUString UCBDeadPropertyValue::aTypeDouble |
| = rtl::OUString::createFromAscii( "double" ); |
| |
| // static |
| const rtl::OUString UCBDeadPropertyValue::aXMLPre |
| = rtl::OUString::createFromAscii( "<ucbprop><type>" ); |
| const rtl::OUString UCBDeadPropertyValue::aXMLMid |
| = rtl::OUString::createFromAscii( "</type><value>" ); |
| const rtl::OUString UCBDeadPropertyValue::aXMLEnd |
| = rtl::OUString::createFromAscii( "</value></ucbprop>" ); |
| |
| #define STATE_TOP (1) |
| |
| #define STATE_UCBPROP (STATE_TOP) |
| #define STATE_TYPE (STATE_TOP + 1) |
| #define STATE_VALUE (STATE_TOP + 2) |
| |
| /* |
| ////////////////////////////////////////////////////////////////////////// |
| extern "C" int UCBDeadPropertyValue_startelement_callback( |
| void *, |
| int parent, |
| const char * nspace, |
| const char *name, |
| const char ** ) |
| { |
| if ( name != 0 ) |
| { |
| switch ( parent ) |
| { |
| case NE_XML_STATEROOT: |
| if ( strcmp( name, "ucbprop" ) == 0 ) |
| return STATE_UCBPROP; |
| break; |
| |
| case STATE_UCBPROP: |
| if ( strcmp( name, "type" ) == 0 ) |
| return STATE_TYPE; |
| else if ( strcmp( name, "value" ) == 0 ) |
| return STATE_VALUE; |
| break; |
| } |
| } |
| return NE_XML_DECLINE; |
| } |
| |
| ////////////////////////////////////////////////////////////////////////// |
| extern "C" int UCBDeadPropertyValue_chardata_callback( |
| void *userdata, |
| int state, |
| const char *buf, |
| size_t len ) |
| { |
| UCBDeadPropertyValueParseContext * pCtx |
| = static_cast< UCBDeadPropertyValueParseContext * >( userdata ); |
| |
| switch ( state ) |
| { |
| case STATE_TYPE: |
| OSL_ENSURE( !pCtx->pType, |
| "UCBDeadPropertyValue_endelement_callback - " |
| "Type already set!" ); |
| pCtx->pType |
| = new rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); |
| break; |
| |
| case STATE_VALUE: |
| OSL_ENSURE( !pCtx->pValue, |
| "UCBDeadPropertyValue_endelement_callback - " |
| "Value already set!" ); |
| pCtx->pValue |
| = new rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); |
| break; |
| } |
| return 0; // zero to continue, non-zero to abort parsing |
| } |
| |
| ////////////////////////////////////////////////////////////////////////// |
| extern "C" int UCBDeadPropertyValue_endelement_callback( |
| void *userdata, |
| int state, |
| const char *, |
| const char * ) |
| { |
| UCBDeadPropertyValueParseContext * pCtx |
| = static_cast< UCBDeadPropertyValueParseContext * >( userdata ); |
| |
| switch ( state ) |
| { |
| case STATE_TYPE: |
| if ( !pCtx->pType ) |
| return 1; // abort |
| break; |
| |
| case STATE_VALUE: |
| if ( !pCtx->pValue ) |
| return 1; // abort |
| break; |
| |
| case STATE_UCBPROP: |
| if ( !pCtx->pType || ! pCtx->pValue ) |
| return 1; // abort |
| break; |
| } |
| return 0; // zero to continue, non-zero to abort parsing |
| } |
| */ |
| |
| ////////////////////////////////////////////////////////////////////////// |
| static rtl::OUString encodeValue( const rtl::OUString & rValue ) |
| { |
| // Note: I do not use the usual & + < + > encoding, because |
| // I want to prevent any XML parser from trying to 'understand' |
| // the value. This caused problems: |
| // |
| // Example: |
| // - Unencoded property value: x<z |
| // PROPPATCH: |
| // - Encoded property value: x<z |
| // - UCBDeadPropertyValue::toXML result: |
| // <ucbprop><type>string</type><value>x<z</value></ucbprop> |
| // PROPFIND: |
| // - parser replaces < by > ==> error (not well formed) |
| |
| rtl::OUStringBuffer aResult; |
| const sal_Unicode * pValue = rValue.getStr(); |
| |
| sal_Int32 nCount = rValue.getLength(); |
| for ( sal_Int32 n = 0; n < nCount; ++n ) |
| { |
| const sal_Unicode c = pValue[ n ]; |
| |
| if ( '%' == c ) |
| aResult.appendAscii( "%per;" ); |
| else if ( '<' == c ) |
| aResult.appendAscii( "%lt;" ); |
| else if ( '>' == c ) |
| aResult.appendAscii( "%gt;" ); |
| else |
| aResult.append( c ); |
| } |
| return rtl::OUString( aResult ); |
| } |
| |
| /* |
| ////////////////////////////////////////////////////////////////////////// |
| static rtl::OUString decodeValue( const rtl::OUString & rValue ) |
| { |
| rtl::OUStringBuffer aResult; |
| const sal_Unicode * pValue = rValue.getStr(); |
| |
| sal_Int32 nPos = 0; |
| sal_Int32 nEnd = rValue.getLength(); |
| |
| while ( nPos < nEnd ) |
| { |
| sal_Unicode c = pValue[ nPos ]; |
| |
| if ( '%' == c ) |
| { |
| nPos++; |
| |
| if ( nPos == nEnd ) |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::decodeValue - syntax error!" ); |
| return rtl::OUString(); |
| } |
| |
| c = pValue[ nPos ]; |
| |
| if ( 'p' == c ) |
| { |
| // %per; |
| |
| if ( nPos > nEnd - 4 ) |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::decodeValue - syntax error!" ); |
| return rtl::OUString(); |
| } |
| |
| if ( ( 'e' == pValue[ nPos + 1 ] ) |
| && |
| ( 'r' == pValue[ nPos + 2 ] ) |
| && |
| ( ';' == pValue[ nPos + 3 ] ) ) |
| { |
| aResult.append( sal_Unicode( '%' ) ); |
| nPos += 3; |
| } |
| else |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::decodeValue - syntax error!" ); |
| return rtl::OUString(); |
| } |
| } |
| else if ( 'l' == c ) |
| { |
| // %lt; |
| |
| if ( nPos > nEnd - 3 ) |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::decodeValue - syntax error!" ); |
| return rtl::OUString(); |
| } |
| |
| if ( ( 't' == pValue[ nPos + 1 ] ) |
| && |
| ( ';' == pValue[ nPos + 2 ] ) ) |
| { |
| aResult.append( sal_Unicode( '<' ) ); |
| nPos += 2; |
| } |
| else |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::decodeValue - syntax error!" ); |
| return rtl::OUString(); |
| } |
| } |
| else if ( 'g' == c ) |
| { |
| // %gt; |
| |
| if ( nPos > nEnd - 3 ) |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::decodeValue - syntax error!" ); |
| return rtl::OUString(); |
| } |
| |
| if ( ( 't' == pValue[ nPos + 1 ] ) |
| && |
| ( ';' == pValue[ nPos + 2 ] ) ) |
| { |
| aResult.append( sal_Unicode( '>' ) ); |
| nPos += 2; |
| } |
| else |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::decodeValue - syntax error!" ); |
| return rtl::OUString(); |
| } |
| } |
| else |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::decodeValue - syntax error!" ); |
| return rtl::OUString(); |
| } |
| } |
| else |
| aResult.append( c ); |
| |
| nPos++; |
| } |
| |
| return rtl::OUString( aResult ); |
| } |
| */ |
| |
| ////////////////////////////////////////////////////////////////////////// |
| // static |
| bool UCBDeadPropertyValue::supportsType( const uno::Type & rType ) |
| { |
| if ( ( rType != getCppuType( static_cast< const rtl::OUString * >( 0 ) ) ) |
| && |
| ( rType != getCppuType( static_cast< const sal_Int32 * >( 0 ) ) ) |
| && |
| ( rType != getCppuType( static_cast< const sal_Int16 * >( 0 ) ) ) |
| && |
| ( rType != getCppuBooleanType() ) |
| && |
| ( rType != getCppuCharType() ) |
| && |
| ( rType != getCppuType( static_cast< const sal_Int8 * >( 0 ) ) ) |
| && |
| ( rType != getCppuType( static_cast< const sal_Int64 * >( 0 ) ) ) |
| && |
| ( rType != getCppuType( static_cast< const float * >( 0 ) ) ) |
| && |
| ( rType != getCppuType( static_cast< const double * >( 0 ) ) ) ) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| ////////////////////////////////////////////////////////////////////////// |
| // static |
| bool UCBDeadPropertyValue::createFromXML( const rtl::OString & /*rInData*/, |
| uno::Any & /*rOutData*/ ) |
| { |
| bool success = false; |
| |
| /* |
| ne_xml_parser * parser = ne_xml_create(); |
| if ( parser ) |
| { |
| UCBDeadPropertyValueParseContext aCtx; |
| ne_xml_push_handler( parser, |
| UCBDeadPropertyValue_startelement_callback, |
| UCBDeadPropertyValue_chardata_callback, |
| UCBDeadPropertyValue_endelement_callback, |
| &aCtx ); |
| |
| ne_xml_parse( parser, rInData.getStr(), rInData.getLength() ); |
| |
| success = !ne_xml_failed( parser ); |
| |
| ne_xml_destroy( parser ); |
| |
| if ( success ) |
| { |
| if ( aCtx.pType && aCtx.pValue ) |
| { |
| // Decode aCtx.pValue! It may contain XML reserved chars. |
| rtl::OUString aStringValue = decodeValue( *aCtx.pValue ); |
| if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeString ) ) |
| { |
| rOutData <<= aStringValue; |
| } |
| else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeLong ) ) |
| { |
| rOutData <<= aStringValue.toInt32(); |
| } |
| else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeShort ) ) |
| { |
| rOutData <<= sal_Int16( aStringValue.toInt32() ); |
| } |
| else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeBoolean ) ) |
| { |
| if ( aStringValue.equalsIgnoreAsciiCase( |
| rtl::OUString::createFromAscii( "true" ) ) ) |
| rOutData <<= sal_Bool( sal_True ); |
| else |
| rOutData <<= sal_Bool( sal_False ); |
| } |
| else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeChar ) ) |
| { |
| rOutData <<= aStringValue.toChar(); |
| } |
| else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeByte ) ) |
| { |
| rOutData <<= sal_Int8( aStringValue.toChar() ); |
| } |
| else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeHyper ) ) |
| { |
| rOutData <<= aStringValue.toInt64(); |
| } |
| else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeFloat ) ) |
| { |
| rOutData <<= aStringValue.toFloat(); |
| } |
| else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeDouble ) ) |
| { |
| rOutData <<= aStringValue.toDouble(); |
| } |
| else |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::createFromXML - " |
| "Unsupported property type!" ); |
| success = false; |
| } |
| } |
| else |
| success = false; |
| } |
| } |
| */ |
| return success; |
| } |
| |
| ////////////////////////////////////////////////////////////////////////// |
| // static |
| bool UCBDeadPropertyValue::toXML( const uno::Any & rInData, |
| rtl::OUString & rOutData ) |
| { |
| // <ucbprop><type>the_type</type><value>the_value</value></ucbprop> |
| |
| // Check property type. Extract type and value as string. |
| |
| const uno::Type& rType = rInData.getValueType(); |
| rtl::OUString aStringValue; |
| rtl::OUString aStringType; |
| |
| if ( rType == getCppuType( static_cast< const rtl::OUString * >( 0 ) ) ) |
| { |
| // string |
| rInData >>= aStringValue; |
| aStringType = aTypeString; |
| } |
| else if ( rType == getCppuType( static_cast< const sal_Int32 * >( 0 ) ) ) |
| { |
| // long |
| sal_Int32 nValue = 0; |
| rInData >>= nValue; |
| aStringValue = rtl::OUString::valueOf( nValue ); |
| aStringType = aTypeLong; |
| } |
| else if ( rType == getCppuType( static_cast< const sal_Int16 * >( 0 ) ) ) |
| { |
| // short |
| sal_Int32 nValue = 0; |
| rInData >>= nValue; |
| aStringValue = rtl::OUString::valueOf( nValue ); |
| aStringType = aTypeShort; |
| } |
| else if ( rType == getCppuBooleanType() ) |
| { |
| // boolean |
| sal_Bool bValue = false; |
| rInData >>= bValue; |
| aStringValue = rtl::OUString::valueOf( bValue ); |
| aStringType = aTypeBoolean; |
| } |
| else if ( rType == getCppuCharType() ) |
| { |
| // char |
| sal_Unicode cValue = 0; |
| rInData >>= cValue; |
| aStringValue = rtl::OUString::valueOf( cValue ); |
| aStringType = aTypeChar; |
| } |
| else if ( rType == getCppuType( static_cast< const sal_Int8 * >( 0 ) ) ) |
| { |
| // byte |
| sal_Int8 nValue = 0; |
| rInData >>= nValue; |
| aStringValue = rtl::OUString::valueOf( sal_Unicode( nValue ) ); |
| aStringType = aTypeByte; |
| } |
| else if ( rType == getCppuType( static_cast< const sal_Int64 * >( 0 ) ) ) |
| { |
| // hyper |
| sal_Int64 nValue = 0; |
| rInData >>= nValue; |
| aStringValue = rtl::OUString::valueOf( nValue ); |
| aStringType = aTypeHyper; |
| } |
| else if ( rType == getCppuType( static_cast< const float * >( 0 ) ) ) |
| { |
| // float |
| float nValue = 0; |
| rInData >>= nValue; |
| aStringValue = rtl::OUString::valueOf( nValue ); |
| aStringType = aTypeFloat; |
| } |
| else if ( rType == getCppuType( static_cast< const double * >( 0 ) ) ) |
| { |
| // double |
| double nValue = 0; |
| rInData >>= nValue; |
| aStringValue = rtl::OUString::valueOf( nValue ); |
| aStringType = aTypeDouble; |
| } |
| else |
| { |
| OSL_ENSURE( sal_False, |
| "UCBDeadPropertyValue::toXML - " |
| "Unsupported property type!" ); |
| return false; |
| } |
| |
| // Encode value! It must not contain XML reserved chars! |
| aStringValue = encodeValue( aStringValue ); |
| |
| rOutData = aXMLPre; |
| rOutData += aStringType; |
| rOutData += aXMLMid; |
| rOutData += aStringValue; |
| rOutData += aXMLEnd; |
| return true; |
| } |