524 lines
17 KiB
C++
524 lines
17 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 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 webdav_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_CONSTASCII_USTRINGPARAM("string"));
|
|
const rtl::OUString UCBDeadPropertyValue::aTypeLong(RTL_CONSTASCII_USTRINGPARAM("long"));
|
|
const rtl::OUString UCBDeadPropertyValue::aTypeShort(RTL_CONSTASCII_USTRINGPARAM("short"));
|
|
const rtl::OUString UCBDeadPropertyValue::aTypeBoolean(RTL_CONSTASCII_USTRINGPARAM("boolean"));
|
|
const rtl::OUString UCBDeadPropertyValue::aTypeChar(RTL_CONSTASCII_USTRINGPARAM("char"));
|
|
const rtl::OUString UCBDeadPropertyValue::aTypeByte(RTL_CONSTASCII_USTRINGPARAM("byte"));
|
|
const rtl::OUString UCBDeadPropertyValue::aTypeHyper(RTL_CONSTASCII_USTRINGPARAM("hyper"));
|
|
const rtl::OUString UCBDeadPropertyValue::aTypeFloat(RTL_CONSTASCII_USTRINGPARAM("float"));
|
|
const rtl::OUString UCBDeadPropertyValue::aTypeDouble(RTL_CONSTASCII_USTRINGPARAM("double"));
|
|
|
|
// static
|
|
const rtl::OUString UCBDeadPropertyValue::aXMLPre(RTL_CONSTASCII_USTRINGPARAM("<ucbprop><type>"));
|
|
const rtl::OUString UCBDeadPropertyValue::aXMLMid(RTL_CONSTASCII_USTRINGPARAM("</type><value>"));
|
|
const rtl::OUString UCBDeadPropertyValue::aXMLEnd(RTL_CONSTASCII_USTRINGPARAM("</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_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
|
|
return rtl::OUString();
|
|
}
|
|
|
|
c = pValue[ nPos ];
|
|
|
|
if ( 'p' == c )
|
|
{
|
|
// %per;
|
|
|
|
if ( nPos > nEnd - 4 )
|
|
{
|
|
OSL_FAIL( "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_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
|
|
return rtl::OUString();
|
|
}
|
|
}
|
|
else if ( 'l' == c )
|
|
{
|
|
// %lt;
|
|
|
|
if ( nPos > nEnd - 3 )
|
|
{
|
|
OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
|
|
return rtl::OUString();
|
|
}
|
|
|
|
if ( ( 't' == pValue[ nPos + 1 ] )
|
|
&&
|
|
( ';' == pValue[ nPos + 2 ] ) )
|
|
{
|
|
aResult.append( sal_Unicode( '<' ) );
|
|
nPos += 2;
|
|
}
|
|
else
|
|
{
|
|
OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
|
|
return rtl::OUString();
|
|
}
|
|
}
|
|
else if ( 'g' == c )
|
|
{
|
|
// %gt;
|
|
|
|
if ( nPos > nEnd - 3 )
|
|
{
|
|
OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
|
|
return rtl::OUString();
|
|
}
|
|
|
|
if ( ( 't' == pValue[ nPos + 1 ] )
|
|
&&
|
|
( ';' == pValue[ nPos + 2 ] ) )
|
|
{
|
|
aResult.append( sal_Unicode( '>' ) );
|
|
nPos += 2;
|
|
}
|
|
else
|
|
{
|
|
OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" );
|
|
return rtl::OUString();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OSL_FAIL( "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(RTL_CONSTASCII_USTRINGPARAM("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_FAIL( "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_FAIL( "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: */
|