From a8b241a7fc2c0342edd15767bef8e39de3bda363 Mon Sep 17 00:00:00 2001 From: "darin%meer.net" Date: Tue, 16 Nov 2004 04:44:57 +0000 Subject: [PATCH] fixes bug 264274 "support dependent strings in frozen string API" r=biesi sr=bsmedberg git-svn-id: svn://10.0.0.236/trunk@165390 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/build/nsXPCOMPrivate.h | 6 ++ mozilla/xpcom/glue/standalone/nsXPCOMGlue.cpp | 22 +++++ mozilla/xpcom/string/public/nsStringAPI.h | 98 ++++++++++++++++++- mozilla/xpcom/string/public/nsTSubstring.h | 14 ++- mozilla/xpcom/stub/nsStringAPI.cpp | 90 +++++++++++++++++ mozilla/xpcom/stub/nsXPComStub.cpp | 6 +- mozilla/xpcom/tests/TestMinStringAPI.cpp | 88 +++++++++++++++++ 7 files changed, 316 insertions(+), 8 deletions(-) diff --git a/mozilla/xpcom/build/nsXPCOMPrivate.h b/mozilla/xpcom/build/nsXPCOMPrivate.h index 02db40df760..1779cce403e 100644 --- a/mozilla/xpcom/build/nsXPCOMPrivate.h +++ b/mozilla/xpcom/build/nsXPCOMPrivate.h @@ -96,6 +96,7 @@ typedef nsresult (* GetDebugFunc)(nsIDebug* *result); typedef nsresult (* GetTraceRefcntFunc)(nsITraceRefcnt* *result); typedef nsresult (* StringContainerInitFunc)(nsStringContainer&); +typedef nsresult (* StringContainerInit2Func)(nsStringContainer&, const PRUnichar *, PRUint32, PRUint32); typedef void (* StringContainerFinishFunc)(nsStringContainer&); typedef PRUint32 (* StringGetDataFunc)(const nsAString&, const PRUnichar**, PRBool*); typedef PRUnichar* (* StringCloneDataFunc)(const nsAString&); @@ -104,6 +105,7 @@ typedef nsresult (* StringSetDataRangeFunc)(nsAString&, PRUint32, PRUint32, co typedef nsresult (* StringCopyFunc)(nsAString &, const nsAString &); typedef nsresult (* CStringContainerInitFunc)(nsCStringContainer&); +typedef nsresult (* CStringContainerInit2Func)(nsCStringContainer&, const char *, PRUint32, PRUint32); typedef void (* CStringContainerFinishFunc)(nsCStringContainer&); typedef PRUint32 (* CStringGetDataFunc)(const nsACString&, const char**, PRBool*); typedef char* (* CStringCloneDataFunc)(const nsACString&); @@ -159,9 +161,13 @@ typedef struct XPCOMFunctions{ UTF16ToCString utf16ToCString; StringCloneDataFunc stringCloneData; CStringCloneDataFunc cstringCloneData; + + // Added for Mozilla 1.8 AllocFunc allocFunc; ReallocFunc reallocFunc; FreeFunc freeFunc; + StringContainerInit2Func stringContainerInit2; + CStringContainerInit2Func cstringContainerInit2; } XPCOMFunctions; diff --git a/mozilla/xpcom/glue/standalone/nsXPCOMGlue.cpp b/mozilla/xpcom/glue/standalone/nsXPCOMGlue.cpp index 6f1b4740746..6aca278d761 100644 --- a/mozilla/xpcom/glue/standalone/nsXPCOMGlue.cpp +++ b/mozilla/xpcom/glue/standalone/nsXPCOMGlue.cpp @@ -288,6 +288,17 @@ NS_StringContainerInit(nsStringContainer &aStr) return xpcomFunctions.stringContainerInit(aStr); } +extern "C" NS_COM nsresult +NS_StringContainerInit2(nsStringContainer &aStr, + const PRUnichar *aData, + PRUint32 aDataLength, + PRUint32 aFlags) +{ + if (!xpcomFunctions.stringContainerInit2) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.stringContainerInit2(aStr, aData, aDataLength, aFlags); +} + extern "C" NS_COM void NS_StringContainerFinish(nsStringContainer &aStr) { @@ -348,6 +359,17 @@ NS_CStringContainerInit(nsCStringContainer &aStr) return xpcomFunctions.cstringContainerInit(aStr); } +extern "C" NS_COM nsresult +NS_CStringContainerInit2(nsCStringContainer &aStr, + const char *aData, + PRUint32 aDataLength, + PRUint32 aFlags) +{ + if (!xpcomFunctions.cstringContainerInit2) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringContainerInit2(aStr, aData, aDataLength, aFlags); +} + extern "C" NS_COM void NS_CStringContainerFinish(nsCStringContainer &aStr) { diff --git a/mozilla/xpcom/string/public/nsStringAPI.h b/mozilla/xpcom/string/public/nsStringAPI.h index 30730d5196a..29d457f017f 100644 --- a/mozilla/xpcom/string/public/nsStringAPI.h +++ b/mozilla/xpcom/string/public/nsStringAPI.h @@ -70,7 +70,7 @@ class nsACString; * implementation detail. * * The string data stored in a string container is always single fragment - * and null-terminated. + * and may be null-terminated depending on how it is initialized. * * Typically, string containers are allocated on the stack for temporary * use. However, they can also be malloc'd if necessary. In either case, @@ -128,6 +128,27 @@ class nsACString; */ class nsStringContainer; +/** + * Flags that may be OR'd together to pass to NS_StringContainerInit2: + */ +enum { + /* Data passed into NS_StringContainerInit2 is not copied; instead, the + * string references the passed in data pointer directly. The caller must + * ensure that the data is valid for the lifetime of the string container. + * This flag should not be combined with NS_STRING_CONTAINER_INIT_ADOPT. */ + NS_STRING_CONTAINER_INIT_DEPEND = (1 << 1), + + /* Data passed into NS_StringContainerInit2 is not copied; instead, the + * string takes ownership over the data pointer. The caller must have + * allocated the data array using the XPCOM memory allocator (nsMemory). + * This flag should not be combined with NS_STRING_CONTAINER_INIT_DEPEND. */ + NS_STRING_CONTAINER_INIT_ADOPT = (1 << 2), + + /* Data passed into NS_StringContainerInit2 is a substring that is not + * null-terminated. */ + NS_STRING_CONTAINER_INIT_SUBSTRING = (1 << 3) +}; + /** * NS_StringContainerInit * @@ -142,6 +163,32 @@ class nsStringContainer; NS_STRINGAPI(nsresult) NS_StringContainerInit(nsStringContainer &aContainer); +/** + * NS_StringContainerInit2 + * + * @param aContainer string container reference + * @param aData character buffer (may be null) + * @param aDataLength number of characters stored at aData (may pass + * PR_UINT32_MAX if aData is null-terminated) + * @param aFlags flags affecting how the string container is + * initialized. this parameter is ignored when aData + * is null. otherwise, if this parameter is 0, then + * aData is copied into the string. + * + * This function resembles NS_StringContainerInit but provides further + * options that permit more efficient memory usage. When aContainer is + * no longer needed, NS_StringContainerFinish should be called. + * + * NOTE: NS_StringContainerInit2(container, nsnull, 0, 0) is equivalent to + * NS_StringContainerInit(container). + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_StringContainerInit2 + (nsStringContainer &aContainer, const PRUnichar *aData = nsnull, + PRUint32 aDataLength = PR_UINT32_MAX, PRUint32 aFlags = 0); + /** * NS_StringContainerFinish * @@ -347,12 +394,33 @@ NS_StringCutData(nsAString &aStr, PRUint32 aCutOffset, PRUint32 aCutLength) * implementation detail. * * The string data stored in a string container is always single fragment - * and null-terminated. + * and may be null-terminated depending on how it is initialized. * * @see nsStringContainer for use cases and further documentation. */ class nsCStringContainer; +/** + * Flags that may be OR'd together to pass to NS_StringContainerInit2: + */ +enum { + /* Data passed into NS_CStringContainerInit2 is not copied; instead, the + * string references the passed in data pointer directly. The caller must + * ensure that the data is valid for the lifetime of the string container. + * This flag should not be combined with NS_CSTRING_CONTAINER_INIT_ADOPT. */ + NS_CSTRING_CONTAINER_INIT_DEPEND = (1 << 1), + + /* Data passed into NS_CStringContainerInit2 is not copied; instead, the + * string takes ownership over the data pointer. The caller must have + * allocated the data array using the XPCOM memory allocator (nsMemory). + * This flag should not be combined with NS_CSTRING_CONTAINER_INIT_DEPEND. */ + NS_CSTRING_CONTAINER_INIT_ADOPT = (1 << 2), + + /* Data passed into NS_CStringContainerInit2 is a substring that is not + * null-terminated. */ + NS_CSTRING_CONTAINER_INIT_SUBSTRING = (1 << 3) +}; + /** * NS_CStringContainerInit * @@ -367,6 +435,32 @@ class nsCStringContainer; NS_STRINGAPI(nsresult) NS_CStringContainerInit(nsCStringContainer &aContainer); +/** + * NS_CStringContainerInit2 + * + * @param aContainer string container reference + * @param aData character buffer (may be null) + * @param aDataLength number of characters stored at aData (may pass + * PR_UINT32_MAX if aData is null-terminated) + * @param aFlags flags affecting how the string container is + * initialized. this parameter is ignored when aData + * is null. otherwise, if this parameter is 0, then + * aData is copied into the string. + * + * This function resembles NS_CStringContainerInit but provides further + * options that permit more efficient memory usage. When aContainer is + * no longer needed, NS_CStringContainerFinish should be called. + * + * NOTE: NS_CStringContainerInit2(container, nsnull, 0, 0) is equivalent to + * NS_CStringContainerInit(container). + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringContainerInit2 + (nsCStringContainer &aContainer, const char *aData = nsnull, + PRUint32 aDataLength = PR_UINT32_MAX, PRUint32 aFlags = 0); + /** * NS_CStringContainerFinish * diff --git a/mozilla/xpcom/string/public/nsTSubstring.h b/mozilla/xpcom/string/public/nsTSubstring.h index aaaf5a64e7a..b85951a5b6e 100644 --- a/mozilla/xpcom/string/public/nsTSubstring.h +++ b/mozilla/xpcom/string/public/nsTSubstring.h @@ -405,6 +405,16 @@ class nsTSubstring_CharT : public nsTAString_CharT Assign(tuple); } + /** + * allows for direct initialization of a nsTSubstring object. + * + * NOTE: this constructor is declared public _only_ for convenience + * inside the string implementation. + */ + nsTSubstring_CharT( char_type *data, size_type length, PRUint32 flags ) + : abstract_string_type(data, length, flags) {} + + protected: friend class nsTObsoleteAStringThunk_CharT; @@ -419,10 +429,6 @@ class nsTSubstring_CharT : public nsTAString_CharT : abstract_string_type( NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer), 0, F_TERMINATED) {} - // allow subclasses to initialize fields directly - nsTSubstring_CharT( char_type *data, size_type length, PRUint32 flags ) - : abstract_string_type(data, length, flags) {} - // version of constructor that leaves mData and mLength uninitialized explicit nsTSubstring_CharT( PRUint32 flags ) diff --git a/mozilla/xpcom/stub/nsStringAPI.cpp b/mozilla/xpcom/stub/nsStringAPI.cpp index c8c21f77e45..903774871cf 100644 --- a/mozilla/xpcom/stub/nsStringAPI.cpp +++ b/mozilla/xpcom/stub/nsStringAPI.cpp @@ -55,6 +55,51 @@ NS_StringContainerInit(nsStringContainer &aContainer) return NS_OK; } +NS_STRINGAPI(nsresult) +NS_StringContainerInit2(nsStringContainer &aContainer, + const PRUnichar *aData, + PRUint32 aDataLength, + PRUint32 aFlags) +{ + NS_ASSERTION(sizeof(nsStringContainer) >= sizeof(nsString), + "nsStringContainer is not large enough"); + + if (!aData) + { + new (&aContainer) nsString(); + } + else + { + if (aDataLength == PR_UINT32_MAX) + { + NS_ENSURE_ARG(!(aFlags & NS_STRING_CONTAINER_INIT_SUBSTRING)); + aDataLength = nsCharTraits::length(aData); + } + + if (aFlags & (NS_STRING_CONTAINER_INIT_DEPEND | + NS_STRING_CONTAINER_INIT_ADOPT)) + { + PRUint32 flags; + if (aFlags & NS_STRING_CONTAINER_INIT_SUBSTRING) + flags = nsSubstring::F_NONE; + else + flags = nsSubstring::F_TERMINATED; + + if (aFlags & NS_STRING_CONTAINER_INIT_ADOPT) + flags |= nsSubstring::F_OWNED; + + new (&aContainer) nsSubstring(NS_CONST_CAST(PRUnichar *, aData), + aDataLength, flags); + } + else + { + new (&aContainer) nsString(aData, aDataLength); + } + } + + return NS_OK; +} + NS_STRINGAPI(void) NS_StringContainerFinish(nsStringContainer &aContainer) { @@ -140,6 +185,51 @@ NS_CStringContainerInit(nsCStringContainer &aContainer) return NS_OK; } +NS_STRINGAPI(nsresult) +NS_CStringContainerInit2(nsCStringContainer &aContainer, + const char *aData, + PRUint32 aDataLength, + PRUint32 aFlags) +{ + NS_ASSERTION(sizeof(nsCStringContainer) >= sizeof(nsCString), + "nsStringContainer is not large enough"); + + if (!aData) + { + new (&aContainer) nsCString(); + } + else + { + if (aDataLength == PR_UINT32_MAX) + { + NS_ENSURE_ARG(!(aFlags & NS_CSTRING_CONTAINER_INIT_SUBSTRING)); + aDataLength = nsCharTraits::length(aData); + } + + if (aFlags & (NS_CSTRING_CONTAINER_INIT_DEPEND | + NS_CSTRING_CONTAINER_INIT_ADOPT)) + { + PRUint32 flags; + if (aFlags & NS_CSTRING_CONTAINER_INIT_SUBSTRING) + flags = nsCSubstring::F_NONE; + else + flags = nsCSubstring::F_TERMINATED; + + if (aFlags & NS_CSTRING_CONTAINER_INIT_ADOPT) + flags |= nsCSubstring::F_OWNED; + + new (&aContainer) nsCSubstring(NS_CONST_CAST(char *, aData), + aDataLength, flags); + } + else + { + new (&aContainer) nsCString(aData, aDataLength); + } + } + + return NS_OK; +} + NS_STRINGAPI(void) NS_CStringContainerFinish(nsCStringContainer &aContainer) { diff --git a/mozilla/xpcom/stub/nsXPComStub.cpp b/mozilla/xpcom/stub/nsXPComStub.cpp index f02ef141ba0..4e6057495cd 100644 --- a/mozilla/xpcom/stub/nsXPComStub.cpp +++ b/mozilla/xpcom/stub/nsXPComStub.cpp @@ -77,10 +77,12 @@ static const XPCOMFunctions kFrozenFunctions = { &NS_StringCloneData, &NS_CStringCloneData, - // these functions were added post 1.7 (Firefox 1.0) + // these functions were added post 1.7 (post Firefox 1.0) &NS_Alloc_P, &NS_Realloc_P, - &NS_Free_P + &NS_Free_P, + &NS_StringContainerInit2, + &NS_CStringContainerInit2 }; extern "C" NS_EXPORT nsresult diff --git a/mozilla/xpcom/tests/TestMinStringAPI.cpp b/mozilla/xpcom/tests/TestMinStringAPI.cpp index c9de46af074..2cc445a24e5 100644 --- a/mozilla/xpcom/tests/TestMinStringAPI.cpp +++ b/mozilla/xpcom/tests/TestMinStringAPI.cpp @@ -345,6 +345,90 @@ static PRBool test_compress_ws() return rv; } +static PRBool test_depend() + { + static const char kData[] = "hello world"; + + nsCStringContainer s; + NS_ENSURE_SUCCESS( + NS_CStringContainerInit2(s, kData, sizeof(kData)-1, + NS_CSTRING_CONTAINER_INIT_DEPEND), + PR_FALSE); + + const char *sd; + NS_CStringGetData(s, &sd); + + PRBool rv = (sd == kData); + NS_CStringContainerFinish(s); + return rv; + } + +static PRBool test_depend_sub() + { + static const char kData[] = "hello world"; + + nsCStringContainer s; + NS_ENSURE_SUCCESS( + NS_CStringContainerInit2(s, kData, sizeof(kData)-1, + NS_CSTRING_CONTAINER_INIT_DEPEND | + NS_CSTRING_CONTAINER_INIT_SUBSTRING), + PR_FALSE); + + PRBool terminated; + const char *sd; + PRUint32 len = NS_CStringGetData(s, &sd, &terminated); + + PRBool rv = (sd == kData && len == sizeof(kData)-1 && !terminated); + NS_CStringContainerFinish(s); + return rv; + } + +static PRBool test_adopt() + { + static const char kData[] = "hello world"; + + char *data = (char *) nsMemory::Clone(kData, sizeof(kData)); + if (!data) + return PR_FALSE; + + nsCStringContainer s; + NS_ENSURE_SUCCESS( + NS_CStringContainerInit2(s, data, PR_UINT32_MAX, + NS_CSTRING_CONTAINER_INIT_ADOPT), + PR_FALSE); // leaks data on failure *shrug* + + const char *sd; + NS_CStringGetData(s, &sd); + + PRBool rv = (sd == data); + NS_CStringContainerFinish(s); + return rv; + } + +static PRBool test_adopt_sub() + { + static const char kData[] = "hello world"; + + char *data = (char *) nsMemory::Clone(kData, sizeof(kData)-1); + if (!data) + return PR_FALSE; + + nsCStringContainer s; + NS_ENSURE_SUCCESS( + NS_CStringContainerInit2(s, data, sizeof(kData)-1, + NS_CSTRING_CONTAINER_INIT_ADOPT | + NS_CSTRING_CONTAINER_INIT_SUBSTRING), + PR_FALSE); // leaks data on failure *shrug* + + PRBool terminated; + const char *sd; + PRUint32 len = NS_CStringGetData(s, &sd, &terminated); + + PRBool rv = (sd == data && len == sizeof(kData)-1 && !terminated); + NS_CStringContainerFinish(s); + return rv; + } + //---- typedef PRBool (*TestFunc)(); @@ -362,6 +446,10 @@ tests[] = { "test_append", test_append }, { "test_replace", test_replace }, { "test_compress_ws", test_compress_ws }, + { "test_depend", test_depend }, + { "test_depend_sub", test_depend_sub }, + { "test_adopt", test_adopt }, + { "test_adopt_sub", test_adopt_sub }, { nsnull, nsnull } };