From kde-core-devel Wed Mar 16 12:43:32 2005 From: Frans Englich Date: Wed, 16 Mar 2005 12:43:32 +0000 To: kde-core-devel Subject: Re: [PATCH] URI, URL, FOO, URN Message-Id: <200503161243.32476.frans.englich () telia ! com> X-MARC-Message: https://marc.info/?l=kde-core-devel&m=111097654917175 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_0nCOCxdAfv6Zcfd" --Boundary-00=_0nCOCxdAfv6Zcfd Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline Then I'll commit the class to kdecore/ later today or tomorrow, something like that. Frans PS. Attached update includes some small fixes. --Boundary-00=_0nCOCxdAfv6Zcfd Content-Type: text/x-diff; charset="iso-8859-1"; name="kurn.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kurn.diff" Index: Makefile.am =================================================================== RCS file: /home/kde/kdelibs/kdecore/Makefile.am,v retrieving revision 1.360 diff -u -3 -p -r1.360 Makefile.am --- Makefile.am 7 Jan 2005 23:09:18 -0000 1.360 +++ Makefile.am 16 Mar 2005 12:34:25 -0000 @@ -59,7 +59,7 @@ include_HEADERS = kconfig.h kconfigskele kcalendarsystem.h kcalendarsystemfactory.h kmacroexpander.h \ kmanagerselection.h kmountpoint.h kuser.h klockfile.h \ kidna.h ktempdir.h kshell.h fixx11h.h kxerrorhandler.h kdelibs_export.h \ - kdemacros.h kde_file.h kswap.h + kdemacros.h kde_file.h kswap.h kurn.h libkdefakes_la_SOURCES = fakes.c vsnprintf.c libkdefakes_la_LDFLAGS = -version-info 6:0:2 @@ -100,7 +100,7 @@ libkdecore_la_SOURCES = libintl.cpp kapp kcmdlineargs.cpp kaboutdata.cpp kcompletionbase.cpp knotifyclient.cpp \ kaudioplayer.cpp kdcoppropertyproxy.cpp \ ksockaddr.cpp kextsock.cpp netsupp.cpp kprocio.cpp kbufferedio.cpp \ - kpixmapprovider.cpp kurldrag.cpp \ + kpixmapprovider.cpp kurldrag.cpp kurn.cpp \ kmdcodec.cpp ksocks.cpp fakes.c vsnprintf.c \ ksycoca.cpp ksycocadict.cpp ksycocafactory.cpp ksycoca.skel \ kxmessages.cpp kstartupinfo.cpp kcatalogue.cpp kasyncio.cpp \ Index: kurn.cpp =================================================================== RCS file: kurn.cpp diff -N kurn.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ kurn.cpp 16 Mar 2005 12:34:25 -0000 @@ -0,0 +1,290 @@ +/* This file is part of the KDE libraries + * + * Copyright (C) 2005 Frans Englich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + **/ + +#include + +#include "kurn.h" + +/** + * Case insensitive QString-comparision. + */ +#define isInsCaseEqual(a, b) (a.length() == b.length() && (b.find(a, 0, false) != -1)) + +/* + * Related documentation: + * + * + RFC 3151 -- URN Syntax + * + RFC 2141 -- A URN Namespace for Public Identifiers + * + OASIS XML Catalogs, section 6.4 - "URN 'Unwrapping'" + */ + +/* + * TODO: + * + Perform lexical validation in isValidNSS() and isValidNID(). + */ + +class KURN::Private +{ +public: + Private(): + isURN(false), + hasValidNSS(false), + hasValidNID(false), + hasPublicID(false) + { } + + bool isURN :1; + bool hasValidNSS :1; + bool hasValidNID :1; + bool hasPublicID :1; + QString nid; + QString nss; + QString publicID; /* Un-encoded version of nss */ +}; + +KURN::KURN(): KURL(), d(new Private()) +{ + init(); +} + +KURN::KURN(const QString& uri): KURL(uri.stripWhiteSpace()), d(new Private()) +{ + init(); +} + +KURN::KURN(const KURL& uri): KURL(uri.url().stripWhiteSpace()), d(new Private()) +{ + init(); +} + +KURN::KURN( const char* urn): KURL(QString(urn).stripWhiteSpace()), d(new Private()) +{ + init(); +} + +KURN::~KURN() +{ + delete d; +} + +bool KURN::isValidNID(const QString& nid) const +{ + if(isInsCaseEqual(nid, QString("urn"))) /* Reserved */ + return false; + else + return true; +} + +bool KURN::isValidNSS(const QString& /*nss*/) const +{ + return true; +} + +bool KURN::operator==(const KURN &urn) +{ + if(namespaceSpecific() == urn.namespaceSpecific() && + isInsCaseEqual(urn.namespaceID(), namespaceID()) && + urn.isValid() && + isValid()) + return true; + else + return false; +} + +KURN& KURN::operator=(const QString &uri) +{ + KURL::operator=(uri.simplifyWhiteSpace()); + init(); + return *this; +} + +KURN& KURN::operator=(const char * uri) +{ + KURL::operator=(QString(uri).simplifyWhiteSpace()); + init(); + return *this; +} + +KURN& KURN::operator=(const KURN& urn) +{ + *d = *(urn.d); + return *this; +} + +void KURN::setNamespaceID(const QString& nid) +{ + d->nid = nid; + + d->hasValidNID = isValidNID(nid); + + if(d->nid == "publicid") + d->hasPublicID = true; + else + { + d->publicID = QString::null; + d->hasPublicID = false; + } +} + +void KURN::setNamespaceSpecific(const QString& nss) +{ + d->nss = nss; + d->hasValidNSS = isValidNSS(nss); + d->publicID = QString::null; + + /* Normalize %-encoding */ + const uint length = d->nss.length(); + for(uint i = 0; i < length; i++) + if(d->nss.at(i) == '%') + { + d->nss.replace(i + 1, 2, d->nss.mid(i + 1, 2).upper()); + i += 2; + } + + if(hasPublicID()) + { + /* Decode the URN into a XML Public ID */ + const uint length = d->nss.length(); + for(uint i = 0; i < length; i++) + { + const QChar c = d->nss.at(i); + if(c == '+') + d->publicID += " "; + + else if(c == ':') + d->publicID += "//"; + + else if(c == ';') + d->publicID += "::"; + else if(c == '%') + { + const QString hex = d->nss.mid(i+1, 2); + + if(hex == "23") + d->publicID += '#'; + else if(hex == "25") + d->publicID += '%'; + else if(hex == "27") + d->publicID += '\''; + else if(hex == "2B") + d->publicID += '+'; + else if(hex == "2F") + d->publicID += '/'; + else if(hex == "3A") + d->publicID += ':'; + else if(hex == "3B") + d->publicID += ';'; + else if(hex == "3F") + d->publicID += '?'; + else + d->publicID += hex; + + i += 2; + } + else + d->publicID += c; + } + d->publicID = d->publicID.simplifyWhiteSpace(); + } +} + +void KURN::init() +{ + const QString uri = url(); + + /* Put the position of the colon between nss and nid in sepPos */ + const int sepPos = uri.find(":", 4); + setNamespaceID(uri.mid(4, sepPos-4)); + setNamespaceSpecific(uri.mid(sepPos + 1)); /* +1 == No colon */ + + if(uri.startsWith("urn:", false) || uri.isEmpty()) + d->isURN = true; + else + d->isURN = false; + +} + +KURN KURN::fromPublicID(const QString& pub) +{ + /* See RFC3151, section 1.1 - "Public Identifiers" */ + QString npub = pub.simplifyWhiteSpace(); + + const uint length = npub.length(); + for(uint i = 0; i < length; i++) + { + const QChar c = npub.at(i); + if(c == ' ') + npub.replace(i, 1, '+'); + else if(c == '+') + { + npub.replace(i, 1, "%2B"); + i += 2; + } + else if(c == ':') + if( npub.at(i+1) == ':') + npub.replace(i, 2, ';'); + else + { + npub.replace(i, 1, "%3A"); + i += 2; + } + else if(c == '/') + if(npub.at(i+1) == '/') + npub.replace(i, 2, ':'); + else + { + npub.replace(i, 1, "%2F"); + i += 2; + } + } + + return KURN(KURL::fromPathOrURL("urn:publicid:" + npub)); /* KURL performs ordinary URI encoding */ +} + +QString KURN::urn() const +{ + return "urn:" + namespaceID() + ":" + namespaceSpecific(); +} + +bool KURN::isValid() const +{ + return d->hasValidNID && d->hasValidNSS && d->isURN; +} + +QString KURN::namespaceID() const +{ + return d->nid; +} + +bool KURN::hasPublicID() const +{ + return d->hasPublicID; +} + +QString KURN::publicID() const +{ + return d->publicID; +} + +QString KURN::namespaceSpecific() const +{ + return d->nss; +} + Index: kurn.h =================================================================== RCS file: kurn.h diff -N kurn.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ kurn.h 16 Mar 2005 12:34:25 -0000 @@ -0,0 +1,212 @@ +/* This file is part of the KDE libraries + * + * Copyright (C) 2005 Frans Englich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + **/ + +#ifndef kurn_h +#define kurn_h + +#include + +class QString; + +/** + * @short A class for handling URNs, with + * support for the publicid namespace. + * + * @author Frans Englich + */ +class KURN: public KURL +{ +public: + /** + * Constructs an empty URN. + */ + KURN(); + + /** + * Constructs a KURN from @p urn, which is assumed to be a valid, properly encoded, + * URN. + * + * @p urn is assumed to be a valid, that is encoded, URN. + * @param urn an URN string to construct + */ + KURN(const QString& urn); + + /** + * This is an overloaded member function, provided for convenience. + * It behaves essentially like the above function. + */ + KURN(const KURL& urn); + + /** + * This is an overloaded member function, provided for convenience. + * It behaves essentially like the above function. + */ + KURN( const char* urn); + + /** + * Destructor. + */ + virtual ~KURN(); + + /** + * Determines whether the URN is in the publicid namespace, as per + * RFC 3151. + * + * @returns true if the URN is in the publicid namespace + */ + bool hasPublicID() const; + + /** + * Sets the namespace specific string of the URN to @p nss. + */ + void setNamespaceSpecific(const QString& nss); + + /** + * Sets the URN's namespace ID to @p nid. + * + * @param nid the namespace id to set + */ + void setNamespaceID( const QString& nid); + + /** + * Retrieves the namespace identifer of the URN. For example, for the + * URN "urn:oasis:names:tc:entity:xmlns" is "oasis" returned. + * + * @returns the namespace identifier + */ + QString namespaceID() const; + + /** + * Retrieves the namespace specific part of the URN. For example, for + * the URN "urn:oasis:names:tc:entity:xmlns" is "names:tc:entity:xmlns" + * returned. + * + * @returns the namespace specific string + */ + QString namespaceSpecific() const; + + /** + * Retrieves the contained XML Public ID in an unwrapped, unencoded + * representation. If you want the Public ID in its encoded form, + * use namespaceSpecific(), or urn(). + * + * For example: + * \code + * KURN dsssl("urn:publicid:ISO%2FIEC+10179%3A1996:DTD+DSSSL+Architecture:EN"); + * //dsssl.publicID() == "ISO/IEC 10179:1996//DTD DSSSL Architecture//EN"); + * \endcode + * + * If the URN is not in the publicid namespace, an + * empty string is returned. + * + * @returns a public ID + */ + QString publicID() const; + + /** + * Returns a complete URN. This is typically a normalized for of what was + * passed in one of the constructors. + */ + QString urn() const; + + /** + * Determines whether the contained URI is a valid URN. In other words, + * the contained URI may very well be a valid URI, but simply not be + * an URN, or be an invalid URN. + * + * @returns true if the URN is valid + */ + bool isValid() const; + + /** + * Constructs an URN in the publicid namespace with the + * Public Identifier @p pub. For example: + * + * \code + * KURN urn = KURN::fromPublicID("-//OASIS//DTD Docbook XML V4.1.2//EN"); + * //urn.urn() == "urn:publicid:-:OASIS:DTD+Docbook+XML+V4.1.2:EN" + * \endcode + * + * @param pub the public identifier to construct an URN for + * @returns an URN in the publicid with @p pub + */ + static KURN fromPublicID(const QString& pub); + + /** + * Comparishion operator. Two URNs are considered equal if their + * namespace identifier's are case-insensitively equal, and that the + * namespace specific strings are case-sensitively equal. If a + * particular namespace imposes other semantics on lexical equalness for + * the namespace specific string, this function must be re-implemented. + * + * @returns true if the two URNs are considered equal. + */ + bool operator==(const KURN &urn); + + + /** + * Sets the object to house @p urn. This is identical to + * calling a constructor with @p urn. @p urn is assumed to + * be a valid URN. + * + * @param urn the URN to represent + */ + KURN& operator=(const QString &urn); + + /** + * This is an overloaded member function, provided for convenience. + * It behaves essentially like the above function. + */ + KURN& operator=(const char * uri); + + /** + * This is an overloaded member function, provided for convenience. + * It behaves essentially like the above function. + */ + KURN& operator=(const KURN& urn); + +protected: + + /** + * Determines whether @p nid is a valid Namespace Identifier. + * + * @param nid the identifier to validate + * @returns true if @p nid is a valid nid + */ + bool isValidNID(const QString& nid) const; + + /** + * Determines whether @p nss is a valid Namespace Specific String. Reimplement this + * function to do namespace specific validation, beyond what the RFC mandates. + * + * @param nss the namespace string to validate + * @param returns true if @p nss is considered a valid namespace specific string + */ + bool isValidNSS(const QString& nss) const; + + void init(); + +private: + + class Private; + Private* const d; +}; + +#endif // kurn_h Index: tests/Makefile.am =================================================================== RCS file: /home/kde/kdelibs/kdecore/tests/Makefile.am,v retrieving revision 1.50 diff -u -3 -p -r1.50 Makefile.am --- tests/Makefile.am 24 Nov 2004 12:22:34 -0000 1.50 +++ tests/Makefile.am 16 Mar 2005 12:34:25 -0000 @@ -28,9 +28,10 @@ check_PROGRAMS = kconfigtest klocaletest cplusplustest kiconloadertest kresolvertest kmdcodectest knotifytest \ ksortablevaluelisttest krfcdatetest testqtargs kprociotest \ kcharsetstest kcalendartest kmacroexpandertest kshelltest \ - kxerrorhandlertest startserviceby kstdacceltest kglobaltest + kxerrorhandlertest startserviceby kstdacceltest kglobaltest \ + kurntest -TESTS = kurltest kstdacceltest +TESTS = kurltest kstdacceltest kurntest noinst_HEADERS = kconfigtest.h klocaletest.h kprocesstest.h KIDLTest.h \ kipctest.h kprociotest.h @@ -45,6 +46,7 @@ klocaletest_SOURCES = klocaletest.cpp #kcatalogue_SOURCES = kcatalogue.cpp libintl.cpp ksimpleconfigtest_SOURCES = ksimpleconfigtest.cpp kurltest_SOURCES = kurltest.cpp +kurntest_SOURCES = kurntest.cpp kstddirstest_SOURCES = kstddirstest.cpp kprocesstest_SOURCES = kprocesstest.cpp kuniqueapptest_SOURCES = kuniqueapptest.cpp Index: tests/kurntest.cpp =================================================================== RCS file: tests/kurntest.cpp diff -N tests/kurntest.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/kurntest.cpp 16 Mar 2005 12:34:25 -0000 @@ -0,0 +1,193 @@ +/* This file is part of the KDE libraries + * + * Copyright (C) 2005 Frans Englich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + **/ + +#include + +#include + +#include +#include +#include +#include + +static uint numErrors = 0; +static uint numSucessess = 0; + +/** + * Compares @p a to @p b, and if they're not equal the program exits. In either case is + * a debug statement printed. + * + * @param desc a description of the test, such as the function call + * @param a the value to be compared to @p b + * @param b the value @p a is compared to + */ +void check(QString desc, QString a, QString b) +{ + if (a.isEmpty()) + a = QString::null; + + if (b.isEmpty()) + b = QString::null; + + const QString msg = desc + \ + " Expected: \"" + b + "\", " + "got \"" + a + "\"."; + if (a == b) + { + kdDebug() << "SUCCESS: " << msg << endl; + numSucessess++; + } + else + { + kdDebug() << "FAILURE: " << msg << endl; + numErrors++; + } +} + +int main(int argc, char *argv[]) +{ + KApplication::disableAutoDcopRegistration(); + KCmdLineArgs::init( argc, argv, "kurltest", 0, 0, 0, 0 ); + KApplication app( false, false ); + + KURN simple("urn:simple:test:yup:tup"); + + check("KURN::urn()", simple.urn(), "urn:simple:test:yup:tup"); + check("KURN::namespaceID()", simple.namespaceID(), "simple"); + check("KURN::namespaceSpecific()", simple.namespaceSpecific(), "test:yup:tup"); + check("KURN::isValid()", simple.isValid() ? "true": "false", "true"); + check("KURN::publicID()", simple.publicID(), ""); + check("KURN::hasPublicID()", simple.hasPublicID() ? "true": "false", "false"); + + simple = "urn:again:foo:no:no"; /* Ensure that values are actually changed */ + check("KURN::namespaceID()", simple.namespaceID(), "again"); + check("KURN::namespaceSpecific()", simple.namespaceSpecific(), "foo:no:no"); + check("KURN::isValid()", simple.isValid() ? "true": "false", "true"); + check("KURN::publicID()", simple.publicID(), ""); + check("KURN::hasPublicID()", simple.hasPublicID() ? "true": "false", "false"); + + KURN pub("urn:publicid:yo:foo"); /* Simple public ID functionality */ + check("KURN::namespaceID()", pub.namespaceID(), "publicid"); + check("KURN::namespaceSpecific()", pub.namespaceSpecific(), "yo:foo"); + check("KURN::isValid()", pub.isValid() ? "true": "false", "true"); + check("KURN::publicID()", pub.publicID(), "yo//foo"); + check("KURN::hasPublicID()", pub.hasPublicID() ? "true": "false", "true"); + + /* Examples from the RFC */ + KURN dsssl("urn:publicid:ISO%2FIEC+10179%3A1996:DTD+DSSSL+Architecture:EN"); + check("KURN::publicID()", dsssl.publicID(), "ISO/IEC 10179:1996//DTD DSSSL Architecture//EN"); + + KURN latin("urn:publicid:ISO+8879%3A1986:ENTITIES+Added+Latin+1:EN"); + check("KURN::publicID()", latin.publicID(), "ISO 8879:1986//ENTITIES Added Latin 1//EN"); + + KURN oasis("urn:publicid:-:OASIS:DTD+DocBook+XML+V4.1.2:EN"); + check("KURN::publicID()", oasis.publicID(), "-//OASIS//DTD DocBook XML V4.1.2//EN"); + + KURN book("urn:publicid:%2B:IDN+example.org:DTD+XML+Bookmarks+1.0:EN:XML"); + check("KURN::publicID()", book.publicID(), "+//IDN example.org//DTD XML Bookmarks 1.0//EN//XML"); + + KURN arbor("urn:publicid:-:ArborText;prod:DTD+Help+Document;19970708:EN"); + check("KURN::publicID()", arbor.publicID(), "-//ArborText::prod//DTD Help Document::19970708//EN"); + + KURN foo("urn:publicid:foo"); + check("KURN::publicID()", foo.publicID(), "foo"); + + KURN math("urn:publicid:3%2B3=6"); + check("KURN::publicID()", math.publicID(), "3+3=6"); + + /* NIDs equal to "urn" are reserved, not those simply starting with "urn" */ + math = "urn:urnig:test"; + check("KURN::isValid()", math.isValid() ? "true": "false", "true"); + + KURN acme("urn:publicid:-:Acme,+Inc.:DTD+Book+Version+1.0"); + check("KURN::publicID()", acme.publicID(), "-//Acme, Inc.//DTD Book Version 1.0"); + + /* Try to shake it off */ + acme = "urn:publicid:ISO%2FIEC+10179%3A1996:DTD+DSSSL+Architecture:EN"; + check("KURN::publicID()", acme.publicID(), "ISO/IEC 10179:1996//DTD DSSSL Architecture//EN"); + acme = "urn:again:foo:no:no"; + check("KURN::namespaceID()", acme.namespaceID(), "again"); + check("KURN::namespaceSpecific()", acme.namespaceSpecific(), "foo:no:no"); + check("KURN::isValid()", acme.isValid() ? "true": "false", "true"); + check("KURN::publicID()", acme.publicID(), ""); + check("KURN::hasPublicID()", acme.hasPublicID() ? "true": "false", "false"); + + /* Test equalness code */ + check("KURN(\"URN:foo:a123,456\") == KURN(\"urn:foo:a123,456\")", + (KURN("URN:foo:a123,456") == KURN("urn:foo:a123,456")) + ? "true" : "false", "true"); + check("(KURN(\"URN:foo:a123,456\") == KURN(\"urn:FOO:a123,456\")", + (KURN("URN:foo:a123,456") == KURN("urn:FOO:a123,456")) + ? "true" : "false", "true"); + check("(KURN(\"urn:foo:A123,456\") == KURN(\"Urn:foo:a123,456\")", + (KURN("urn:foo:A123,456") == KURN("Urn:foo:a123,456")) + ? "true" : "false", "false"); + check("(KURN(\"urn:foo:a123%2C456\") == KURN(\"URN:FOO:a123%2c456\")", + (KURN("urn:foo:a123%2C456") == KURN("URN:FOO:a123%2c456")) + ? "true" : "false", "true"); + check("(KURN(\"urn:foo:a123%2C456\") == KURN(\"urn:FOO:a123,456\")", + (KURN("urn:foo:a123%2C456") == KURN("urn:FOO:a123,456")) + ? "true" : "false", "false"); + + + /* ...and the other way around */ + + check("KURN::fromPublicID(\"ISO/IEC 10179:1996//DTD DSSSL Architecture//EN\").urn()", + KURN::fromPublicID("ISO/IEC 10179:1996//DTD DSSSL Architecture//EN").urn(), + "urn:publicid:ISO%2FIEC+10179%3A1996:DTD+DSSSL+Architecture:EN"); + check("KURN::fromPublicID(\"ISO 8879:1986//ENTITIES Added Latin 1//EN\").urn()", + KURN::fromPublicID("ISO 8879:1986//ENTITIES Added Latin 1//EN").urn(), + "urn:publicid:ISO+8879%3A1986:ENTITIES+Added+Latin+1:EN"); + check("KURN::fromPublicID(\"+//IDN example.org//DTD XML Bookmarks 1.0//EN//XML\").urn()", + KURN::fromPublicID("+//IDN example.org//DTD XML Bookmarks 1.0//EN//XML").urn(), + "urn:publicid:%2B:IDN+example.org:DTD+XML+Bookmarks+1.0:EN:XML"); + check("KURN::fromPublicID(\"-//ArborText::prod//DTD Help Document::19970708//EN\").urn()", + KURN::fromPublicID("-//ArborText::prod//DTD Help Document::19970708//EN").urn(), + "urn:publicid:-:ArborText;prod:DTD+Help+Document;19970708:EN"); + + check("KURN::fromPublicID(\"foo\").urn()", + KURN::fromPublicID("foo").urn(), + "urn:publicid:foo"); + + check("KURN::fromPublicID(\"3+3=6\").urn()", + KURN::fromPublicID("3+3=6").urn(), + "urn:publicid:3%2B3=6"); + + check("KURN::fromPublicID(\"-//Acme, Inc.//DTD Book Version 1.0\").urn()", + KURN::fromPublicID("-//Acme, Inc.//DTD Book Version 1.0").urn(), + "urn:publicid:-:Acme,+Inc.:DTD+Book+Version+1.0"); + + /* Test altering various parts */ + oasis.setNamespaceID("yo"); + check("oasis.publicID()", oasis.publicID(), ""); + check("oasis.hasPublicID", oasis.hasPublicID() ? "true" : "false", "false"); + check("oasis.namespaceSpecific()", oasis.namespaceSpecific(), "-:OASIS:DTD+DocBook+XML+V4.1.2:EN"); + check("oasis.urn()", oasis.urn(), "urn:yo:-:OASIS:DTD+DocBook+XML+V4.1.2:EN"); + + if(numErrors) + { + kdDebug() << "*** FAILURE: " << numErrors << " tests failed, " << numSucessess + << " succeeded. ***" << endl; + exit(1); + } + else + kdDebug() << "*** SUCCESS: All tests, " << numSucessess << ", succeeded. ***" << endl; + +} + --Boundary-00=_0nCOCxdAfv6Zcfd--