/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include "UCBDeadPropertyValue.hxx" using namespace http_dav_ucp; using namespace ::com::sun::star; ////////////////////////////////////////////////////////////////////////// struct UCBDeadPropertyValueParseContext { OUString * pType; OUString * pValue; UCBDeadPropertyValueParseContext() : pType( 0 ), pValue( 0 ) {} ~UCBDeadPropertyValueParseContext() { delete pType; delete pValue; } }; // static const OUString UCBDeadPropertyValue::aTypeString = OUString( "string" ); const OUString UCBDeadPropertyValue::aTypeLong = OUString( "long" ); const OUString UCBDeadPropertyValue::aTypeShort = OUString( "short" ); const OUString UCBDeadPropertyValue::aTypeBoolean = OUString( "boolean" ); const OUString UCBDeadPropertyValue::aTypeChar = OUString( "char" ); const OUString UCBDeadPropertyValue::aTypeByte = OUString( "byte" ); const OUString UCBDeadPropertyValue::aTypeHyper = OUString( "hyper" ); const OUString UCBDeadPropertyValue::aTypeFloat = OUString( "float" ); const OUString UCBDeadPropertyValue::aTypeDouble = OUString( "double" ); // static const OUString UCBDeadPropertyValue::aXMLPre = OUString( "" ); const OUString UCBDeadPropertyValue::aXMLMid = OUString( "" ); const OUString UCBDeadPropertyValue::aXMLEnd = OUString( "" ); #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 OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); break; case STATE_VALUE: OSL_ENSURE( !pCtx->pValue, "UCBDeadPropertyValue_endelement_callback - " "Value already set!" ); pCtx->pValue = new 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 OUString encodeValue( const 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: xstringx<z // PROPFIND: // - parser replaces < by > ==> error (not well formed) 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 OUString( aResult ); } /* ////////////////////////////////////////////////////////////////////////// static OUString decodeValue( const OUString & rValue ) { 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 OUString(); } c = pValue[ nPos ]; if ( 'p' == c ) { // %per; if ( nPos > nEnd - 4 ) { OSL_ENSURE( sal_False, "UCBDeadPropertyValue::decodeValue - syntax error!" ); return OUString(); } if ( ( 'e' == pValue[ nPos + 1 ] ) && ( 'r' == pValue[ nPos + 2 ] ) && ( ';' == pValue[ nPos + 3 ] ) ) { aResult.append( '%' ); nPos += 3; } else { OSL_ENSURE( sal_False, "UCBDeadPropertyValue::decodeValue - syntax error!" ); return OUString(); } } else if ( 'l' == c ) { // %lt; if ( nPos > nEnd - 3 ) { OSL_ENSURE( sal_False, "UCBDeadPropertyValue::decodeValue - syntax error!" ); return OUString(); } if ( ( 't' == pValue[ nPos + 1 ] ) && ( ';' == pValue[ nPos + 2 ] ) ) { aResult.append( '<' ); nPos += 2; } else { OSL_ENSURE( sal_False, "UCBDeadPropertyValue::decodeValue - syntax error!" ); return OUString(); } } else if ( 'g' == c ) { // %gt; if ( nPos > nEnd - 3 ) { OSL_ENSURE( sal_False, "UCBDeadPropertyValue::decodeValue - syntax error!" ); return OUString(); } if ( ( 't' == pValue[ nPos + 1 ] ) && ( ';' == pValue[ nPos + 2 ] ) ) { aResult.append( '>' ); nPos += 2; } else { OSL_ENSURE( sal_False, "UCBDeadPropertyValue::decodeValue - syntax error!" ); return OUString(); } } else { OSL_ENSURE( sal_False, "UCBDeadPropertyValue::decodeValue - syntax error!" ); return OUString(); } } else aResult.append( c ); nPos++; } return OUString( aResult ); } */ ////////////////////////////////////////////////////////////////////////// // static bool UCBDeadPropertyValue::supportsType( const uno::Type & rType ) { if ( ( rType != getCppuType( static_cast< const 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 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. 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( OUString( "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, OUString & rOutData ) { // the_typethe_value // Check property type. Extract type and value as string. const uno::Type& rType = rInData.getValueType(); OUString aStringValue; OUString aStringType; if ( rType == getCppuType( static_cast< const 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 = OUString::valueOf( nValue ); aStringType = aTypeLong; } else if ( rType == getCppuType( static_cast< const sal_Int16 * >( 0 ) ) ) { // short sal_Int32 nValue = 0; rInData >>= nValue; aStringValue = OUString::valueOf( nValue ); aStringType = aTypeShort; } else if ( rType == getCppuBooleanType() ) { // boolean sal_Bool bValue = false; rInData >>= bValue; aStringValue = OUString::valueOf( bValue ); aStringType = aTypeBoolean; } else if ( rType == getCppuCharType() ) { // char sal_Unicode cValue = 0; rInData >>= cValue; aStringValue = OUString::valueOf( cValue ); aStringType = aTypeChar; } else if ( rType == getCppuType( static_cast< const sal_Int8 * >( 0 ) ) ) { // byte sal_Int8 nValue = 0; rInData >>= nValue; aStringValue = 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 = OUString::valueOf( nValue ); aStringType = aTypeHyper; } else if ( rType == getCppuType( static_cast< const float * >( 0 ) ) ) { // float float nValue = 0; rInData >>= nValue; aStringValue = OUString::valueOf( nValue ); aStringType = aTypeFloat; } else if ( rType == getCppuType( static_cast< const double * >( 0 ) ) ) { // double double nValue = 0; rInData >>= nValue; aStringValue = 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; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */