Skip to content
Browse files

https://issues.apache.org/jira/browse/AMQCPP-511

  • Loading branch information...
1 parent e348ac1 commit b1746b23e4af5cdad7ebfed49472dea35559d107 @tabish121 tabish121 committed
View
6 activemq-cpp/src/main/Makefile.am
@@ -352,7 +352,9 @@ cc_sources = \
decaf/internal/net/URIEncoderDecoder.cpp \
decaf/internal/net/URIHelper.cpp \
decaf/internal/net/URIType.cpp \
+ decaf/internal/net/URLStreamHandlerManager.cpp \
decaf/internal/net/URLType.cpp \
+ decaf/internal/net/http/HttpHandler.cpp \
decaf/internal/net/ssl/DefaultSSLContext.cpp \
decaf/internal/net/ssl/DefaultSSLServerSocketFactory.cpp \
decaf/internal/net/ssl/DefaultSSLSocketFactory.cpp \
@@ -463,6 +465,7 @@ cc_sources = \
decaf/lang/ThreadLocal.cpp \
decaf/lang/Throwable.cpp \
decaf/lang/Types.cpp \
+ decaf/lang/exceptions/ArrayIndexOutOfBoundsException.cpp \
decaf/lang/exceptions/ClassCastException.cpp \
decaf/lang/exceptions/CloneNotSupportedException.cpp \
decaf/lang/exceptions/IllegalArgumentException.cpp \
@@ -1025,7 +1028,9 @@ h_sources = \
decaf/internal/net/URIEncoderDecoder.h \
decaf/internal/net/URIHelper.h \
decaf/internal/net/URIType.h \
+ decaf/internal/net/URLStreamHandlerManager.h \
decaf/internal/net/URLType.h \
+ decaf/internal/net/http/HttpHandler.h \
decaf/internal/net/ssl/DefaultSSLContext.h \
decaf/internal/net/ssl/DefaultSSLServerSocketFactory.h \
decaf/internal/net/ssl/DefaultSSLSocketFactory.h \
@@ -1143,6 +1148,7 @@ h_sources = \
decaf/lang/ThreadLocal.h \
decaf/lang/Throwable.h \
decaf/lang/Types.h \
+ decaf/lang/exceptions/ArrayIndexOutOfBoundsException.h \
decaf/lang/exceptions/ClassCastException.h \
decaf/lang/exceptions/CloneNotSupportedException.h \
decaf/lang/exceptions/ExceptionDefines.h \
View
165 activemq-cpp/src/main/decaf/internal/net/URLStreamHandlerManager.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#include <decaf/internal/net/URLStreamHandlerManager.h>
+
+#include <decaf/lang/Runnable.h>
+#include <decaf/lang/exceptions/RuntimeException.h>
+#include <decaf/lang/Exception.h>
+#include <decaf/net/URLStreamHandler.h>
+#include <decaf/net/URLStreamHandlerFactory.h>
+#include <decaf/internal/net/Network.h>
+
+#include <decaf/internal/net/http/HttpHandler.h>
+
+using namespace decaf;
+using namespace decaf::internal;
+using namespace decaf::internal::net;
+using namespace decaf::internal::net::http;
+using namespace decaf::net;
+using namespace decaf::lang;
+using namespace decaf::lang::exceptions;
+
+////////////////////////////////////////////////////////////////////////////////
+URLStreamHandlerManager* URLStreamHandlerManager::instance;
+
+////////////////////////////////////////////////////////////////////////////////
+namespace {
+
+ class ShutdownTask : public decaf::lang::Runnable {
+ private:
+
+ URLStreamHandlerManager** defaultRef;
+
+ private:
+
+ ShutdownTask( const ShutdownTask& );
+ ShutdownTask& operator= ( const ShutdownTask& );
+
+ public:
+
+ ShutdownTask( URLStreamHandlerManager** defaultRef ) : defaultRef( defaultRef ) {}
+ virtual ~ShutdownTask() {}
+
+ virtual void run() {
+ *defaultRef = NULL;
+ }
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+namespace decaf {
+namespace internal {
+namespace net {
+
+ class URLStreamHandlerManagerImpl {
+ public:
+
+ URLStreamHandlerFactory* factory;
+
+ public:
+
+ URLStreamHandlerManagerImpl() : factory(NULL) {
+ }
+
+ virtual ~URLStreamHandlerManagerImpl() {
+ try {
+ delete factory;
+ } catch(...) {}
+ }
+
+ };
+
+}}}
+
+////////////////////////////////////////////////////////////////////////////////
+URLStreamHandlerManager::URLStreamHandlerManager() : impl(new URLStreamHandlerManagerImpl) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URLStreamHandlerManager::~URLStreamHandlerManager() {
+ try {
+ delete impl;
+ }
+ DECAF_CATCHALL_NOTHROW()
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URLStreamHandlerManager* URLStreamHandlerManager::getInstance() {
+
+ if (instance == NULL) {
+
+ synchronized(Network::getNetworkRuntime()->getRuntimeLock()) {
+
+ if (instance != NULL) {
+ return instance;
+ }
+
+ instance = new URLStreamHandlerManager;
+
+ // Store the default in the Network Runtime, it will be destroyed when the
+ // Application calls the Decaf shutdownLibrary method.
+ Network::getNetworkRuntime()->addAsResource(instance);
+ Network::getNetworkRuntime()->addShutdownTask(new ShutdownTask(&instance));
+ }
+ }
+
+ return instance;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLStreamHandlerManager::setURLStreamHandlerFactory(URLStreamHandlerFactory* factory) {
+
+ synchronized(Network::getNetworkRuntime()->getRuntimeLock()) {
+
+ if (impl->factory != NULL) {
+ throw RuntimeException(
+ __FILE__, __LINE__, "Application already set a URLStreamHandlerFactory");
+ }
+
+ impl->factory = factory;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URLStreamHandler* URLStreamHandlerManager::getURLStreamHandler(const decaf::lang::String& protocol) {
+
+ URLStreamHandler* streamHandler = NULL;
+
+ synchronized(Network::getNetworkRuntime()->getRuntimeLock()) {
+
+ // If there is a stream handler factory, then attempt to
+ // use it to create the handler.
+ if (impl->factory != NULL) {
+ streamHandler = impl->factory->createURLStreamHandler(protocol.toString());
+ if (streamHandler != NULL) {
+ return streamHandler;
+ }
+ }
+
+ // No one else has provided a handler, so try our internal one.
+ if (protocol.equalsIgnoreCase("http")) {
+ return new HttpHandler;
+ }
+
+ // TODO we should cache the stream handlers and return the cached version
+ // we just need to ensure we manage the lifetime from within this object.
+ }
+
+ return streamHandler;
+}
+
View
94 activemq-cpp/src/main/decaf/internal/net/URLStreamHandlerManager.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#ifndef _DECAF_INTERNAL_NET_URLSTREAMHANDLERMANAGER_H_
+#define _DECAF_INTERNAL_NET_URLSTREAMHANDLERMANAGER_H_
+
+#include <decaf/util/Config.h>
+
+#include <decaf/lang/String.h>
+
+namespace decaf {
+namespace net {
+ class URLStreamHandler;
+ class URLStreamHandlerFactory;
+}
+namespace internal {
+namespace net {
+
+ class Network;
+ class URLStreamHandlerManagerImpl;
+
+ class DECAF_API URLStreamHandlerManager {
+ private:
+
+ URLStreamHandlerManagerImpl* impl;
+
+ private:
+
+ static URLStreamHandlerManager* instance;
+
+ private:
+
+ URLStreamHandlerManager();
+
+ public:
+
+ virtual ~URLStreamHandlerManager();
+
+ public:
+
+ /**
+ * Returns the one and only URLStreamHandlerManager instance for this
+ * application. The returned pointer should never be deleted by the
+ * application.
+ *
+ * @returns a URLStreamHandlerManager instance.
+ */
+ static URLStreamHandlerManager* getInstance();
+
+ public:
+
+ /**
+ * Gets a URLStreamHandler for the specified protocol if one is available.
+ *
+ * @param protocol
+ * The protocol to return a URL Stream Handler instance for.
+ *
+ * @returns a URLStreamHandler instance for the given protocol.
+ */
+ decaf::net::URLStreamHandler* getURLStreamHandler(const decaf::lang::String& protocol);
+
+ /**
+ * Sets an application's URLStreamHandlerFactory. This method can be called at most once.
+ *
+ * The URLStreamHandlerFactory instance is used to construct a stream protocol handler
+ * from a protocol name. The provided factory becomes the property of this runtime and
+ * will be deleted at shutdown.
+ *
+ * @param factory
+ * the desired factory.
+ *
+ * @throws Exception if there is already a set factory.
+ */
+ void setURLStreamHandlerFactory(decaf::net::URLStreamHandlerFactory* factory);
+
+ };
+
+}}}
+
+#endif /* _DECAF_INTERNAL_NET_URLSTREAMHANDLERMANAGER_H_ */
View
50 activemq-cpp/src/main/decaf/internal/net/URLType.h
@@ -18,8 +18,8 @@
#ifndef _DECAF_INTERNAL_NET_URLTYPE_H_
#define _DECAF_INTERNAL_NET_URLTYPE_H_
-#include <string>
#include <decaf/util/Config.h>
+#include <decaf/lang/String.h>
namespace decaf {
namespace internal {
@@ -31,15 +31,15 @@ namespace net {
class DECAF_API URLType {
private:
- std::string file;
- std::string protocol;
- std::string host;
+ decaf::lang::String file;
+ decaf::lang::String protocol;
+ decaf::lang::String host;
int port;
- std::string authority;
- std::string userInfo;
- std::string path;
- std::string query;
- std::string ref;
+ decaf::lang::String authority;
+ decaf::lang::String userInfo;
+ decaf::lang::String path;
+ decaf::lang::String query;
+ decaf::lang::String ref;
int hashCode;
public:
@@ -52,7 +52,7 @@ namespace net {
* Gets the File of the URL.
* @return File part string.
*/
- std::string getFile() const {
+ decaf::lang::String getFile() const {
return file;
}
@@ -60,7 +60,7 @@ namespace net {
* Sets the File of the URL.
* @param File Authority part string.
*/
- void setFile(const std::string& file) {
+ void setFile(const decaf::lang::String& file) {
this->file = file;
}
@@ -68,7 +68,7 @@ namespace net {
* Gets the protocol of the URL, e.g. protocol ("http"/"ftp"/...).
* @return protocol part string.
*/
- std::string getProtocol() const {
+ decaf::lang::String getProtocol() const {
return protocol;
}
@@ -76,7 +76,7 @@ namespace net {
* Sets the protocol of the URL, e.g. protocol ("http"/"ftp"/...).
* @param protocol - protocol part string.
*/
- void setProtocol(const std::string& protocol) {
+ void setProtocol(const decaf::lang::String& protocol) {
this->protocol = protocol;
}
@@ -84,7 +84,7 @@ namespace net {
* Gets the Authority of the URL.
* @return Authority part string.
*/
- std::string getAuthority() const {
+ decaf::lang::String getAuthority() const {
return authority;
}
@@ -92,7 +92,7 @@ namespace net {
* Sets the Authority of the URL.
* @param authority Authority part string.
*/
- void setAuthority(const std::string& authority) {
+ void setAuthority(const decaf::lang::String& authority) {
this->authority = authority;
}
@@ -101,7 +101,7 @@ namespace net {
* http://user:passwd@host:port/
* @return user info part string.
*/
- std::string getUserInfo() const {
+ decaf::lang::String getUserInfo() const {
return userInfo;
}
@@ -111,7 +111,7 @@ namespace net {
*
* @param userInfo - user info part string.
*/
- void setUserInfo(const std::string& userInfo) {
+ void setUserInfo(const decaf::lang::String& userInfo) {
this->userInfo = userInfo;
}
@@ -119,7 +119,7 @@ namespace net {
* Gets the Host name part of the URL.
* @return Host name part string.
*/
- std::string getHost() const {
+ decaf::lang::String getHost() const {
return host;
}
@@ -127,7 +127,7 @@ namespace net {
* Sets the Host name part of the URL.
* @param host - Host name part string.
*/
- void setHost(const std::string& host) {
+ void setHost(const decaf::lang::String& host) {
this->host = host;
}
@@ -151,7 +151,7 @@ namespace net {
* Gets the Path part of the URL.
* @return Path part string.
*/
- std::string getPath() const {
+ decaf::lang::String getPath() const {
return path;
}
@@ -159,7 +159,7 @@ namespace net {
* Sets the Path part of the URL.
* @param path - Path part string.
*/
- void setPath(const std::string& path) {
+ void setPath(const decaf::lang::String& path) {
this->path = path;
}
@@ -167,7 +167,7 @@ namespace net {
* Gets the Query part of the URL.
* @return Query part string.
*/
- std::string getQuery() const {
+ decaf::lang::String getQuery() const {
return query;
}
@@ -175,7 +175,7 @@ namespace net {
* Sets the Query part of the URL.
* @param query - Query part string.
*/
- void setQuery(const std::string& query) {
+ void setQuery(const decaf::lang::String& query) {
this->query = query;
}
@@ -183,7 +183,7 @@ namespace net {
* Gets the Ref part of the URL.
* @return Ref part string.
*/
- std::string getRef() const {
+ decaf::lang::String getRef() const {
return ref;
}
@@ -191,7 +191,7 @@ namespace net {
* Sets the Ref part of the URL.
* @param ref - Ref part string.
*/
- void setRef(const std::string& ref) {
+ void setRef(const decaf::lang::String& ref) {
this->ref = ref;
}
View
52 activemq-cpp/src/main/decaf/internal/net/http/HttpHandler.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#include <decaf/internal/net/http/HttpHandler.h>
+
+#include <decaf/lang/exceptions/IllegalArgumentException.h>
+
+using namespace decaf;
+using namespace decaf::lang;
+using namespace decaf::lang::exceptions;
+using namespace decaf::internal;
+using namespace decaf::internal::net;
+using namespace decaf::internal::net::http;
+
+////////////////////////////////////////////////////////////////////////////////
+HttpHandler::~HttpHandler() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+decaf::net::URLConnection* HttpHandler::openConnection(const decaf::net::URL& url) {
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+decaf::net::URLConnection* HttpHandler::openConnection(const decaf::net::URL& url,
+ const decaf::net::Proxy* proxy) {
+
+ if (proxy == NULL) {
+ throw IllegalArgumentException(__FILE__, __LINE__, "proxy object cannot be NULL");
+ }
+
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int HttpHandler::getDefaultPort() const {
+ return 80;
+}
View
48 activemq-cpp/src/main/decaf/internal/net/http/HttpHandler.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef _DECAF_INTERNAL_NET_HTTP_HTTPHANDLER_H_
+#define _DECAF_INTERNAL_NET_HTTP_HTTPHANDLER_H_
+
+#include <decaf/util/Config.h>
+
+#include <decaf/net/URLStreamHandler.h>
+
+namespace decaf {
+namespace internal {
+namespace net {
+namespace http {
+
+ class DECAF_API HttpHandler : public decaf::net::URLStreamHandler {
+ public:
+
+ virtual ~HttpHandler();
+
+ public:
+
+ virtual decaf::net::URLConnection* openConnection(const decaf::net::URL& url);
+
+ virtual decaf::net::URLConnection* openConnection(const decaf::net::URL& url,
+ const decaf::net::Proxy* proxy);
+
+ virtual int getDefaultPort() const;
+
+ };
+
+}}}}
+
+#endif /* _DECAF_INTERNAL_NET_HTTP_HTTPHANDLER_H_ */
View
26 activemq-cpp/src/main/decaf/internal/util/StringUtils.cpp
@@ -18,9 +18,14 @@
#include "StringUtils.h"
#include <decaf/lang/Character.h>
+#include <decaf/lang/Integer.h>
+
+#include <decaf/lang/exceptions/RuntimeException.h>
+#include <decaf/lang/exceptions/NullPointerException.h>
using namespace decaf;
using namespace decaf::lang;
+using namespace decaf::lang::exceptions;
using namespace decaf::internal;
using namespace decaf::internal::util;
@@ -134,6 +139,27 @@ namespace {
}
////////////////////////////////////////////////////////////////////////////////
+int StringUtils::stringLength(const char* string) {
+
+ if (string == NULL) {
+ throw NullPointerException(__FILE__, __LINE__, "Cannot check length of NULL string.");
+ }
+
+ int length = 0;
+ while (*string != '\0') {
+ string++;
+
+ if (length == Integer::MAX_VALUE) {
+ throw RuntimeException(__FILE__, __LINE__, "String length is longer than Integer::MAX_VALUE");
+ }
+
+ length++;
+ }
+
+ return length;
+}
+
+////////////////////////////////////////////////////////////////////////////////
int StringUtils::compareIgnoreCase(const char* left, const char* right) {
return doCompare(left, right, true);
}
View
13 activemq-cpp/src/main/decaf/internal/util/StringUtils.h
@@ -39,6 +39,19 @@ namespace util {
virtual ~StringUtils() {}
/**
+ * Returns the length of the given C string.
+ *
+ * @param string
+ * The C style string to check.
+ *
+ * @returns the length of the string if the size is < Integer::MAX_VALUE.
+ *
+ * @throws RuntimeException if the length becomes larger than
+ * the max value of an int.
+ */
+ static int stringLength(const char* string);
+
+ /**
* Perform a comparison between two strings using natural ordering and ignoring case.
*
* @param left
View
1,231 activemq-cpp/src/main/decaf/lang/String.cpp
@@ -21,20 +21,26 @@
#include <decaf/lang/System.h>
#include <decaf/lang/exceptions/NullPointerException.h>
#include <decaf/lang/exceptions/IndexOutOfBoundsException.h>
+#include <decaf/lang/exceptions/StringIndexOutOfBoundsException.h>
#include <decaf/lang/Short.h>
#include <decaf/lang/Integer.h>
#include <decaf/lang/Long.h>
+#include <decaf/lang/Character.h>
#include <decaf/lang/Float.h>
#include <decaf/lang/Double.h>
+#include <decaf/internal/util/StringUtils.h>
+
using namespace std;
using namespace decaf;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
+using namespace decaf::internal;
+using namespace decaf::internal::util;
////////////////////////////////////////////////////////////////////////////////
-namespace decaf{
-namespace lang{
+namespace decaf {
+namespace lang {
class Contents {
public:
@@ -43,35 +49,60 @@ namespace lang{
int length;
int offset;
- public:
-
- Contents() : value(), length(0), offset(0) {
- }
+ int hashCode;
- Contents( int length ) : value(length), length(length), offset(0) {
- }
+ public:
+ Contents() : value(), length(0), offset(0), hashCode(0) {}
+ Contents(int length) : value(length), length(length), offset(0), hashCode(0) {}
+ Contents(int offset, int length, ArrayPointer<unsigned char> value) :
+ value(value), length(length), offset(offset), hashCode(0) {}
};
}}
////////////////////////////////////////////////////////////////////////////////
-String::String() : contents(new Contents()) {
+String::String(Contents* content) :
+ contents(new Contents(0, content->value.length(), content->value)) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String::String(int offset, int length, Contents* content) :
+ contents(new Contents(offset, length, content->value)) {
}
////////////////////////////////////////////////////////////////////////////////
-String::String(const String& source) : contents(new Contents(source.length())) {
+String::String() : contents(new Contents()) {
+}
- // TODO
- // load the passed string into the contents value.
- //System::arraycopy( (unsigned char*)source.c_str(), 0, contents->value.get(), 0, source.length() );
+////////////////////////////////////////////////////////////////////////////////
+String::String(const String& source) : contents(new Contents(*source.contents)) {
}
////////////////////////////////////////////////////////////////////////////////
String::String(const std::string& source) : contents(new Contents((int)source.length())) {
// load the passed string into the contents value.
- System::arraycopy( (unsigned char*)source.c_str(), 0, contents->value.get(), 0, source.length() );
+ System::arraycopy((unsigned char*)source.c_str(), 0, contents->value.get(), 0, source.length());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String::String(const char* array) : contents(new Contents) {
+
+ if (array == NULL) {
+ throw NullPointerException(
+ __FILE__, __LINE__, "Buffer pointer passed was NULL.");
+ }
+
+ int size = StringUtils::stringLength(array);
+
+ if (size > 0) {
+
+ this->contents->value = ArrayPointer<unsigned char>(size);
+ this->contents->length = size;
+
+ System::arraycopy((unsigned char*) array, 0, contents->value.get(), 0, size);
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -97,26 +128,55 @@ String::String(const char* array, int size) : contents(new Contents) {
}
////////////////////////////////////////////////////////////////////////////////
+String::String(const char* array, int offset, int length) : contents(new Contents) {
+
+ int size = StringUtils::stringLength(array);
+
+ if (offset > size || offset < 0) {
+ throw IndexOutOfBoundsException(
+ __FILE__, __LINE__, "offset parameter out of Bounds: %d.", offset);
+ }
+
+ if (length < 0 || length > size - offset) {
+ throw IndexOutOfBoundsException(
+ __FILE__, __LINE__, "length parameter out of Bounds: %d.", length);
+ }
+
+ if (array == NULL) {
+ throw NullPointerException(
+ __FILE__, __LINE__, "Buffer pointer passed was NULL.");
+ }
+
+ if (size > 0) {
+
+ this->contents->value = ArrayPointer<unsigned char>(length);
+ this->contents->length = length;
+
+ System::arraycopy((unsigned char*) array, offset, contents->value.get(), 0, length);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
String::String(const char* array, int size, int offset, int length) : contents(new Contents) {
if (size < 0) {
throw IndexOutOfBoundsException(
- __FILE__, __LINE__, "size parameter out of Bounds: %d.", size );
+ __FILE__, __LINE__, "size parameter out of Bounds: %d.", size);
}
if (offset > size || offset < 0) {
throw IndexOutOfBoundsException(
- __FILE__, __LINE__, "offset parameter out of Bounds: %d.", offset );
+ __FILE__, __LINE__, "offset parameter out of Bounds: %d.", offset);
}
if (length < 0 || length > size - offset) {
throw IndexOutOfBoundsException(
- __FILE__, __LINE__, "length parameter out of Bounds: %d.", length );
+ __FILE__, __LINE__, "length parameter out of Bounds: %d.", length);
}
if (array == NULL) {
throw NullPointerException(
- __FILE__, __LINE__, "Buffer pointer passed was NULL." );
+ __FILE__, __LINE__, "Buffer pointer passed was NULL.");
}
if (size > 0) {
@@ -138,28 +198,132 @@ String::~String() {
}
////////////////////////////////////////////////////////////////////////////////
-int String::length() const {
- return this->contents->offset + this->contents->length;
+String& String::operator= (const String& other) {
+ contents->value = other.contents->value;
+ contents->length = other.contents->length;
+ contents->offset = other.contents->offset;
+ contents->hashCode = other.contents->hashCode;
+
+ return *this;
}
////////////////////////////////////////////////////////////////////////////////
-bool String::isEmpty() const {
- return (this->contents->offset + this->contents->length) == 0;
+String& String::operator= (const std::string& other) {
+
+ if (!other.empty()) {
+ int length = (int) other.length();
+
+ contents->value = ArrayPointer<unsigned char>(length);
+ contents->length = length;
+ contents->hashCode = 0;
+
+ System::arraycopy((unsigned char*)other.c_str(), 0, contents->value.get(), 0, length);
+ }
+
+ return *this;
}
////////////////////////////////////////////////////////////////////////////////
-String String::trim() const {
- return String();
+String& String::operator= (const char* other) {
+
+ if (other == NULL) {
+ throw NullPointerException(__FILE__, __LINE__, "Assignment from NULL not supported.");
+ }
+
+ int length = StringUtils::stringLength(other);
+ if (length > 0) {
+ contents->value = ArrayPointer<unsigned char>(length);
+ contents->length = length;
+ contents->hashCode = 0;
+
+ System::arraycopy((unsigned char*)other, 0, contents->value.get(), 0, length);
+ }
+
+ return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::operator==(const String& other) const {
+ return this->equals(other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::operator==(const std::string& other) const {
+ return this->equals(other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::operator==(const char* other) const {
+ return this->equals(other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::operator!=(const String& other) const {
+ return !this->equals(other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::operator!=(const std::string& other) const {
+ return !this->equals(other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::operator!=(const char* other) const {
+ return !this->equals(other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::operator< (const String& other) const {
+ return this->compareTo(other) < 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::operator< (const std::string& other) const {
+ return this->compareTo(other) < 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::operator< (const char* other) const {
+ return this->compareTo(other) < 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::operator+ (const String& other) const {
+ return this->concat(other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::operator+ (const std::string& other) const {
+ return this->concat(other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::operator+ (const char* other) const {
+ return this->concat(other);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+const char* String::c_str() const {
+
+ if (contents->length == 0) {
+ return NULL;
+ }
+
+ if (contents->offset == 0 && contents->length == contents->value.length()) {
+ return (const char*) contents->value.get();
+ }
+
+ throw UnsupportedOperationException(__FILE__, __LINE__, "Not yet implemented for offset values");
}
////////////////////////////////////////////////////////////////////////////////
char String::charAt(int index) const {
- try{
+ try {
if (index < 0 || index >= this->length()) {
throw IndexOutOfBoundsException(
- __FILE__, __LINE__, "Index given is out of bounds: %d.", index );
+ __FILE__, __LINE__, "Index given is out of bounds: %d.", index);
}
return this->contents->value[this->contents->offset + index];
@@ -169,72 +333,1025 @@ char String::charAt(int index) const {
}
////////////////////////////////////////////////////////////////////////////////
-CharSequence* String::subSequence(int start DECAF_UNUSED, int end DECAF_UNUSED) const {
+int String::compareTo(const String& string) const {
- try {
+ int o1 = contents->offset;
+ int o2 = string.contents->offset;
+ int result;
- if (start > end) {
- throw IndexOutOfBoundsException(
- __FILE__, __LINE__, "Start index is greater than end index." );
+ int end = contents->offset +
+ (contents->length < string.contents->length ? contents->length : string.contents->length);
+
+ while (o1 < end) {
+ if ((result = contents->value[o1++] - string.contents->value[o2++]) != 0) {
+ return result;
}
+ }
- if (end - start > this->length()) {
- throw IndexOutOfBoundsException(
- __FILE__, __LINE__, "Requested Range is greater than the String length." );
+ return contents->length - string.contents->length;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::compareTo(const std::string& string) const {
+
+ int o1 = contents->offset;
+ int o2 = 0;
+ int result;
+
+ int end = contents->offset +
+ (contents->length < (int) string.length() ? contents->length : (int) string.length());
+
+ while (o1 < end) {
+ if ((result = contents->value[o1++] - string.at(o2++)) != 0) {
+ return result;
}
+ }
- return NULL;
+ return contents->length - (int)string.length();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::compareTo(const char* string) const {
+
+ if (string == NULL) {
+ throw NullPointerException(__FILE__, __LINE__, "Comparison C String cannot be NULL");
}
- DECAF_CATCH_RETHROW(IndexOutOfBoundsException)
- DECAF_CATCHALL_THROW(IndexOutOfBoundsException)
+
+ int length = StringUtils::stringLength(string);
+
+ int o1 = contents->offset;
+ int o2 = 0;
+ int result;
+
+ int end = contents->offset +
+ (contents->length < length ? contents->length : length);
+
+ while (o1 < end) {
+ if ((result = contents->value[o1++] - string[o2++]) != 0) {
+ return result;
+ }
+ }
+
+ return contents->length - length;
}
////////////////////////////////////////////////////////////////////////////////
-std::string String::toString() const {
+int String::compareToIgnoreCase(const String& string) const {
- if( this->contents->value == NULL ) {
- return "null";
+ int o1 = contents->offset;
+ int o2 = string.contents->offset;
+ int result;
+
+ int end = contents->offset +
+ (contents->length < string.contents->length ? contents->length : string.contents->length);
+ char c1, c2;
+
+ while (o1 < end) {
+ if ((c1 = contents->value[o1++]) == (c2 = string.contents->value[o2++])) {
+ continue;
+ }
+ c1 = Character::toLowerCase(c1);
+ c2 = Character::toLowerCase(c2);
+ if ((result = c1 - c2) != 0) {
+ return result;
+ }
}
- return std::string((const char*) this->contents->value.get(), this->length());
+ return contents->length - string.contents->length;
}
////////////////////////////////////////////////////////////////////////////////
-String String::valueOf(bool value) {
+int String::compareToIgnoreCase(const std::string& string) const {
- if (value) {
- return String("true");
+ int o1 = contents->offset;
+ int o2 = 0;
+ int result;
+
+ int end = contents->offset +
+ (contents->length < (int) string.length() ? contents->length : (int) string.length());
+ char c1, c2;
+
+ while (o1 < end) {
+ if ((c1 = contents->value[o1++]) == (c2 = string.at(o2++))) {
+ continue;
+ }
+ c1 = Character::toLowerCase(c1);
+ c2 = Character::toLowerCase(c2);
+ if ((result = c1 - c2) != 0) {
+ return result;
+ }
}
- return String("false");
+ return contents->length - (int) string.length();
}
////////////////////////////////////////////////////////////////////////////////
-String String::valueOf(char value) {
- return String(&value, 1);
+int String::compareToIgnoreCase(const char* string) const {
+
+ if (string == NULL) {
+ throw NullPointerException(__FILE__, __LINE__, "Comparison C String cannot be NULL");
+ }
+
+ int length = StringUtils::stringLength(string);
+
+ int o1 = contents->offset;
+ int o2 = 0;
+ int result;
+
+ int end = contents->offset + (contents->length < length ? contents->length : length);
+ char c1, c2;
+
+ while (o1 < end) {
+ if ((c1 = contents->value[o1++]) == (c2 = string[o2++])) {
+ continue;
+ }
+ c1 = Character::toLowerCase(c1);
+ c2 = Character::toLowerCase(c2);
+ if ((result = c1 - c2) != 0) {
+ return result;
+ }
+ }
+
+ return contents->length - length;
}
////////////////////////////////////////////////////////////////////////////////
-String String::valueOf(float value) {
- return String(Float::toString(value));
+String String::copyValueOf(const char* data) {
+ if (data == NULL) {
+ throw NullPointerException(__FILE__, __LINE__, "C String to be copied cannot be NULL");
+ }
+
+ return String(data, 0, StringUtils::stringLength(data));
}
////////////////////////////////////////////////////////////////////////////////
-String String::valueOf(double value) {
- return String(Double::toString(value));
+String String::copyValueOf(char* data, int start, int length) {
+ if (data == NULL) {
+ throw NullPointerException(__FILE__, __LINE__, "C String to be copied cannot be NULL");
+ }
+
+ return String(data, start, length);
}
////////////////////////////////////////////////////////////////////////////////
-String String::valueOf(short value) {
- return String(Short::toString(value));
+String String::concat(const String& string) const {
+
+ if (string.contents->length == 0) {
+ return *this;
+ }
+
+ Contents buffer(contents->length + string.contents->length);
+
+ if (contents->length > 0) {
+ System::arraycopy(contents->value.get(), contents->offset,
+ buffer.value.get(), 0, contents->length);
+ }
+
+ System::arraycopy(string.contents->value.get(), string.contents->offset,
+ buffer.value.get(), contents->length, string.contents->length);
+
+ return String(&buffer);
}
////////////////////////////////////////////////////////////////////////////////
-String String::valueOf(int value) {
- return String(Integer::toString(value));
+String String::concat(const std::string& string) const {
+
+ if (string.length() == 0) {
+ return *this;
+ }
+
+ Contents buffer(contents->length + (int) string.length());
+
+ if (contents->length > 0) {
+ System::arraycopy(contents->value.get(), contents->offset,
+ buffer.value.get(), 0, contents->length);
+ }
+
+ System::arraycopy((const unsigned char*) string.c_str(),
+ 0, buffer.value.get(), contents->length, string.length());
+
+ return String(&buffer);
}
////////////////////////////////////////////////////////////////////////////////
-String String::valueOf(long long value) {
- return String(Long::toString(value));
+String String::concat(const char* string) const {
+
+ if (string == NULL) {
+ return *this;
+ }
+
+ int length = StringUtils::stringLength(string);
+
+ if (length == 0) {
+ return *this;
+ }
+
+ Contents buffer(contents->length + length);
+
+ if (contents->length > 0) {
+ System::arraycopy(contents->value.get(), contents->offset,
+ buffer.value.get(), 0, contents->length);
+ }
+
+ System::arraycopy((const unsigned char*) string, 0,
+ buffer.value.get(), contents->length, length);
+
+ return String(&buffer);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::contains(const String& string) const {
+ return indexOf(string) >= 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::contains(const std::string& string) const {
+ return indexOf(string) >= 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::contains(const char* string) const {
+ return indexOf(string) >= 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::endsWith(const String& suffix) const {
+ return regionMatches(contents->length - suffix.contents->length, suffix, 0, suffix.contents->length);
}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::equals(const String& other) const {
+
+ if (this == &other) {
+ return true;
+ }
+
+ if (other.isEmpty() && this->isEmpty()) {
+ return true;
+ }
+
+ if (other.length() != this->length()) {
+ return false;
+ }
+
+ // Don't force compute hash code on this instance, if not already done
+ // we will just do a straight compare.
+ int hashCode = contents->hashCode;
+ int otherHashCode = other.contents->hashCode;
+
+ if (hashCode != otherHashCode && hashCode != 0 && otherHashCode != 0) {
+ return false;
+ }
+
+ for (int i = 0; i < contents->length; ++i) {
+ if (contents->value[contents->offset + i] != other.contents->value[other.contents->offset + i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::equals(const std::string& other) const {
+
+ if (other.empty() && this->isEmpty()) {
+ return true;
+ }
+
+ if (other.length() != (std::size_t) this->length()) {
+ return false;
+ }
+
+ for (int i = 0; i < contents->length; ++i) {
+ if (contents->value[contents->offset + i] != (unsigned char) other.at(i)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::equals(const char* other) const {
+
+ if (other == NULL) {
+ return false;
+ }
+
+ if (StringUtils::stringLength(other) != this->length()) {
+ return false;
+ }
+
+ for (int i = 0; i < contents->length; ++i) {
+ if (contents->value[contents->offset + i] != (unsigned char) other[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::equalsIgnoreCase(const String& string) const {
+ if (this == &string) {
+ return true;
+ }
+
+ if (contents->length != string.contents->length) {
+ return false;
+ }
+
+ int offsetThis = contents->offset;
+ int offsetOther = string.contents->offset;
+ int end = contents->offset + contents->length;
+
+ char c1, c2;
+ ArrayPointer<unsigned char> target = string.contents->value;
+
+ while (offsetThis < end) {
+ if ((c1 = contents->value[offsetThis++]) != (c2 = target[offsetOther++])) {
+ // If we add support for multibyte strings we need to check both cases
+ // toUpperCase and toLowerCase because of Unicode.
+ if (Character::toUpperCase(c1) != Character::toUpperCase(c2)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::equalsIgnoreCase(const std::string& string) const {
+
+ if (contents->length != (int) string.length()) {
+ return false;
+ }
+
+ int offsetThis = contents->offset;
+ int end = contents->offset + contents->length;
+
+ int indexOther = 0;
+ char c1, c2;
+
+ while (offsetThis < end) {
+ if ((c1 = contents->value[offsetThis++]) != (c2 = string.at(indexOther++))) {
+ // If we add support for multibyte strings we need to check both cases
+ // toUpperCase and toLowerCase because of Unicode.
+ if (Character::toUpperCase(c1) != Character::toUpperCase(c2)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::equalsIgnoreCase(const char* string) const {
+
+ if (string == NULL) {
+ return false;
+ }
+
+ int stringLen = StringUtils::stringLength(string);
+
+ if (contents->length != stringLen) {
+ return false;
+ }
+
+ int indexOther = 0;
+ int offsetThis = contents->offset;
+ int end = contents->offset + contents->length;
+
+ char c1, c2;
+
+ while (offsetThis < end) {
+ if ((c1 = contents->value[offsetThis++]) != (c2 = string[indexOther++])) {
+ // If we add support for multibyte strings we need to check both cases
+ // toUpperCase and toLowerCase because of Unicode.
+ if (Character::toUpperCase(c1) != Character::toUpperCase(c2)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::hashCode() const {
+
+ if (contents->hashCode == 0) {
+ if (contents->length == 0) {
+ return 0;
+ }
+
+ int hash = 0;
+
+ for (int i = contents->offset; i < contents->length + contents->offset; i++) {
+ hash = contents->value[i] + ((hash << 5) - hash);
+ }
+ contents->hashCode = hash;
+ }
+ return contents->hashCode;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::isEmpty() const {
+ return this->contents->length == 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::isNullOrEmpty(const char* string) {
+ return string == NULL || StringUtils::stringLength(string) == 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::indexOf(char value) const {
+ return indexOf(value, 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::indexOf(char value, int start) const {
+ if (start < contents->length) {
+ if (start < 0) {
+ start = 0;
+ }
+
+ for (int i = contents->offset + start; i < contents->offset + contents->length; i++) {
+ if (contents->value[i] == value) {
+ return i - contents->offset;
+ }
+ }
+ }
+ return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::indexOf(const String& string) const {
+ return indexOf(string, 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::indexOf(const String& subString, int start) const {
+
+ if (start < 0) {
+ start = 0;
+ }
+
+ int subCount = subString.contents->length;
+ if (subCount > 0) {
+ if (subCount + start > contents->length) {
+ return -1;
+ }
+
+ unsigned char* target = subString.contents->value.get();
+ int subOffset = subString.contents->offset;
+
+ char firstChar = target[subOffset];
+ int end = subOffset + subCount;
+
+ while (true) {
+ int i = indexOf(firstChar, start);
+ if (i == -1 || subCount + i > contents->length) {
+ return -1; // handles subCount > length() || start >= length()
+ }
+
+ int o1 = contents->offset + i;
+ int o2 = subOffset;
+
+ while (++o2 < end && contents->value[++o1] == target[o2]) {
+ // Intentionally empty
+ }
+ if (o2 == end) {
+ return i;
+ }
+ start = i + 1;
+ }
+ }
+
+ return start < contents->length ? start : contents->length;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::indexOf(const std::string& string) const {
+ return indexOf(string, 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::indexOf(const std::string& subString, int start) const {
+
+ if (start < 0) {
+ start = 0;
+ }
+
+ int subCount = (int) subString.length();
+ if (subCount > 0) {
+ if (subCount + start > contents->length) {
+ return -1;
+ }
+
+ const char* target = subString.c_str();
+ char firstChar = target[0];
+ int end = subCount;
+
+ while (true) {
+ int i = indexOf(firstChar, start);
+ if (i == -1 || subCount + i > contents->length) {
+ return -1; // handles subCount > length() || start >= length()
+ }
+
+ int o1 = contents->offset + i;
+ int o2 = 0;
+
+ while (++o2 < end && contents->value[++o1] == target[o2]) {
+ // Intentionally empty
+ }
+ if (o2 == end) {
+ return i;
+ }
+ start = i + 1;
+ }
+ }
+
+ return start < contents->length ? start : contents->length;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::indexOf(const char* string) const {
+ return indexOf(string, 0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::indexOf(const char* subString, int start) const {
+
+ if (start < 0) {
+ start = 0;
+ }
+
+ if (subString == NULL) {
+ return -1;
+ }
+
+ int subCount = StringUtils::stringLength(subString);
+ if (subCount > 0) {
+ if (subCount + start > contents->length) {
+ return -1;
+ }
+
+ char firstChar = subString[0];
+ int end = subCount;
+
+ while (true) {
+ int i = indexOf(firstChar, start);
+ if (i == -1 || subCount + i > contents->length) {
+ return -1; // handles subCount > length() || start >= length()
+ }
+
+ int o1 = contents->offset + i;
+ int o2 = 0;
+
+ while (++o2 < end && contents->value[++o1] == subString[o2]) {
+ // Intentionally empty
+ }
+ if (o2 == end) {
+ return i;
+ }
+ start = i + 1;
+ }
+ }
+
+ return start < contents->length ? start : contents->length;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::lastIndexOf(char value) const {
+ return lastIndexOf(value, contents->length - 1);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::lastIndexOf(char value, int start) const {
+ if (start >= 0) {
+ if (start >= contents->length) {
+ start = contents->length - 1;
+ }
+
+ for (int i = contents->offset + start; i >= contents->offset; --i) {
+ if (contents->value[i] == value) {
+ return i - contents->offset;
+ }
+ }
+ }
+ return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::lastIndexOf(const String& string) const {
+ // Use length instead of length - 1 so lastIndexOf("") answers length
+ return lastIndexOf(string, contents->length);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::lastIndexOf(const String& subString, int start) const {
+ int subCount = subString.contents->length;
+
+ if (subCount <= contents->length && start >= 0) {
+ if (subCount > 0) {
+ if (start > contents->length - subCount) {
+ start = contents->length - subCount;
+ }
+
+ // count and subCount are both >= 1
+ unsigned char* target = subString.contents->value.get();
+ int subOffset = subString.contents->offset;
+ char firstChar = target[subOffset];
+ int end = subOffset + subCount;
+
+ while (true) {
+ int i = lastIndexOf(firstChar, start);
+ if (i == -1) {
+ return -1;
+ }
+
+ int o1 = contents->offset + i;
+ int o2 = subOffset;
+
+ while (++o2 < end && contents->value[++o1] == target[o2]) {
+ // Intentionally empty
+ }
+
+ if (o2 == end) {
+ return i;
+ }
+ start = i - 1;
+ }
+ }
+ return start < contents->length ? start : contents->length;
+ }
+ return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::lastIndexOf(const std::string& string) const {
+ // Use length instead of length - 1 so lastIndexOf("") answers length
+ return lastIndexOf(string, contents->length);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::lastIndexOf(const std::string& subString, int start) const {
+ int subCount = (int) subString.length();
+
+ if (subCount <= contents->length && start >= 0) {
+ if (subCount > 0) {
+ if (start > contents->length - subCount) {
+ start = contents->length - subCount;
+ }
+
+ // count and subCount are both >= 1
+ const char* target = subString.c_str();
+ char firstChar = target[0];
+ int end = subCount;
+
+ while (true) {
+ int i = lastIndexOf(firstChar, start);
+ if (i == -1) {
+ return -1;
+ }
+
+ int o1 = contents->offset + i;
+ int o2 = 0;
+
+ while (++o2 < end && contents->value[++o1] == target[o2]) {
+ // Intentionally empty
+ }
+
+ if (o2 == end) {
+ return i;
+ }
+ start = i - 1;
+ }
+ }
+ return start < contents->length ? start : contents->length;
+ }
+ return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::lastIndexOf(const char* string) const {
+ // Use length instead of length - 1 so lastIndexOf("") answers length
+ return lastIndexOf(string, contents->length);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::lastIndexOf(const char* subString, int start) const {
+
+ if (subString == NULL) {
+ return -1;
+ }
+
+ int subCount = StringUtils::stringLength(subString);
+
+ if (subCount <= contents->length && start >= 0) {
+ if (subCount > 0) {
+ if (start > contents->length - subCount) {
+ start = contents->length - subCount;
+ }
+
+ // count and subCount are both >= 1
+ char firstChar = subString[0];
+ int end = subCount;
+
+ while (true) {
+ int i = lastIndexOf(firstChar, start);
+ if (i == -1) {
+ return -1;
+ }
+
+ int o1 = contents->offset + i;
+ int o2 = 0;
+
+ while (++o2 < end && contents->value[++o1] == subString[o2]) {
+ // Intentionally empty
+ }
+
+ if (o2 == end) {
+ return i;
+ }
+ start = i - 1;
+ }
+ }
+ return start < contents->length ? start : contents->length;
+ }
+ return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int String::length() const {
+ return this->contents->length;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::regionMatches(int thisStart, const String& string, int start, int length) const {
+
+ if (string.contents->length - start < length || start < 0) {
+ return false;
+ }
+
+ if (thisStart < 0 || contents->length - thisStart < length) {
+ return false;
+ }
+
+ if (length <= 0) {
+ return true;
+ }
+
+ int o1 = contents->offset + thisStart;
+ int o2 = string.contents->offset + start;
+
+ for (int i = 0; i < length; ++i) {
+ if (contents->value[o1 + i] != string.contents->value[o2 + i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::regionMatches(bool ignoreCase, int thisStart, const String& string, int start, int length) const {
+
+ if (!ignoreCase) {
+ return regionMatches(thisStart, string, start, length);
+ }
+
+ if (thisStart < 0 || length > contents->length - thisStart) {
+ return false;
+ }
+ if (start < 0 || length > string.contents->length - start) {
+ return false;
+ }
+
+ thisStart += contents->offset;
+ start += string.contents->offset;
+ int end = thisStart + length;
+ char c1, c2;
+
+ while (thisStart < end) {
+ if ((c1 = contents->value[thisStart++]) != (c2 = string.contents->value[start++])) {
+ // If we add support for multibyte strings we need to check both cases
+ // toUpperCase and toLowerCase because of Unicode.
+ if (Character::toUpperCase(c1) != Character::toUpperCase(c2)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::replace(char oldChar, char newChar) const {
+
+ int index = indexOf(oldChar, 0);
+ if (index == -1) {
+ return *this;
+ }
+
+ Contents buffer(contents->length);
+
+ System::arraycopy(contents->value.get(), contents->offset, buffer.value.get(), 0, contents->length);
+
+ do {
+ buffer.value[index++] = newChar;
+ } while ((index = indexOf(oldChar, index)) != -1);
+
+ return String(&buffer);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::startsWith(const String& prefix) const {
+ return regionMatches(0, prefix, 0, prefix.contents->length);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool String::startsWith(const String& prefix, int start) const {
+ return regionMatches(start, prefix, 0, prefix.contents->length);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::substring(int start) const {
+
+ if (start == 0) {
+ return *this;
+ }
+
+ if (0 <= start && start <= contents->length) {
+ return String(contents->offset + start, contents->length - start, contents);
+ }
+
+ throw StringIndexOutOfBoundsException(__FILE__, __LINE__, start);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::substring(int start, int end) const {
+
+ if (start == 0 && end == contents->length) {
+ return *this;
+ }
+
+ if (start < 0) {
+ throw StringIndexOutOfBoundsException(__FILE__, __LINE__, start);
+ } else if (start > end) {
+ throw StringIndexOutOfBoundsException(__FILE__, __LINE__, end - start);
+ } else if (end > contents->length) {
+ throw StringIndexOutOfBoundsException(__FILE__, __LINE__, end);
+ }
+
+ // NOTE last character not copied!
+ return String(contents->offset + start, end - start, contents);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+CharSequence* String::subSequence(int start DECAF_UNUSED, int end DECAF_UNUSED) const {
+
+ try {
+
+ if (start > end) {
+ throw IndexOutOfBoundsException(
+ __FILE__, __LINE__, "Start index is greater than end index.");
+ }
+
+ if (end - start > this->length()) {
+ throw IndexOutOfBoundsException(
+ __FILE__, __LINE__, "Requested Range is greater than the String length.");
+ }
+
+ return NULL;
+ }
+ DECAF_CATCH_RETHROW(IndexOutOfBoundsException)
+ DECAF_CATCHALL_THROW(IndexOutOfBoundsException)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+char* String::toCharArray() const {
+ char* buffer = new char[contents->length];
+ System::arraycopy((const char*)contents->value.get(), contents->offset, buffer, 0, contents->length);
+ return buffer;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::toLowerCase() const {
+
+ Contents newContents(contents->length);
+ int offset = contents->offset;
+
+ for (int i = 0; i < contents->length; ++i) {
+ newContents.value[i] = Character::toLowerCase(contents->value[offset + i]);
+ }
+
+ return String(&newContents);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::toUpperCase() const {
+
+ Contents newContents(contents->length);
+ int offset = contents->offset;
+
+ for (int i = 0; i < contents->length; ++i) {
+ newContents.value[i] = Character::toUpperCase(contents->value[offset + i]);
+ }
+
+ return String(&newContents);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::string String::toString() const {
+
+ if (this->contents->value == NULL) {
+ return "null";
+ }
+
+ return std::string((const char*) contents->value.get() + contents->offset, this->length());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::trim() const {
+
+ int start = contents->offset;
+ int last = contents->offset + contents->length - 1;
+
+ int end = last;
+
+ while ((start <= end) && (contents->value[start] <= 0x20)) {
+ start++;
+ }
+
+ while ((end >= start) && (contents->value[end] <= 0x20)) {
+ end--;
+ }
+
+ if (start == contents->offset && end == last) {
+ return *this;
+ }
+
+ return String(start, end - start + 1, contents);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::valueOf(bool value) {
+
+ if (value) {
+ return String("true");
+ }
+
+ return String("false");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::valueOf(char value) {
+ return String(&value, 1);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::valueOf(float value) {
+ return String(Float::toString(value));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::valueOf(double value) {
+ return String(Double::toString(value));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::valueOf(short value) {
+ return String(Short::toString(value));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::valueOf(int value) {
+ return String(Integer::toString(value));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String String::valueOf(long long value) {
+ return String(Long::toString(value));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+namespace decaf {
+namespace lang {
+
+ std::ostream& operator<<(std::ostream &out, const String& target) {
+
+ if (target.isEmpty()) {
+ out << "NULL";
+ }
+
+ for (int i = 0; i < target.length(); ++i) {
+ out << target.charAt(i);
+ }
+
+ return out;
+ }
+
+}}
View
806 activemq-cpp/src/main/decaf/lang/String.h
@@ -24,6 +24,7 @@
#include <decaf/lang/Comparable.h>
#include <string>
+#include <ostream>
namespace decaf {
namespace lang {
@@ -64,6 +65,18 @@ namespace lang {
String(const std::string& source);
/**
+ * Create a new String object that represents the given array of characters, the C string
+ * must be null terminated in order for a proper size calculation to work. If the string
+ * is not properly terminated than this method can overrun the array and cause a fault.
+ *
+ * @param array
+ * The character buffer to copy into this new String object.
+ *
+ * @throws NullPointerException if the character array parameter is NULL.
+ */
+ String(const char* array);
+
+ /**
* Create a new String object that represents the given array of characters. The method
* takes the size of the array as a parameter to allow for strings that are not NULL
* terminated, the caller can pass strlen(array) in the case where the array is properly
@@ -80,6 +93,24 @@ namespace lang {
String(const char* array, int size);
/**
+ * Create a new String object that represents the given array of characters, the C string
+ * must be null terminated in order for a proper size calculation to work. If the string
+ * is not properly terminated than this method can overrun the array and cause a fault.
+ *
+ * @param array
+ * The character buffer to copy into this new String object.
+ * @param offset
+ * The position to start copying from in the given buffer.
+ * @param length
+ * The number of bytes to copy from the given buffer starting from the offset.
+ *
+ * @throws NullPointerException if the character array parameter is NULL.
+ * @throws IndexOutOfBoundsException if the size, offset or length parameter is negative
+ * or if the length to copy is greater than the span of size - offset.
+ */
+ String(const char* array, int offset, int length);
+
+ /**
* Create a new String object that represents the given array of characters. The method
* takes the size of the array as a parameter to allow for strings that are not NULL
* terminated, the caller can pass strlen(array) in the case where the array is properly
@@ -104,18 +135,738 @@ namespace lang {
public:
- // TODO
- String& operator=(const String&);
- String& operator=(const std::string&);
+ /**
+ * Assignment from another String instance. The internal contents of this string now
+ * reference the same contents as the provided String. The original contents of this
+ * String are not altered in other String instances that reference it.
+ *
+ * @param other
+ * The other String to assign to this instance.
+ *
+ * @returns a reference to this string with the new contents.
+ */
+ String& operator= (const String& other);
+
+ /**
+ * Assignment from another std::string instance. The internal contents of this string now
+ * reference a copy of the contents as the provided std::string. The original contents of
+ * this String are not altered in other String instances that reference it.
+ *
+ * @param other
+ * The other std::string to assign to this instance.
+ *
+ * @returns a reference to this string with the new contents.
+ */
+ String& operator= (const std::string& other);
+
+ /**
+ * Assignment from another C string instance. The internal contents of this string now
+ * reference a copy of the contents as the provided C string. The original contents of
+ * this String are not altered in other String instances that reference it.
+ *
+ * @param other
+ * The other C string to assign to this instance.
+ *
+ * @returns a reference to this string with the new contents.
+ */
+ String& operator= (const char* other);
+
+ /**
+ * Comparison operators for the various string types that uses the equals method
+ * to determine equality.
+ *
+ * @param other
+ * The string value to compare to this one.
+ *
+ * @returns true if the other string is equal to this one, false otherwise.
+ */
+ bool operator==(const char* other) const;
+ bool operator==(const String& other) const;
+ bool operator==(const std::string& other) const;
+
+ /**
+ * Comparison operators for the various string types that uses the equals method
+ * to determine equality.
+ *
+ * @param other
+ * The string value to compare to this one.
+ *
+ * @returns true if the other string is not equal to this one, false otherwise.
+ */
+ bool operator!=(const char* other) const;
+ bool operator!=(const String& other) const;
+ bool operator!=(const std::string& other) const;
+
+ /**
+ * Comparison operators for the various string types that uses the compareTo method
+ * to determine the string are lexicographically equal or not.
+ *
+ * @param other
+ * The string value to compare to this one.
+ *
+ * @returns true if this string is lexicographically less than the other string.
+ */
+ bool operator< (const char* other) const;
+ bool operator< (const String& other) const;
+ bool operator< (const std::string& other) const;
+
+ /**
+ * Concatenation operators for the various string types. The value of this string
+ * and the given string are concatenated and returned in a new String instance.
+ *
+ * @param other
+ * The string whose value is to be concatenated with this one.
+ *
+ * @returns a new String instance that is the concatenation of the two strings.
+ */
+ String operator+ (const String& other) const;
+ String operator+ (const std::string& other) const;
+ String operator+ (const char* other) const;
+
+ private:
+
+ // TODO - String is not always NULL terminated at the moment.
+
+ /**
+ * Returns a const char* value to allow easier coexistence with standard c++
+ * string operations. The value returned will be NULL if the String is empty.
+ *
+ * @returns a const char* value for this String or NULL if empty.
+ */
+ const char* c_str() const;
public:
/**
+ * Compares two strings lexicographically. The comparison is based on the value
+ * of each character in the strings. The character sequence represented by this
+ * String is compared lexicographically to the character sequence represented by
+ * the provided string. The result is a negative number if this String
+ * lexicographically precedes the argument string. The result is a positive value
+ * if this String lexicographically follows the argument string. The result is
+ * zero if the strings are equal; compareTo returns 0 exactly when the equals
+ * method would return true.
+ *
+ * @param string
+ * the string to compare.
+ *
+ * @return 0 if the strings are equal, a negative integer if this string is
+ * before the specified string, or a positive integer if this string
+ * is after the specified string.
+ */
+ int compareTo(const String& string) const;
+
+ /**
+ * Compares two strings lexicographically. The comparison is based on the value
+ * of each character in the strings. The character sequence represented by this
+ * String is compared lexicographically to the character sequence represented by
+ * the provided string. The result is a negative number if this String
+ * lexicographically precedes the argument string. The result is a positive value
+ * if this String lexicographically follows the argument string. The result is
+ * zero if the strings are equal; compareTo returns 0 exactly when the equals
+ * method would return true.
+ *
+ * @param string
+ * the STL string to compare.
+ *
+ * @return 0 if the strings are equal, a negative integer if this string is
+ * before the specified string, or a positive integer if this string
+ * is after the specified string.
+ */
+ int compareTo(const std::string& string) const;
+
+ /**
+ * Compares two strings lexicographically. The comparison is based on the value
+ * of each character in the strings. The character sequence represented by this
+ * String is compared lexicographically to the character sequence represented by
+ * the provided string. The result is a negative number if this String
+ * lexicographically precedes the argument string. The result is a positive value
+ * if this String lexicographically follows the argument string. The result is
+ * zero if the strings are equal; compareTo returns 0 exactly when the equals
+ * method would return true.
+ *
+ * @param string
+ * the C string to compare.
+ *
+ * @return 0 if the strings are equal, a negative integer if this string is
+ * before the specified string, or a positive integer if this string
+ * is after the specified string.
+ *
+ * @throws NullPointerException if the passed in C String value is NULL.
+ */
+ int compareTo(const char* string) const;
+
+ /**
+ * Compares two strings lexicographically, ignoring case differences. This method
+ * returns an integer whose sign is that of calling compareTo with normalized
+ * versions of the strings where case differences have been eliminated by calling
+ * Character::toLowerCase() on each character.
+ *
+ * @param string
+ * the string to compare.
+ *
+ * @return 0 if the strings are equal, a negative integer if this string is
+ * before the specified string, or a positive integer if this string
+ * is after the specified string.
+ */
+ int compareToIgnoreCase(const String& string) const;
+
+ /**
+ * Compares two strings lexicographically, ignoring case differences. This method
+ * returns an integer whose sign is that of calling compareTo with normalized
+ * versions of the strings where case differences have been eliminated by calling
+ * Character::toLowerCase() on each character.
+ *
+ * @param string
+ * the STL string to compare.
+ *
+ * @return 0 if the strings are equal, a negative integer if this string is
+ * before the specified string, or a positive integer if this string
+ * is after the specified string.
+ */
+ int compareToIgnoreCase(const std::string& string) const;
+
+ /**
+ * Compares two strings lexicographically, ignoring case differences. This method
+ * returns an integer whose sign is that of calling compareTo with normalized
+ * versions of the strings where case differences have been eliminated by calling
+ * Character::toLowerCase() on each character.
+ *
+ * @param string
+ * the C string to compare.
+ *
+ * @return 0 if the strings are equal, a negative integer if this string is
+ * before the specified string, or a positive integer if this string
+ * is after the specified string.
+ *
+ * @throws NullPointerException if the passed in C String value is NULL.
+ */
+ int compareToIgnoreCase(const char* string) const;
+
+ /**
+ * Concatenates this string and the specified string.
+ *
+ * @param string
+ * the string to concatenate onto this String
+ *
+ * @return a new string which is the concatenation of this string and the
+ * specified string.
+ */
+ String concat(const String& string) const;
+
+ /**
+ * Concatenates this string and the specified std::string.
+ *
+ * @param string
+ * the STL string to concatenate onto this String
+ *
+ * @return a new string which is the concatenation of this string and the
+ * specified string.
+ */
+ String concat(const std::string& string) const;
+
+ /**
+ * Concatenates this string and the specified C string.
+ *
+ * @param string
+ * the C string to concatenate onto this String
+ *
+ * @return a new string which is the concatenation of this string and the
+ * specified string.
+ */
+ String concat(const char* string) const;
+
+ /**
+ * Determines if this String contains the sequence of characters in the String
+ * passed in.
+ *
+ * @param string
+ * the String value to search for.
+ *
+ * @return true if the sequence of characters are contained in this String,
+ * otherwise returns false.
+ */
+ bool contains(const String& string) const;
+
+ /**
+ * Determines if this String contains the sequence of characters in the std::string
+ * passed in.
+ *
+ * @param string
+ * the STL String value to search for.
+ *
+ * @return true if the sequence of characters are contained in this String,
+ * otherwise returns false.
+ */
+ bool contains(const std::string& string) const;
+
+ /**
+ * Determines if this String contains the sequence of characters in the C String
+ * passed in. If the value given is null the method always returns false.
+ *
+ * @param string
+ * the C String value to search for.
+ *
+ * @return true if the sequence of characters are contained in this String,
+ * otherwise returns false.
+ */
+ bool contains(const char* string) const;
+
+ /**
+ * Compares the specified string to this string to determine if the
+ * specified string is a suffix.
+ *
+ * @param suffix
+ * the suffix to look for.
+ *
+ * @return true if the specified string is a suffix of this string, false otherwise.
+ */
+ bool endsWith(const String& suffix) const;
+
+ /**
+ * Returns true if this String is equal to the given String instance.
+ *
+ * @param other
+ * A String instance to compare to this string.
+ *
+ * @returns true if this String is equal to the given String instance.
+ */
+ bool equals(const String& other) const;
+
+ /**
+ * Returns true if this String is equal to the given std::string instance.
+ *
+ * @param other
+ * A standard string instance to compare to this String.