mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 743056 - nsPrintfCString is consistently misused because people don't understand its length-truncation behavior. Make it behave the way people expect by expanding the string as necessary (and use nsTSubstring::AppendPrintf to unify the codepath), r=jlebar
--HG-- extra : rebase_source : 8d638515f4ef5b89f0ecaca5a4cc2974982d7092
This commit is contained in:
parent
a0b742a231
commit
e4e9885e88
@ -56,6 +56,7 @@
|
||||
#endif /* !NS_DISABLE_LITERAL_TEMPLATE */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define kNotFound -1
|
||||
|
||||
|
@ -42,46 +42,44 @@
|
||||
#include "nsString.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* |nsPrintfCString| lets you use a formated |printf| string as an |const nsACString|.
|
||||
*
|
||||
* myCStr += nsPrintfCString("%f", 13.917);
|
||||
* // ...a general purpose substitute for |AppendFloat|
|
||||
*
|
||||
* For longer patterns, you'll want to use the constructor that takes a length
|
||||
*
|
||||
* nsPrintfCString(128, "%f, %f, %f, %f, %f, %f, %f, %i, %f", x, y, z, 3.2, j, k, l, 3, 3.1);
|
||||
*
|
||||
* Exceding the default size (which you must specify in the constructor, it is not determined)
|
||||
* causes an allocation, so avoid that. If your formatted string exceeds the allocated space, it is
|
||||
* cut off at the size of the buffer, no error is reported (and no out-of-bounds writing occurs).
|
||||
* This class is intended to be useful for numbers and short
|
||||
* strings, not arbitrary formatting of other strings (e.g., with %s). There is currently no
|
||||
* wide version of this class, since wide |printf| is not generally available. That means
|
||||
* to get a wide version of your formatted data, you must, e.g.,
|
||||
*
|
||||
* CopyASCIItoUTF16(nsPrintfCString("%f", 13.917"), myStr);
|
||||
*
|
||||
* That's another good reason to avoid this class for anything but numbers ... as strings can be
|
||||
* much more efficiently handled with |NS_LITERAL_[C]STRING| and |nsLiteral[C]String|.
|
||||
*/
|
||||
|
||||
class nsPrintfCString : public nsCString
|
||||
/**
|
||||
* |nsPrintfCString| is syntactic sugar for a printf used as a
|
||||
* |const nsACString| with a small builtin autobuffer. In almost all cases
|
||||
* it is better to just use AppendPrintf. Example usage:
|
||||
*
|
||||
* NS_WARNING(nsPrintfCString("Unexpected value: %f", 13.917).get());
|
||||
*/
|
||||
class nsPrintfCString : public nsFixedCString
|
||||
{
|
||||
typedef nsCString string_type;
|
||||
|
||||
enum { kLocalBufferSize=15 };
|
||||
public:
|
||||
explicit nsPrintfCString( const char_type* format, ... )
|
||||
: nsFixedCString(mLocalBuffer, kLocalBufferSize, 0)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
AppendPrintf(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Obsolete form required you to specify a length in advance. The length is now
|
||||
// unused.
|
||||
nsPrintfCString( size_type n, const char_type* format, ...)
|
||||
: nsFixedCString(mLocalBuffer, kLocalBufferSize, 0)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
AppendPrintf(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
private:
|
||||
enum { kLocalBufferSize=15 };
|
||||
// ought to be large enough for most things ... a |long long| needs at most 20 (so you'd better ask)
|
||||
// pinkerton suggests 7. We should measure and decide what's appropriate
|
||||
|
||||
public:
|
||||
// XXX don't these need to be declared CDECL ??
|
||||
explicit nsPrintfCString( const char_type* format, ... );
|
||||
nsPrintfCString( size_type n, const char_type* format, ...);
|
||||
|
||||
private:
|
||||
char_type mLocalBuffer[ kLocalBufferSize + 1 ];
|
||||
char_type mLocalBuffer[ kLocalBufferSize ];
|
||||
};
|
||||
|
||||
#endif // !defined(nsPrintfCString_h___)
|
||||
|
@ -387,34 +387,38 @@ class nsTSubstring_CharT
|
||||
|
||||
void AppendASCII( const char* data, size_type length = size_type(-1) ) { ReplaceASCII(mLength, 0, data, length); }
|
||||
|
||||
/**
|
||||
* Append a formatted string to the current string. Uses the format
|
||||
* codes documented in prprf.h
|
||||
*/
|
||||
void AppendPrintf( const char* format, ... );
|
||||
void AppendInt( PRInt32 aInteger )
|
||||
{ AppendPrintf31( "%d", aInteger ); }
|
||||
{ AppendPrintf( "%d", aInteger ); }
|
||||
void AppendInt( PRInt32 aInteger, int aRadix )
|
||||
{
|
||||
const char *fmt = aRadix == 10 ? "%d" : aRadix == 8 ? "%o" : "%x";
|
||||
AppendPrintf31( fmt, aInteger );
|
||||
AppendPrintf( fmt, aInteger );
|
||||
}
|
||||
void AppendInt( PRUint32 aInteger )
|
||||
{ AppendPrintf31( "%u", aInteger ); }
|
||||
{ AppendPrintf( "%u", aInteger ); }
|
||||
void AppendInt( PRUint32 aInteger, int aRadix )
|
||||
{
|
||||
const char *fmt = aRadix == 10 ? "%u" : aRadix == 8 ? "%o" : "%x";
|
||||
AppendPrintf31( fmt, aInteger );
|
||||
AppendPrintf( fmt, aInteger );
|
||||
}
|
||||
void AppendInt( PRInt64 aInteger )
|
||||
{ AppendPrintf31( "%lld", aInteger ); }
|
||||
{ AppendPrintf( "%lld", aInteger ); }
|
||||
void AppendInt( PRInt64 aInteger, int aRadix )
|
||||
{
|
||||
const char *fmt = aRadix == 10 ? "%lld" : aRadix == 8 ? "%llo" : "%llx";
|
||||
AppendPrintf31( fmt, aInteger );
|
||||
AppendPrintf( fmt, aInteger );
|
||||
}
|
||||
void AppendInt( PRUint64 aInteger )
|
||||
{ AppendPrintf31( "%llu", aInteger ); }
|
||||
{ AppendPrintf( "%llu", aInteger ); }
|
||||
void AppendInt( PRUint64 aInteger, int aRadix )
|
||||
{
|
||||
const char *fmt = aRadix == 10 ? "%llu" : aRadix == 8 ? "%llo" : "%llx";
|
||||
AppendPrintf31( fmt, aInteger );
|
||||
AppendPrintf( fmt, aInteger );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -426,8 +430,6 @@ class nsTSubstring_CharT
|
||||
{ DoAppendFloat(aFloat, 15); }
|
||||
private:
|
||||
void NS_FASTCALL DoAppendFloat( double aFloat, int digits );
|
||||
// AppendPrintf31 truncates output to 31 ASCII characters
|
||||
void AppendPrintf31( const char* format, ... );
|
||||
public:
|
||||
|
||||
// AppendLiteral must ONLY be applied to an actual literal string.
|
||||
@ -740,6 +742,9 @@ class nsTSubstring_CharT
|
||||
mFlags = dataFlags | (mFlags & 0xFFFF0000);
|
||||
}
|
||||
|
||||
static PRIntn AppendFunc( void* arg, const char* s, PRUint32 len);
|
||||
void AppendPrintf( const char* format, va_list ap );
|
||||
|
||||
public:
|
||||
|
||||
// mFlags is a bitwise combination of the following flags. the meaning
|
||||
|
@ -53,7 +53,6 @@ MOZILLA_INTERNAL_API = 1
|
||||
CPPSRCS = \
|
||||
nsDependentString.cpp \
|
||||
nsDependentSubstring.cpp \
|
||||
nsPrintfCString.cpp \
|
||||
nsPromiseFlatString.cpp \
|
||||
nsReadableUtils.cpp \
|
||||
nsSubstring.cpp \
|
||||
|
@ -1,82 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsPrintfCString.h"
|
||||
#include <stdarg.h>
|
||||
#include "prprf.h"
|
||||
|
||||
|
||||
// though these classes define a fixed buffer, they do not set the F_FIXED
|
||||
// flag. this is because they are not intended to be modified after they have
|
||||
// been constructed. we could change this but it would require adding a new
|
||||
// class to the hierarchy, one that both this class and nsCAutoString would
|
||||
// inherit from. for now, we populate the fixed buffer, and then let the
|
||||
// nsCString code treat the buffer as if it were a dependent buffer.
|
||||
|
||||
nsPrintfCString::nsPrintfCString( const char_type* format, ... )
|
||||
: string_type(mLocalBuffer, 0, F_TERMINATED)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
size_type logical_capacity = kLocalBufferSize;
|
||||
size_type physical_capacity = logical_capacity + 1;
|
||||
|
||||
va_start(ap, format);
|
||||
mLength = PR_vsnprintf(mData, physical_capacity, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
nsPrintfCString::nsPrintfCString( size_type n, const char_type* format, ... )
|
||||
: string_type(mLocalBuffer, 0, F_TERMINATED)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
// make sure there's at least |n| space
|
||||
size_type logical_capacity = kLocalBufferSize;
|
||||
if ( n > logical_capacity )
|
||||
{
|
||||
if (!SetCapacity(n))
|
||||
return; // out of memory !!
|
||||
logical_capacity = n;
|
||||
}
|
||||
size_type physical_capacity = logical_capacity + 1;
|
||||
|
||||
va_start(ap, format);
|
||||
mLength = PR_vsnprintf(mData, physical_capacity, format, ap);
|
||||
va_end(ap);
|
||||
}
|
@ -731,27 +731,37 @@ nsTSubstring_CharT::StripChars( const char_type* aChars, PRUint32 aOffset )
|
||||
mLength = to - mData;
|
||||
}
|
||||
|
||||
void nsTSubstring_CharT::AppendPrintf31( const char* format, ...)
|
||||
PRIntn
|
||||
nsTSubstring_CharT::AppendFunc(void* arg, const char* s, PRUint32 len)
|
||||
{
|
||||
char buf[32];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
PRUint32 len = PR_vsnprintf(buf, sizeof(buf), format, ap);
|
||||
AppendASCII(buf, len);
|
||||
va_end(ap);
|
||||
self_type* self = static_cast<self_type*>(arg);
|
||||
|
||||
// NSPR sends us the final null terminator even though we don't want it
|
||||
if (len && s[len - 1] == '\0') {
|
||||
--len;
|
||||
}
|
||||
|
||||
self->AppendASCII(s, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void nsTSubstring_CharT::AppendPrintf( const char* format, ...)
|
||||
{
|
||||
char *buf;
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
buf = PR_vsmprintf(format, ap);
|
||||
AppendASCII(buf);
|
||||
PR_smprintf_free(buf);
|
||||
PRUint32 r = PR_vsxprintf(AppendFunc, this, format, ap);
|
||||
if (r == (PRUint32) -1)
|
||||
NS_RUNTIMEABORT("Allocation or other failure in PR_vsxprintf");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void nsTSubstring_CharT::AppendPrintf( const char* format, va_list ap )
|
||||
{
|
||||
PRUint32 r = PR_vsxprintf(AppendFunc, this, format, ap);
|
||||
if (r == (PRUint32) -1)
|
||||
NS_RUNTIMEABORT("Allocation or other failure in PR_vsxprintf");
|
||||
}
|
||||
|
||||
/* hack to make sure we define Modified_cnvtf only once */
|
||||
#ifdef CharT_is_PRUnichar
|
||||
|
Loading…
Reference in New Issue
Block a user