landing 172512. nsEmbedString for component developers and embeders. r=alec, sr=jag/darin, a=asa@mozilla.org

This commit is contained in:
dougt%netscape.com 2002-10-17 23:41:47 +00:00
Родитель ac0efa78fc
Коммит a167020474
16 изменённых файлов: 557 добавлений и 1033 удалений

Просмотреть файл

@ -30,13 +30,17 @@ include $(DEPTH)/config/autoconf.mk
MODULE = string
SDK_HEADERS = \
nsAString.h \
nsBufferHandle.h \
nsStringFragment.h \
$(NULL)
EXPORTS = \
nsAFlatString.h \
nsAlgorithm.h \
nsASingleFragmentString.h \
nsAString.h \
nsAStringGenerator.h \
nsBufferHandle.h \
nsBufferHandleUtils.h \
nsCharTraits.h \
nsDependentConcatenation.h \
@ -51,7 +55,6 @@ EXPORTS = \
nsSharedBufferList.h \
nsSlidingString.h \
nsStringDefines.h \
nsStringFragment.h \
nsStringFwd.h \
nsStringIterator.h \
nsStringIteratorUtils.h \

Просмотреть файл

@ -1,997 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* 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.
*
* The Initial Developer of the Original Code is Netscape
* Communications. Portions created by Netscape Communications are
* Copyright (C) 2001 by Netscape Communications. All
* Rights Reserved.
*
* Contributor(s):
* Scott Collins <scc@mozilla.org> (original author)
*/
#include "nsAString.h"
#include "nsDependentSubstring.h"
#include "nsDependentString.h"
#include "nsCRT.h"
int
nsDefaultStringComparator::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const
{
return nsCharTraits<char_type>::compare(lhs, rhs, aLength);
}
int
nsDefaultStringComparator::operator()( char_type lhs, char_type rhs) const
{
return lhs - rhs;
}
NS_COM
int
Compare( const nsAString& lhs, const nsAString& rhs, const nsStringComparator& aComparator )
{
typedef nsAString::size_type size_type;
if ( &lhs == &rhs )
return 0;
size_type lLength = lhs.Length();
size_type rLength = rhs.Length();
size_type lengthToCompare = NS_MIN(lLength, rLength);
nsAString::const_iterator leftIter, rightIter;
lhs.BeginReading(leftIter);
rhs.BeginReading(rightIter);
for (;;)
{
size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) );
if ( lengthAvailable > lengthToCompare )
lengthAvailable = lengthToCompare;
{
int result;
// Note: |result| should be declared in this |if| expression, but some compilers don't like that
if ( (result = aComparator(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 )
return result;
}
if ( !(lengthToCompare -= lengthAvailable) )
break;
leftIter.advance( PRInt32(lengthAvailable) );
rightIter.advance( PRInt32(lengthAvailable) );
}
if ( lLength < rLength )
return -1;
else if ( rLength < lLength )
return 1;
else
return 0;
}
const nsAString::shared_buffer_handle_type*
nsAString::GetSharedBufferHandle() const
{
return 0;
}
const nsAString::buffer_handle_type*
nsAString::GetFlatBufferHandle() const
{
return GetSharedBufferHandle();
}
const nsAString::buffer_handle_type*
nsAString::GetBufferHandle() const
{
return GetSharedBufferHandle();
}
PRUint32
nsAString::GetImplementationFlags() const
{
return 0;
}
PRBool
nsAString::IsVoid() const
{
return PR_FALSE;
}
void
nsAString::SetIsVoid( PRBool )
{
// |SetIsVoid| is ignored by default
}
PRBool
nsAString::Equals( const char_type* rhs, const nsStringComparator& aComparator ) const
{
return Equals(nsDependentString(rhs), aComparator);
}
nsAString::char_type
nsAString::First() const
{
NS_ASSERTION(Length()>0, "|First()| on an empty string");
const_iterator iter;
return *BeginReading(iter);
}
nsAString::char_type
nsAString::Last() const
{
NS_ASSERTION(Length()>0, "|Last()| on an empty string");
const_iterator iter;
if ( !IsEmpty() )
{
EndReading(iter);
iter.advance(-1);
}
return *iter; // Note: this has undefined results if |IsEmpty()|
}
nsAString::size_type
nsAString::CountChar( char_type c ) const
{
/*
re-write this to use a counting sink
*/
size_type result = 0;
size_type lengthToExamine = Length();
const_iterator iter;
for ( BeginReading(iter); ; )
{
PRInt32 lengthToExamineInThisFragment = iter.size_forward();
const char_type* fromBegin = iter.get();
result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c));
if ( !(lengthToExamine -= lengthToExamineInThisFragment) )
return result;
iter.advance(lengthToExamineInThisFragment);
}
// never reached; quiets warnings
return 0;
}
PRInt32
nsAString::FindChar( char_type aChar, PRUint32 aOffset ) const
{
const_iterator iter, done_searching;
BeginReading(iter).advance( PRInt32(aOffset) );
EndReading(done_searching);
size_type lengthSearched = 0;
while ( iter != done_searching )
{
PRInt32 fragmentLength = iter.size_forward();
const char_type* charFoundAt = nsCharTraits<char_type>::find(iter.get(), fragmentLength, aChar);
if ( charFoundAt )
return lengthSearched + (charFoundAt-iter.get()) + aOffset;
lengthSearched += fragmentLength;
iter.advance(fragmentLength);
}
return -1;
}
PRBool
nsAString::IsDependentOn( const self_type& aString ) const
{
const_fragment_type f1;
const char_type* s1 = GetReadableFragment(f1, kFirstFragment);
while ( s1 )
{
const_fragment_type f2;
const char_type* s2 = aString.GetReadableFragment(f2, kFirstFragment);
while ( s2 )
{
// if it _isn't_ the case that
// one fragment starts after the other ends,
// or ends before the other starts,
// then, they conflict:
// !(f2.mStart>=f1.mEnd || f2.mEnd<=f1.mStart)
//
// Simplified, that gives us:
if ( f2.mStart < f1.mEnd && f2.mEnd > f1.mStart )
return PR_TRUE;
s2 = aString.GetReadableFragment(f2, kNextFragment);
}
s1 = GetReadableFragment(f1, kNextFragment);
}
return PR_FALSE;
}
//
// |Assign()|
//
void
nsAString::do_AssignFromReadable( const self_type& aReadable )
/*
...we need to check whether the string that's being assigned into |this| somehow references |this|.
E.g.,
... writable& w ...
... readable& r ...
w = r + w;
In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before
anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents
of |r| before being retrieved to be appended.
We could have a really tricky solution where we tell the promise to resolve _just_ the data promised
by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g.,
in the case above, |Insert| could have special behavior with significantly better performance. Since
it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the
entire promise. If we measure and this turns out to show up on performance radar, we then have the
option to fix either the callers or this mechanism.
*/
{
// self-assign is a no-op
if ( this == &aReadable)
return;
if ( !aReadable.IsDependentOn(*this) )
UncheckedAssignFromReadable(aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
// Note: not exception safe. We need something to manage temporary buffers like this
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
UncheckedAssignFromReadable(Substring(buffer, buffer + length));
delete[] buffer;
}
// else assert?
}
}
void
nsAString::UncheckedAssignFromReadable( const self_type& aReadable )
{
SetLength(0);
if ( !aReadable.IsEmpty() )
{
SetLength(aReadable.Length());
// first setting the length to |0| avoids copying characters only to be overwritten later
// in the case where the implementation decides to re-allocate
const_iterator fromBegin, fromEnd;
iterator toBegin;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin));
}
}
void
nsAString::do_AssignFromElementPtr( const char_type* aPtr )
{
do_AssignFromReadable(nsDependentString(aPtr));
}
void
nsAString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength )
{
do_AssignFromReadable(Substring(aPtr, aPtr+aLength));
}
void
nsAString::do_AssignFromElement( char_type aChar )
{
UncheckedAssignFromReadable(Substring(&aChar, &aChar+1));
}
//
// |Append()|
//
void
nsAString::do_AppendFromReadable( const self_type& aReadable )
{
if ( !aReadable.IsDependentOn(*this) )
UncheckedAppendFromReadable(aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
UncheckedAppendFromReadable(Substring(buffer, buffer + length));
delete[] buffer;
}
// else assert?
}
}
void
nsAString::UncheckedAppendFromReadable( const self_type& aReadable)
{
size_type oldLength = this->Length();
SetLength(oldLength + aReadable.Length());
const_iterator fromBegin, fromEnd;
iterator toBegin;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) );
}
void
nsAString::do_AppendFromElementPtr( const char_type* aPtr )
{
do_AppendFromReadable(nsDependentString(aPtr));
}
void
nsAString::do_AppendFromElementPtrLength( const char_type* aPtr, size_type aLength )
{
do_AppendFromReadable(Substring(aPtr, aPtr+aLength));
}
void
nsAString::do_AppendFromElement( char_type aChar )
{
UncheckedAppendFromReadable(Substring(&aChar, &aChar + 1));
}
//
// |Insert()|
//
void
nsAString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition )
{
if ( !aReadable.IsDependentOn(*this) )
UncheckedInsertFromReadable(aReadable, atPosition);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
UncheckedInsertFromReadable(Substring(buffer, buffer + length), atPosition);
delete[] buffer;
}
// else assert
}
}
void
nsAString::UncheckedInsertFromReadable( const self_type& aReadable, index_type atPosition )
{
size_type oldLength = this->Length();
SetLength(oldLength + aReadable.Length());
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( atPosition < oldLength )
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
else
atPosition = oldLength;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition)));
}
void
nsAString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition )
{
do_InsertFromReadable(nsDependentString(aPtr), atPosition);
}
void
nsAString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength )
{
do_InsertFromReadable(Substring(aPtr, aPtr+aLength), atPosition);
}
void
nsAString::do_InsertFromElement( char_type aChar, index_type atPosition )
{
UncheckedInsertFromReadable(Substring(&aChar, &aChar+1), atPosition);
}
//
// |Cut()|
//
void
nsAString::Cut( index_type cutStart, size_type cutLength )
{
size_type myLength = this->Length();
cutLength = NS_MIN(cutLength, myLength-cutStart);
index_type cutEnd = cutStart + cutLength;
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( cutEnd < myLength )
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
SetLength(myLength-cutLength);
}
//
// |Replace()|
//
void
nsAString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReadable )
{
if ( !aReadable.IsDependentOn(*this) )
UncheckedReplaceFromReadable(cutStart, cutLength, aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
UncheckedReplaceFromReadable(cutStart, cutLength, Substring(buffer, buffer + length));
delete[] buffer;
}
// else assert?
}
}
void
nsAString::UncheckedReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
{
size_type oldLength = this->Length();
cutStart = NS_MIN(cutStart, oldLength);
cutLength = NS_MIN(cutLength, oldLength-cutStart);
index_type cutEnd = cutStart + cutLength;
size_type replacementLength = aReplacement.Length();
index_type replacementEnd = cutStart + replacementLength;
size_type newLength = oldLength - cutLength + replacementLength;
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( cutLength > replacementLength )
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd)));
SetLength(newLength);
if ( cutLength < replacementLength )
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
}
int
nsDefaultCStringComparator::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const
{
return nsCharTraits<char_type>::compare(lhs, rhs, aLength);
}
PRBool
nsDefaultCStringComparator::operator()( char_type lhs, char_type rhs ) const
{
return lhs - rhs;
}
int
nsCaseInsensitiveCStringComparator::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const
{
return nsCRT::strncasecmp(lhs, rhs, aLength);
}
PRBool
nsCaseInsensitiveCStringComparator::operator()( char lhs, char rhs ) const
{
if (lhs == rhs) return 0;
lhs = tolower(lhs);
rhs = tolower(rhs);
return lhs - rhs;
}
NS_COM
int
Compare( const nsACString& lhs, const nsACString& rhs, const nsCStringComparator& aComparator )
{
typedef nsACString::size_type size_type;
if ( &lhs == &rhs )
return 0;
size_type lLength = lhs.Length();
size_type rLength = rhs.Length();
size_type lengthToCompare = NS_MIN(lLength, rLength);
nsACString::const_iterator leftIter, rightIter;
lhs.BeginReading(leftIter);
rhs.BeginReading(rightIter);
for (;;)
{
size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) );
if ( lengthAvailable > lengthToCompare )
lengthAvailable = lengthToCompare;
{
int result;
// Note: |result| should be declared in this |if| expression, but some compilers don't like that
if ( (result = aComparator(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 )
return result;
}
if ( !(lengthToCompare -= lengthAvailable) )
break;
leftIter.advance( PRInt32(lengthAvailable) );
rightIter.advance( PRInt32(lengthAvailable) );
}
if ( lLength < rLength )
return -1;
else if ( rLength < lLength )
return 1;
else
return 0;
}
const nsACString::shared_buffer_handle_type*
nsACString::GetSharedBufferHandle() const
{
return 0;
}
const nsACString::buffer_handle_type*
nsACString::GetFlatBufferHandle() const
{
return GetSharedBufferHandle();
}
const nsACString::buffer_handle_type*
nsACString::GetBufferHandle() const
{
return GetSharedBufferHandle();
}
PRUint32
nsACString::GetImplementationFlags() const
{
return 0;
}
PRBool
nsACString::IsVoid() const
{
return PR_FALSE;
}
void
nsACString::SetIsVoid( PRBool )
{
// |SetIsVoid| is ignored by default
}
PRBool
nsACString::Equals( const char_type* rhs, const nsCStringComparator& aComparator ) const
{
return Equals(nsDependentCString(rhs), aComparator);
}
nsACString::char_type
nsACString::First() const
{
NS_ASSERTION(Length()>0, "|First()| on an empty string");
const_iterator iter;
return *BeginReading(iter);
}
nsACString::char_type
nsACString::Last() const
{
NS_ASSERTION(Length()>0, "|Last()| on an empty string");
const_iterator iter;
if ( !IsEmpty() )
{
EndReading(iter);
iter.advance(-1);
}
return *iter; // Note: this has undefined results if |IsEmpty()|
}
nsACString::size_type
nsACString::CountChar( char_type c ) const
{
/*
re-write this to use a counting sink
*/
size_type result = 0;
size_type lengthToExamine = Length();
const_iterator iter;
for ( BeginReading(iter); ; )
{
PRInt32 lengthToExamineInThisFragment = iter.size_forward();
const char_type* fromBegin = iter.get();
result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c));
if ( !(lengthToExamine -= lengthToExamineInThisFragment) )
return result;
iter.advance(lengthToExamineInThisFragment);
}
// never reached; quiets warnings
return 0;
}
PRInt32
nsACString::FindChar( char_type aChar, PRUint32 aOffset ) const
{
const_iterator iter, done_searching;
BeginReading(iter).advance( PRInt32(aOffset) );
EndReading(done_searching);
size_type lengthSearched = 0;
while ( iter != done_searching )
{
PRInt32 fragmentLength = iter.size_forward();
const char_type* charFoundAt = nsCharTraits<char_type>::find(iter.get(), fragmentLength, aChar);
if ( charFoundAt )
return lengthSearched + (charFoundAt-iter.get()) + aOffset;
lengthSearched += fragmentLength;
iter.advance(fragmentLength);
}
return -1;
}
PRBool
nsACString::IsDependentOn( const self_type& aString ) const
{
const_fragment_type f1;
const char_type* s1 = GetReadableFragment(f1, kFirstFragment);
while ( s1 )
{
const_fragment_type f2;
const char_type* s2 = aString.GetReadableFragment(f2, kFirstFragment);
while ( s2 )
{
// if it _isn't_ the case that
// one fragment starts after the other ends,
// or ends before the other starts,
// then, they conflict:
// !(f2.mStart>=f1.mEnd || f2.mEnd<=f1.mStart)
//
// Simplified, that gives us:
if ( f2.mStart < f1.mEnd && f2.mEnd > f1.mStart )
return PR_TRUE;
s2 = aString.GetReadableFragment(f2, kNextFragment);
}
s1 = GetReadableFragment(f1, kNextFragment);
}
return PR_FALSE;
}
//
// |Assign()|
//
void
nsACString::do_AssignFromReadable( const self_type& aReadable )
/*
...we need to check whether the string that's being assigned into |this| somehow references |this|.
E.g.,
... writable& w ...
... readable& r ...
w = r + w;
In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before
anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents
of |r| before being retrieved to be appended.
We could have a really tricky solution where we tell the promise to resolve _just_ the data promised
by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g.,
in the case above, |Insert| could have special behavior with significantly better performance. Since
it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the
entire promise. If we measure and this turns out to show up on performance radar, we then have the
option to fix either the callers or this mechanism.
*/
{
// self-assign is a no-op
if (this == &aReadable)
return;
if ( !aReadable.IsDependentOn(*this) )
UncheckedAssignFromReadable(aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
// Note: not exception safe. We need something to manage temporary buffers like this
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
UncheckedAssignFromReadable(Substring(buffer, buffer + length));
delete[] buffer;
}
// else assert?
}
}
void
nsACString::UncheckedAssignFromReadable( const self_type& aReadable )
{
SetLength(0);
if ( !aReadable.IsEmpty() )
{
SetLength(aReadable.Length());
// first setting the length to |0| avoids copying characters only to be overwritten later
// in the case where the implementation decides to re-allocate
const_iterator fromBegin, fromEnd;
iterator toBegin;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin));
}
}
void
nsACString::do_AssignFromElementPtr( const char_type* aPtr )
{
do_AssignFromReadable(nsDependentCString(aPtr));
}
void
nsACString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength )
{
do_AssignFromReadable(Substring(aPtr, aPtr+aLength));
}
void
nsACString::do_AssignFromElement( char_type aChar )
{
UncheckedAssignFromReadable(Substring(&aChar, &aChar+1));
}
//
// |Append()|
//
void
nsACString::do_AppendFromReadable( const self_type& aReadable )
{
if ( !aReadable.IsDependentOn(*this) )
UncheckedAppendFromReadable(aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
UncheckedAppendFromReadable(Substring(buffer, buffer + length));
delete[] buffer;
}
// else assert?
}
}
void
nsACString::UncheckedAppendFromReadable( const self_type& aReadable )
{
size_type oldLength = this->Length();
SetLength(oldLength + aReadable.Length());
const_iterator fromBegin, fromEnd;
iterator toBegin;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) );
}
void
nsACString::do_AppendFromElementPtr( const char_type* aPtr )
{
do_AppendFromReadable(nsDependentCString(aPtr));
}
void
nsACString::do_AppendFromElementPtrLength( const char_type* aPtr, size_type aLength )
{
do_AppendFromReadable(Substring(aPtr, aPtr+aLength));
}
void
nsACString::do_AppendFromElement( char_type aChar )
{
UncheckedAppendFromReadable(Substring(&aChar, &aChar + 1));
}
//
// |Insert()|
//
void
nsACString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition )
{
if ( !aReadable.IsDependentOn(*this) )
UncheckedInsertFromReadable(aReadable, atPosition);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
UncheckedInsertFromReadable(Substring(buffer, buffer + length), atPosition);
delete[] buffer;
}
// else assert
}
}
void
nsACString::UncheckedInsertFromReadable( const self_type& aReadable, index_type atPosition )
{
size_type oldLength = this->Length();
SetLength(oldLength + aReadable.Length());
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( atPosition < oldLength )
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
else
atPosition = oldLength;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition)));
}
void
nsACString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition )
{
do_InsertFromReadable(nsDependentCString(aPtr), atPosition);
}
void
nsACString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength )
{
do_InsertFromReadable(Substring(aPtr, aPtr+aLength), atPosition);
}
void
nsACString::do_InsertFromElement( char_type aChar, index_type atPosition )
{
UncheckedInsertFromReadable(Substring(&aChar, &aChar+1), atPosition);
}
//
// |Cut()|
//
void
nsACString::Cut( index_type cutStart, size_type cutLength )
{
size_type myLength = this->Length();
cutLength = NS_MIN(cutLength, myLength-cutStart);
index_type cutEnd = cutStart + cutLength;
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( cutEnd < myLength )
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
SetLength(myLength-cutLength);
}
//
// |Replace()|
//
void
nsACString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReadable )
{
if ( !aReadable.IsDependentOn(*this) )
UncheckedReplaceFromReadable(cutStart, cutLength, aReadable);
else
{
size_type length = aReadable.Length();
char_type* buffer = new char_type[length];
if ( buffer )
{
const_iterator fromBegin, fromEnd;
char_type* toBegin = buffer;
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
UncheckedReplaceFromReadable(cutStart, cutLength, Substring(buffer, buffer + length));
delete[] buffer;
}
// else assert?
}
}
void
nsACString::UncheckedReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
{
size_type oldLength = this->Length();
cutStart = NS_MIN(cutStart, oldLength);
cutLength = NS_MIN(cutLength, oldLength-cutStart);
index_type cutEnd = cutStart + cutLength;
size_type replacementLength = aReplacement.Length();
index_type replacementEnd = cutStart + replacementLength;
size_type newLength = oldLength - cutLength + replacementLength;
const_iterator fromBegin, fromEnd;
iterator toBegin;
if ( cutLength > replacementLength )
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd)));
SetLength(newLength);
if ( cutLength < replacementLength )
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
}

Просмотреть файл

@ -49,6 +49,18 @@
*/
#define NS_DIRECTORY_SERVICE_CONTRACTID "@mozilla.org/file/directory_service;1"
/**
* XPCOM File
* The file abstraction provides ways to obtain and access files and
* directories located on the local system.
*
* This contract supports the nsIFile interface and the nsILocalFile interface.
* This contract may also support platform specific interfaces such as
* nsILocalFileMac on platforms where additional interfaces are required.
*
*/
#define NS_LOCAL_FILE_CONTRACTID "@mozilla.org/file/local;1"
/**
* XPCOM Category Manager Contract ID
* The contract supports the nsICategoryManager interface. The

Просмотреть файл

@ -351,7 +351,7 @@ static const nsModuleComponentInfo components[] = {
COMPONENT_SUPPORTS(INTERFACE_POINTER, InterfacePointer),
#undef COMPONENT_SUPPORTS
#define NS_LOCAL_FILE_CLASSNAME "Local File Specification"
COMPONENT(LOCAL_FILE, nsLocalFile::nsLocalFileConstructor),
#define NS_DIRECTORY_SERVICE_CLASSNAME "nsIFile Directory Service"
COMPONENT(DIRECTORY_SERVICE, nsDirectoryService::Create),

Просмотреть файл

@ -51,6 +51,7 @@
#include "nsIFile.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryService.h"
#include "nsEmbedString.h"
#endif
nsGenericFactory::nsGenericFactory(const nsModuleComponentInfo *info)
@ -297,7 +298,7 @@ nsGenericModule::Initialize(nsIComponentManager *compMgr)
if (NS_FAILED(rv))
return rv;
nsCAutoString path;
nsEmbedCString path;
xpcomDll->GetNativePath(path);
rv = XPCOMGlueStartup(path.get());

Просмотреть файл

@ -48,21 +48,34 @@ LIBRARY_NAME = xpcomglue
REQUIRES = string \
$(NULL)
LOCAL_INCLUDES = \
-I$(srcdir)/../../build \
$(NULL)
STRING_LCSRCS = \
nsAString.cpp \
nsDependentSubstring.cpp \
nsASingleFragmentString.cpp \
$(NULL)
STRING_CSRCS := $(addprefix $(topsrcdir)/string/src/, $(STRING_LCSRCS))
CPPSRCS = \
$(XPCOM_GLUE_SRC_LCSRCS) \
nsXPCOMGlue.cpp \
$(XPCOM_GLUE_SRC_LCSRCS) \
$(STRING_LCSRCS) \
nsXPCOMGlue.cpp \
nsEmbedString.cpp \
$(NULL)
EXPORTS = \
nsXPCOMGlue.h \
$(NULL)
SDK_BINARY = \
SDK_HEADERS = \
nsEmbedString.h \
$(NULL)
SDK_BINARY = \
$(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \
$(NULL)
@ -73,9 +86,11 @@ FORCE_STATIC_LIB = 1
FORCE_USE_PIC = 1
GARBAGE += $(XPCOM_GLUE_SRC_LCSRCS) $(wildcard *.$(OBJ_SUFFIX))
GARBAGE += $(STRING_LCSRCS) $(wildcard *.$(OBJ_SUFFIX))
ifeq ($(OS_ARCH),WINNT)
GARBAGE += $(addprefix $(srcdir)/,$(XPCOM_GLUE_SRC_LCSRCS))
GARBAGE += $(addprefix $(srcdir)/,$(STRING_LCSRCS))
endif
include $(topsrcdir)/config/rules.mk
@ -87,6 +102,13 @@ else
$(INSTALL) $^ .
endif
export:: $(STRING_CSRCS)
ifeq ($(OS_ARCH),WINNT)
$(INSTALL) $^ $(srcdir)
else
$(INSTALL) $^ .
endif
DEFINES += -DXPCOM_GLUE

Просмотреть файл

@ -0,0 +1,456 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 a small implementation of the nsAString and nsACString.
*
* The Initial Developer of the Original Code is
* Peter Annema <jaggernaut@netscape.com>.
*
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either 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 "nsEmbedString.h"
#include "nsMemory.h"
const PRUnichar gCommonEmptyBuffer[1] = { 0 };
nsEmbedString::nsEmbedString()
{
Init();
}
nsEmbedString::nsEmbedString(const char_type* aString)
{
Init();
Assign(aString);
}
nsEmbedString::nsEmbedString(const char_type* aString, size_type aLength)
{
Init();
Assign(aString, aLength);
}
nsEmbedString::nsEmbedString(const nsEmbedString& aString)
{
Init();
Assign(aString);
}
nsEmbedString::nsEmbedString(const abstract_string_type& aReadable)
{
Init();
Assign(aReadable);
}
nsEmbedString::~nsEmbedString()
{
Destroy();
}
void
nsEmbedString::Init()
{
mStr = (char_type*)gCommonEmptyBuffer;
mLength = 0;
mCapacity = 0;
}
void
nsEmbedString::Destroy()
{
Free();
}
void
nsEmbedString::Free()
{
if (OwnsBuffer())
nsMemory::Free(mStr);
}
PRBool
nsEmbedString::Realloc(size_type aNewSize)
{
PRBool result = PR_TRUE;
if (OwnsBuffer())
{
char_type* temp = (char_type*)nsMemory::Realloc(mStr, (aNewSize + 1) * sizeof(char_type));
if (temp)
{
mStr = temp;
mCapacity = aNewSize;
}
else
result = PR_FALSE;
}
else
{
char_type* temp = (char_type*)nsMemory::Alloc((aNewSize + 1) * sizeof(char_type));
if (temp)
{
memcpy(temp, mStr, mLength * sizeof(char_type));
mStr = temp;
mCapacity = aNewSize;
}
else
result = PR_FALSE;
}
return result;
}
PRBool
nsEmbedString::OwnsBuffer() const
{
return mStr != (char_type*)gCommonEmptyBuffer;
}
const nsEmbedString::char_type*
nsEmbedString::GetReadableFragment(const_fragment_type& aFragment, nsFragmentRequest aRequest, index_type aOffset) const
{
switch (aRequest) {
case kFirstFragment:
case kLastFragment:
case kFragmentAt:
aFragment.mEnd = (aFragment.mStart = mStr) + mLength;
return aFragment.mStart + aOffset;
case kPrevFragment:
case kNextFragment:
default:
return 0;
}
}
nsEmbedString::char_type*
nsEmbedString::GetWritableFragment(fragment_type& aFragment, nsFragmentRequest aRequest, index_type aOffset)
{
switch (aRequest) {
case kFirstFragment:
case kLastFragment:
case kFragmentAt:
aFragment.mEnd = (aFragment.mStart = mStr) + mLength;
return aFragment.mStart + aOffset;
case kPrevFragment:
case kNextFragment:
default:
return 0;
}
}
const nsEmbedString::buffer_handle_type*
nsEmbedString::GetFlatBufferHandle() const
{
return NS_REINTERPRET_CAST(const buffer_handle_type*, 1);
}
void
nsEmbedString::SetLength(size_type aLength)
{
if (aLength > mCapacity)
GrowCapacity(aLength);
mLength = aLength;
if (mStr != (char_type*)gCommonEmptyBuffer)
AddNullTerminator();
}
void
nsEmbedString::SetCapacity(size_type aNewCapacity)
{
if (aNewCapacity)
{
if (aNewCapacity > mCapacity)
GrowCapacity(aNewCapacity);
// AddNullTerminator(); // doesn't make sense
}
else
{
Destroy();
Init();
}
}
PRBool
nsEmbedString::EnsureCapacity(size_type aNewCapacity)
{
PRBool result = PR_TRUE;
if (aNewCapacity > mCapacity)
{
result = Realloc(aNewCapacity);
if (result)
AddNullTerminator();
}
return result;
}
PRBool
nsEmbedString::GrowCapacity(size_type aNewCapacity)
{
PRBool result = PR_TRUE;
if (mCapacity)
{
size_type newCapacity = mCapacity;
while (newCapacity < aNewCapacity)
newCapacity <<= 1;
aNewCapacity = newCapacity;
}
nsEmbedString temp;
result = temp.EnsureCapacity(aNewCapacity);
if (result)
{
if (mLength)
temp.Assign(*this);
Free();
mStr = temp.mStr;
temp.mStr = 0;
mLength = temp.mLength;
mCapacity = temp.mCapacity;
}
return result;
}
nsEmbedCString::nsEmbedCString()
{
Init();
}
nsEmbedCString::nsEmbedCString(const char_type* aString)
{
Init();
Assign(aString);
}
nsEmbedCString::nsEmbedCString(const char_type* aString, size_type aLength)
{
Init();
Assign(aString, aLength);
}
nsEmbedCString::nsEmbedCString(const nsEmbedCString& aString)
{
Init();
Assign(aString);
}
nsEmbedCString::nsEmbedCString(const abstract_string_type& aReadable)
{
Init();
Assign(aReadable);
}
nsEmbedCString::~nsEmbedCString()
{
Destroy();
}
void
nsEmbedCString::Init()
{
mStr = (char_type*)gCommonEmptyBuffer;
mLength = 0;
mCapacity = 0;
}
void
nsEmbedCString::Destroy()
{
Free();
}
void
nsEmbedCString::Free()
{
if (OwnsBuffer())
nsMemory::Free(mStr);
}
PRBool
nsEmbedCString::Realloc(size_type aNewSize)
{
PRBool result = PR_TRUE;
if (OwnsBuffer())
{
char_type* temp = (char_type*)nsMemory::Realloc(mStr, (aNewSize + 1) * sizeof(char_type));
if (temp)
{
mStr = temp;
mCapacity = aNewSize;
}
else
result = PR_FALSE;
}
else
{
char_type* temp = (char_type*)nsMemory::Alloc((aNewSize + 1) * sizeof(char_type));
if (temp)
{
memcpy(temp, mStr, mLength * sizeof(char_type));
mStr = temp;
mCapacity = aNewSize;
}
else
result = PR_FALSE;
}
return result;
}
PRBool
nsEmbedCString::OwnsBuffer() const
{
return mStr != (char_type*)gCommonEmptyBuffer;
}
const nsEmbedCString::char_type*
nsEmbedCString::GetReadableFragment(const_fragment_type& aFragment, nsFragmentRequest aRequest, index_type aOffset) const
{
switch (aRequest) {
case kFirstFragment:
case kLastFragment:
case kFragmentAt:
aFragment.mEnd = (aFragment.mStart = mStr) + mLength;
return aFragment.mStart + aOffset;
case kPrevFragment:
case kNextFragment:
default:
return 0;
}
}
nsEmbedCString::char_type*
nsEmbedCString::GetWritableFragment(fragment_type& aFragment, nsFragmentRequest aRequest, index_type aOffset)
{
switch (aRequest) {
case kFirstFragment:
case kLastFragment:
case kFragmentAt:
aFragment.mEnd = (aFragment.mStart = mStr) + mLength;
return aFragment.mStart + aOffset;
case kPrevFragment:
case kNextFragment:
default:
return 0;
}
}
const nsEmbedCString::buffer_handle_type*
nsEmbedCString::GetFlatBufferHandle() const
{
return NS_REINTERPRET_CAST(const buffer_handle_type*, 1);
}
void
nsEmbedCString::SetLength(size_type aLength)
{
if (aLength > mCapacity)
GrowCapacity(aLength);
mLength = aLength;
if (mStr != (char_type*)gCommonEmptyBuffer)
AddNullTerminator();
}
void
nsEmbedCString::SetCapacity(size_type aNewCapacity)
{
if (aNewCapacity)
{
if (aNewCapacity > mCapacity)
GrowCapacity(aNewCapacity);
// AddNullTerminator(); // doesn't make sense
}
else
{
Destroy();
Init();
}
}
PRBool
nsEmbedCString::EnsureCapacity(size_type aNewCapacity)
{
PRBool result = PR_TRUE;
if (aNewCapacity > mCapacity)
{
result = Realloc(aNewCapacity);
if (result)
AddNullTerminator();
}
return result;
}
PRBool
nsEmbedCString::GrowCapacity(size_type aNewCapacity)
{
PRBool result = PR_TRUE;
if (mCapacity)
{
size_type newCapacity = mCapacity;
while (newCapacity < aNewCapacity)
newCapacity <<= 1;
aNewCapacity = newCapacity;
}
nsEmbedCString temp;
result = temp.EnsureCapacity(aNewCapacity);
if (result)
{
if (mLength)
temp.Assign(*this);
Free();
mStr = temp.mStr;
temp.mStr = 0;
mLength = temp.mLength;
mCapacity = temp.mCapacity;
}
return result;
}

Просмотреть файл

Просмотреть файл

@ -317,8 +317,6 @@ interface nsIFile : nsISupports
};
%{C++
#define NS_FILE_CONTRACTID "@mozilla.org/file;1"
#define NS_FILE_CLASSNAME "File Specification"
#ifndef MOZILLA_STRICT_API
#include "nsDirectoryServiceUtils.h"
#endif

Просмотреть файл

@ -170,8 +170,3 @@ interface nsILocalFile : nsIFile
void setRelativeDescriptor(in nsILocalFile fromFile, in ACString relativeDesc);
};
%{C++
#define NS_LOCAL_FILE_CONTRACTID "@mozilla.org/file/local;1"
#define NS_LOCAL_FILE_CLASSNAME "Local File Specification"
%}

Просмотреть файл

@ -63,15 +63,11 @@ EXTRA_COMPONENTS = nsSample.js
# seperate libraries linked in.
EXTRA_DSO_LDOPTS = \
$(DIST)/lib/$(LIB_PREFIX)string_s.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)string_obsolete_s.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \
$(NSPR_LIBS) \
$(NULL)
LIBS = \
$(DIST)/lib/$(LIB_PREFIX)string_s.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)string_obsolete_s.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \
$(NSPR_LIBS) \
$(NULL)

Просмотреть файл

@ -47,16 +47,12 @@
#include "nsSample.h"
#include "nsMemory.h"
#ifdef XPCOM_GLUE
#include "nsXPCOMGlue.h"
#endif
#include "nsEmbedString.h"
////////////////////////////////////////////////////////////////////////
nsSampleImpl::nsSampleImpl() : mValue(nsnull)
{
#ifdef XPCOM_GLUE
XPCOMGlueStartup("XPCOMComponentGlue");
#endif
NS_INIT_ISUPPORTS();
mValue = (char*)nsMemory::Clone("initial value", 14);
}
@ -65,10 +61,6 @@ nsSampleImpl::~nsSampleImpl()
{
if (mValue)
nsMemory::Free(mValue);
#ifdef XPCOM_GLUE
XPCOMGlueShutdown();
#endif
}
/**
@ -150,6 +142,12 @@ nsSampleImpl::Poke(const char* aValue)
return SetValue((char*) aValue);
}
static void GetStringValue(nsACString& aValue)
{
aValue.Assign("GetValue");
}
NS_IMETHODIMP
nsSampleImpl::WriteValue(const char* aPrefix)
{
@ -158,5 +156,27 @@ nsSampleImpl::WriteValue(const char* aPrefix)
return NS_ERROR_NULL_POINTER;
printf("%s %s\n", aPrefix, mValue);
// This next part illustrates the nsEmbedString:
nsEmbedString foopy;
foopy.Append(PRUnichar('f'));
foopy.Append(PRUnichar('o'));
foopy.Append(PRUnichar('o'));
foopy.Append(PRUnichar('p'));
foopy.Append(PRUnichar('y'));
const PRUnichar* f = foopy.get();
PRUint32 l = foopy.Length();
printf("%c%c%c%c%c %d\n", char(f[0]), char(f[1]), char(f[2]), char(f[3]), char(f[4]), l);
nsEmbedCString foopy2;
GetStringValue(foopy2);
//foopy2.Append(NS_LITERAL_CSTRING("foopy"));
const char* f2 = foopy2.get();
PRUint32 l2 = foopy2.Length();
printf("%s %d\n", f2, l2);
return NS_OK;
}

Просмотреть файл

@ -51,6 +51,7 @@
#ifdef XPCOM_GLUE
#include "nsXPCOMGlue.h"
#include "nsMemory.h"
#endif
#define NS_SAMPLE_CONTRACTID "@mozilla.org/sample;1"
@ -114,8 +115,14 @@ main(void)
return -3;
}
printf("Set value to: %s\n", testValue);
#ifndef XPCOM_GLUE
nsXPIDLCString str;
rv = mysample->GetValue(getter_Copies(str));
#else
char *str;
rv = mysample->GetValue(&str);
#endif
if (NS_FAILED(rv))
{
printf("ERROR: Calling nsISample::GetValue() [%x]\n", rv);
@ -127,6 +134,9 @@ main(void)
return -4;
}
#ifdef XPCOM_GLUE
nsMemory::Free(str);
#endif
rv = mysample->WriteValue("Final print :");
printf("Test passed.\n");

Просмотреть файл

@ -30,13 +30,17 @@ include $(DEPTH)/config/autoconf.mk
MODULE = string
SDK_HEADERS = \
nsAString.h \
nsBufferHandle.h \
nsStringFragment.h \
$(NULL)
EXPORTS = \
nsAFlatString.h \
nsAlgorithm.h \
nsASingleFragmentString.h \
nsAString.h \
nsAStringGenerator.h \
nsBufferHandle.h \
nsBufferHandleUtils.h \
nsCharTraits.h \
nsDependentConcatenation.h \
@ -51,7 +55,6 @@ EXPORTS = \
nsSharedBufferList.h \
nsSlidingString.h \
nsStringDefines.h \
nsStringFragment.h \
nsStringFwd.h \
nsStringIterator.h \
nsStringIteratorUtils.h \

Просмотреть файл

@ -24,7 +24,7 @@
#include "nsAString.h"
#include "nsDependentSubstring.h"
#include "nsDependentString.h"
#include "nsCRT.h"
#include "plstr.h"
int
@ -520,7 +520,12 @@ nsDefaultCStringComparator::operator()( char_type lhs, char_type rhs ) const
int
nsCaseInsensitiveCStringComparator::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const
{
return nsCRT::strncasecmp(lhs, rhs, aLength);
PRInt32 result=PRInt32(PL_strncasecmp(lhs, rhs, aLength));
//Egads. PL_strncasecmp is returning *very* negative numbers.
//Some folks expect -1,0,1, so let's temper its enthusiasm.
if (result<0)
result=-1;
return result;
}
PRBool

Просмотреть файл

@ -268,7 +268,7 @@ DeletionTest(const char* creationPath, const char* appendPath, PRBool recursive)
{
nsCOMPtr<nsILocalFile> file;
nsresult rv =
nsComponentManager::CreateInstance(NS_FILE_CONTRACTID, NULL,
nsComponentManager::CreateInstance(NS_LOCAL_FILE_CONTRACTID, NULL,
NS_GET_IID(nsILocalFile),
(void**)getter_AddRefs(file));