blob: 51fd4acde6f4f4b0ca3fef82b1c7392b89648940 [file] [log] [blame]
/**************************************************************
*
* 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_stoc.hxx"
#include "stocservices.hxx"
#include "UriReference.hxx"
#include "supportsService.hxx"
#include "com/sun/star/lang/IllegalArgumentException.hpp"
#include "com/sun/star/lang/XServiceInfo.hpp"
#include "com/sun/star/uno/Reference.hxx"
#include "com/sun/star/uno/RuntimeException.hpp"
#include "com/sun/star/uno/Sequence.hxx"
#include "com/sun/star/uno/XInterface.hpp"
#include "com/sun/star/uri/XUriReference.hpp"
#include "com/sun/star/uri/XUriSchemeParser.hpp"
#include "com/sun/star/uri/XVndSunStarScriptUrlReference.hpp"
#include "cppuhelper/implbase1.hxx"
#include "cppuhelper/implbase2.hxx"
#include "cppuhelper/weak.hxx"
#include "osl/mutex.hxx"
#include "rtl/uri.hxx"
#include "rtl/ustrbuf.hxx"
#include "rtl/ustring.hxx"
#include "sal/types.h"
#include <new>
namespace css = com::sun::star;
namespace {
int getHexWeight(sal_Unicode c) {
return c >= '0' && c <= '9' ? static_cast< int >(c - '0')
: c >= 'A' && c <= 'F' ? static_cast< int >(c - 'A' + 10)
: c >= 'a' && c <= 'f' ? static_cast< int >(c - 'a' + 10)
: -1;
}
int parseEscaped(rtl::OUString const & part, sal_Int32 * index) {
if (part.getLength() - *index < 3 || part[*index] != '%') {
return -1;
}
int n1 = getHexWeight(part[*index + 1]);
int n2 = getHexWeight(part[*index + 2]);
if (n1 < 0 || n2 < 0) {
return -1;
}
*index += 3;
return (n1 << 4) | n2;
}
rtl::OUString parsePart(
rtl::OUString const & part, bool namePart, sal_Int32 * index)
{
rtl::OUStringBuffer buf;
while (*index < part.getLength()) {
sal_Unicode c = part[*index];
if (namePart ? c == '?' : c == '&' || c == '=') {
break;
} else if (c == '%') {
sal_Int32 i = *index;
int n = parseEscaped(part, &i);
if (n >= 0 && n <= 0x7F) {
buf.append(static_cast< sal_Unicode >(n));
} else if (n >= 0xC0 && n <= 0xFC) {
sal_Int32 encoded;
int shift;
sal_Int32 min;
if (n <= 0xDF) {
encoded = (n & 0x1F) << 6;
shift = 0;
min = 0x80;
} else if (n <= 0xEF) {
encoded = (n & 0x0F) << 12;
shift = 6;
min = 0x800;
} else if (n <= 0xF7) {
encoded = (n & 0x07) << 18;
shift = 12;
min = 0x10000;
} else if (n <= 0xFB) {
encoded = (n & 0x03) << 24;
shift = 18;
min = 0x200000;
} else {
encoded = 0;
shift = 24;
min = 0x4000000;
}
bool utf8 = true;
for (; shift >= 0; shift -= 6) {
n = parseEscaped(part, &i);
if (n < 0x80 || n > 0xBF) {
utf8 = false;
break;
}
encoded |= (n & 0x3F) << shift;
}
if (!utf8 || encoded < min
|| (encoded >= 0xD800 && encoded <= 0xDFFF)
|| encoded > 0x10FFFF)
{
break;
}
if (encoded <= 0xFFFF) {
buf.append(static_cast< sal_Unicode >(encoded));
} else {
buf.append(static_cast< sal_Unicode >(
(encoded >> 10) | 0xD800));
buf.append(static_cast< sal_Unicode >(
(encoded & 0x3FF) | 0xDC00));
}
} else {
break;
}
*index = i;
} else {
buf.append(c);
++*index;
}
}
return buf.makeStringAndClear();
}
namespace
{
static rtl::OUString encodeNameOrParamFragment( rtl::OUString const & fragment )
{
static sal_Bool const aCharClass[] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* NameOrParamFragment */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* !"#$%&'()*+,-./*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /*0123456789:;<=>?*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*@ABCDEFGHIJKLMNO*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, /*PQRSTUVWXYZ[\]^_*/
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*`abcdefghijklmno*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /*pqrstuvwxyz{|}~ */
};
return rtl::Uri::encode(
fragment,
aCharClass,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8
);
}
}
bool parseSchemeSpecificPart(rtl::OUString const & part) {
sal_Int32 len = part.getLength();
sal_Int32 i = 0;
if (parsePart(part, true, &i).getLength() == 0 || part[0] == '/') {
return false;
}
if (i == len) {
return true;
}
for (;;) {
++i; // skip '?' or '&'
if (parsePart(part, false, &i).getLength() == 0 || i == len
|| part[i] != '=')
{
return false;
}
++i;
parsePart(part, false, &i);
if (i == len) {
return true;
}
if (part[i] != '&') {
return false;
}
}
}
class UrlReference:
public cppu::WeakImplHelper1< css::uri::XVndSunStarScriptUrlReference >
{
public:
UrlReference(rtl::OUString const & scheme, rtl::OUString const & path):
m_base(
scheme, false, false, rtl::OUString(), path, false, rtl::OUString())
{}
virtual rtl::OUString SAL_CALL getUriReference()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.getUriReference(); }
virtual sal_Bool SAL_CALL isAbsolute()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.isAbsolute(); }
virtual rtl::OUString SAL_CALL getScheme()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.getScheme(); }
virtual rtl::OUString SAL_CALL getSchemeSpecificPart()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.getSchemeSpecificPart(); }
virtual sal_Bool SAL_CALL isHierarchical()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.isHierarchical(); }
virtual sal_Bool SAL_CALL hasAuthority()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.hasAuthority(); }
virtual rtl::OUString SAL_CALL getAuthority()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.getAuthority(); }
virtual rtl::OUString SAL_CALL getPath()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.getPath(); }
virtual sal_Bool SAL_CALL hasRelativePath()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.hasRelativePath(); }
virtual sal_Int32 SAL_CALL getPathSegmentCount()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.getPathSegmentCount(); }
virtual rtl::OUString SAL_CALL getPathSegment(sal_Int32 index)
throw (com::sun::star::uno::RuntimeException)
{ return m_base.getPathSegment(index); }
virtual sal_Bool SAL_CALL hasQuery()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.hasQuery(); }
virtual rtl::OUString SAL_CALL getQuery()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.getQuery(); }
virtual sal_Bool SAL_CALL hasFragment()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.hasFragment(); }
virtual rtl::OUString SAL_CALL getFragment()
throw (com::sun::star::uno::RuntimeException)
{ return m_base.getFragment(); }
virtual void SAL_CALL setFragment(rtl::OUString const & fragment)
throw (com::sun::star::uno::RuntimeException)
{ m_base.setFragment(fragment); }
virtual void SAL_CALL clearFragment()
throw (com::sun::star::uno::RuntimeException)
{ m_base.clearFragment(); }
virtual rtl::OUString SAL_CALL getName() throw (css::uno::RuntimeException);
virtual void SAL_CALL setName(rtl::OUString const & name)
throw (css::uno::RuntimeException, css::lang::IllegalArgumentException);
virtual sal_Bool SAL_CALL hasParameter(rtl::OUString const & key)
throw (css::uno::RuntimeException);
virtual rtl::OUString SAL_CALL getParameter(rtl::OUString const & key)
throw (css::uno::RuntimeException);
virtual void SAL_CALL setParameter(rtl::OUString const & key, rtl::OUString const & value)
throw (css::uno::RuntimeException, css::lang::IllegalArgumentException);
private:
UrlReference(UrlReference &); // not implemented
void operator =(UrlReference); // not implemented
virtual ~UrlReference() {}
sal_Int32 findParameter(rtl::OUString const & key);
stoc::uriproc::UriReference m_base;
};
rtl::OUString UrlReference::getName() throw (css::uno::RuntimeException) {
osl::MutexGuard g(m_base.m_mutex);
sal_Int32 i = 0;
return parsePart(m_base.m_path, true, &i);
}
void SAL_CALL UrlReference::setName(rtl::OUString const & name) throw (css::uno::RuntimeException, css::lang::IllegalArgumentException)
{
if (name.getLength() == 0)
throw css::lang::IllegalArgumentException(
::rtl::OUString(), *this, 1);
osl::MutexGuard g(m_base.m_mutex);
sal_Int32 i = 0;
parsePart(m_base.m_path, true, &i);
rtl::OUStringBuffer newPath;
newPath.append(encodeNameOrParamFragment(name));
newPath.append(m_base.m_path.copy(i));
m_base.m_path = newPath.makeStringAndClear();
}
sal_Bool UrlReference::hasParameter(rtl::OUString const & key)
throw (css::uno::RuntimeException)
{
osl::MutexGuard g(m_base.m_mutex);
return findParameter(key) >= 0;
}
rtl::OUString UrlReference::getParameter(rtl::OUString const & key)
throw (css::uno::RuntimeException)
{
osl::MutexGuard g(m_base.m_mutex);
sal_Int32 i = findParameter(key);
return i >= 0 ? parsePart(m_base.m_path, false, &i) : rtl::OUString();
}
void UrlReference::setParameter(rtl::OUString const & key, rtl::OUString const & value)
throw (css::uno::RuntimeException, css::lang::IllegalArgumentException)
{
if (key.getLength() == 0)
throw css::lang::IllegalArgumentException(
::rtl::OUString(), *this, 1);
osl::MutexGuard g(m_base.m_mutex);
sal_Int32 i = findParameter(key);
bool bExistent = ( i>=0 );
if (!bExistent) {
i = m_base.m_path.getLength();
}
rtl::OUStringBuffer newPath;
newPath.append(m_base.m_path.copy(0, i));
if (!bExistent) {
newPath.append(sal_Unicode(m_base.m_path.indexOf('?') < 0 ? '?' : '&'));
newPath.append(encodeNameOrParamFragment(key));
newPath.append(sal_Unicode('='));
}
newPath.append(encodeNameOrParamFragment(value));
if (bExistent) {
/*oldValue = */
parsePart(m_base.m_path, false, &i); // skip key
newPath.append(m_base.m_path.copy(i));
}
m_base.m_path = newPath.makeStringAndClear();
}
sal_Int32 UrlReference::findParameter(rtl::OUString const & key) {
sal_Int32 i = 0;
parsePart(m_base.m_path, true, &i); // skip name
for (;;) {
if (i == m_base.m_path.getLength()) {
return -1;
}
++i; // skip '?' or '&'
rtl::OUString k = parsePart(m_base.m_path, false, &i);
++i; // skip '='
if (k == key) {
return i;
}
parsePart(m_base.m_path, false, &i); // skip value
}
}
class Parser: public cppu::WeakImplHelper2<
css::lang::XServiceInfo, css::uri::XUriSchemeParser >
{
public:
Parser() {}
virtual rtl::OUString SAL_CALL getImplementationName()
throw (css::uno::RuntimeException);
virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
throw (css::uno::RuntimeException);
virtual css::uno::Sequence< rtl::OUString > SAL_CALL
getSupportedServiceNames() throw (css::uno::RuntimeException);
virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
parse(
rtl::OUString const & scheme, rtl::OUString const & schemeSpecificPart)
throw (css::uno::RuntimeException);
private:
Parser(Parser &); // not implemented
void operator =(Parser); // not implemented
virtual ~Parser() {}
};
rtl::OUString Parser::getImplementationName()
throw (css::uno::RuntimeException)
{
return stoc_services::UriSchemeParser_vndDOTsunDOTstarDOTscript::
getImplementationName();
}
sal_Bool Parser::supportsService(rtl::OUString const & serviceName)
throw (css::uno::RuntimeException)
{
return stoc::uriproc::supportsService(
getSupportedServiceNames(), serviceName);
}
css::uno::Sequence< rtl::OUString > Parser::getSupportedServiceNames()
throw (css::uno::RuntimeException)
{
return stoc_services::UriSchemeParser_vndDOTsunDOTstarDOTscript::
getSupportedServiceNames();
}
css::uno::Reference< css::uri::XUriReference >
Parser::parse(
rtl::OUString const & scheme, rtl::OUString const & schemeSpecificPart)
throw (css::uno::RuntimeException)
{
if (!parseSchemeSpecificPart(schemeSpecificPart)) {
return 0;
}
try {
return new UrlReference(scheme, schemeSpecificPart);
} catch (std::bad_alloc &) {
throw css::uno::RuntimeException(
rtl::OUString::createFromAscii("std::bad_alloc"), 0);
}
}
}
namespace stoc_services {
namespace UriSchemeParser_vndDOTsunDOTstarDOTscript {
css::uno::Reference< css::uno::XInterface > create(
css::uno::Reference< css::uno::XComponentContext > const &)
SAL_THROW((css::uno::Exception))
{
//TODO: single instance
try {
return static_cast< cppu::OWeakObject * >(new Parser);
} catch (std::bad_alloc &) {
throw css::uno::RuntimeException(
rtl::OUString::createFromAscii("std::bad_alloc"), 0);
}
}
rtl::OUString getImplementationName() {
return rtl::OUString::createFromAscii(
"com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript");
}
css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
css::uno::Sequence< rtl::OUString > s(1);
s[0] = rtl::OUString::createFromAscii(
"com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript");
return s;
}
} }