dom/src/json/nsJSON.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=79: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "jsapi.h"
     8 #include "js/CharacterEncoding.h"
     9 #include "js/OldDebugAPI.h"
    10 #include "nsJSON.h"
    11 #include "nsIXPConnect.h"
    12 #include "nsIXPCScriptable.h"
    13 #include "nsStreamUtils.h"
    14 #include "nsIInputStream.h"
    15 #include "nsStringStream.h"
    16 #include "mozilla/dom/EncodingUtils.h"
    17 #include "nsIUnicodeEncoder.h"
    18 #include "nsIUnicodeDecoder.h"
    19 #include "nsXPCOMStrings.h"
    20 #include "nsNetUtil.h"
    21 #include "nsContentUtils.h"
    22 #include "nsIScriptError.h"
    23 #include "nsCRTGlue.h"
    24 #include "nsAutoPtr.h"
    25 #include "nsIScriptSecurityManager.h"
    26 #include "mozilla/Maybe.h"
    27 #include <algorithm>
    29 using mozilla::dom::EncodingUtils;
    31 #define JSON_STREAM_BUFSIZE 4096
    33 NS_INTERFACE_MAP_BEGIN(nsJSON)
    34   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSON)
    35   NS_INTERFACE_MAP_ENTRY(nsIJSON)
    36 NS_INTERFACE_MAP_END
    38 NS_IMPL_ADDREF(nsJSON)
    39 NS_IMPL_RELEASE(nsJSON)
    41 nsJSON::nsJSON()
    42 {
    43 }
    45 nsJSON::~nsJSON()
    46 {
    47 }
    49 enum DeprecationWarning { EncodeWarning, DecodeWarning };
    51 static nsresult
    52 WarnDeprecatedMethod(DeprecationWarning warning)
    53 {
    54   return nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    55                                          NS_LITERAL_CSTRING("DOM Core"), nullptr,
    56                                          nsContentUtils::eDOM_PROPERTIES,
    57                                          warning == EncodeWarning
    58                                          ? "nsIJSONEncodeDeprecatedWarning"
    59                                          : "nsIJSONDecodeDeprecatedWarning");
    60 }
    62 NS_IMETHODIMP
    63 nsJSON::Encode(JS::Handle<JS::Value> aValue, JSContext* cx, uint8_t aArgc,
    64                nsAString &aJSON)
    65 {
    66   // This function should only be called from JS.
    67   nsresult rv = WarnDeprecatedMethod(EncodeWarning);
    68   if (NS_FAILED(rv))
    69     return rv;
    71   if (aArgc == 0) {
    72     aJSON.Truncate();
    73     aJSON.SetIsVoid(true);
    74     return NS_OK;
    75   }
    77   nsJSONWriter writer;
    78   rv = EncodeInternal(cx, aValue, &writer);
    80   // FIXME: bug 408838. Get exception types sorted out
    81   if (NS_SUCCEEDED(rv) || rv == NS_ERROR_INVALID_ARG) {
    82     rv = NS_OK;
    83     // if we didn't consume anything, it's not JSON, so return null
    84     if (!writer.DidWrite()) {
    85       aJSON.Truncate();
    86       aJSON.SetIsVoid(true);
    87     } else {
    88       writer.FlushBuffer();
    89       aJSON.Append(writer.mOutputString);
    90     }
    91   }
    93   return rv;
    94 }
    96 static const char UTF8BOM[] = "\xEF\xBB\xBF";
    97 static const char UTF16LEBOM[] = "\xFF\xFE";
    98 static const char UTF16BEBOM[] = "\xFE\xFF";
   100 static nsresult CheckCharset(const char* aCharset)
   101 {
   102   // Check that the charset is permissible
   103   if (!(strcmp(aCharset, "UTF-8") == 0 ||
   104         strcmp(aCharset, "UTF-16LE") == 0 ||
   105         strcmp(aCharset, "UTF-16BE") == 0)) {
   106     return NS_ERROR_INVALID_ARG;
   107   }
   109   return NS_OK;
   110 }
   112 NS_IMETHODIMP
   113 nsJSON::EncodeToStream(nsIOutputStream *aStream,
   114                        const char* aCharset,
   115                        const bool aWriteBOM,
   116                        JS::Handle<JS::Value> val,
   117                        JSContext* cx,
   118                        uint8_t aArgc)
   119 {
   120   // This function should only be called from JS.
   121   NS_ENSURE_ARG(aStream);
   122   nsresult rv;
   124   rv = CheckCharset(aCharset);
   125   NS_ENSURE_SUCCESS(rv, rv);
   127   // Check to see if we have a buffered stream
   128   nsCOMPtr<nsIOutputStream> bufferedStream;
   129   // FIXME: bug 408514.
   130   // NS_OutputStreamIsBuffered(aStream) asserts on file streams...
   131   //if (!NS_OutputStreamIsBuffered(aStream)) {
   132     rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedStream),
   133                                     aStream, 4096);
   134     NS_ENSURE_SUCCESS(rv, rv);
   135   //  aStream = bufferedStream;
   136   //}
   138   uint32_t ignored;
   139   if (aWriteBOM) {
   140     if (strcmp(aCharset, "UTF-8") == 0)
   141       rv = aStream->Write(UTF8BOM, 3, &ignored);
   142     else if (strcmp(aCharset, "UTF-16LE") == 0)
   143       rv = aStream->Write(UTF16LEBOM, 2, &ignored);
   144     else if (strcmp(aCharset, "UTF-16BE") == 0)
   145       rv = aStream->Write(UTF16BEBOM, 2, &ignored);
   146     NS_ENSURE_SUCCESS(rv, rv);
   147   }
   149   nsJSONWriter writer(bufferedStream);
   150   rv = writer.SetCharset(aCharset);
   151   NS_ENSURE_SUCCESS(rv, rv);
   153   if (aArgc == 0) {
   154     return NS_OK;
   155   }
   157   rv = EncodeInternal(cx, val, &writer);
   158   NS_ENSURE_SUCCESS(rv, rv);
   160   rv = bufferedStream->Flush();
   162   return rv;
   163 }
   165 static bool
   166 WriteCallback(const jschar *buf, uint32_t len, void *data)
   167 {
   168   nsJSONWriter *writer = static_cast<nsJSONWriter*>(data);
   169   nsresult rv =  writer->Write((const char16_t*)buf, (uint32_t)len);
   170   if (NS_FAILED(rv))
   171     return false;
   173   return true;
   174 }
   176 NS_IMETHODIMP
   177 nsJSON::EncodeFromJSVal(JS::Value *value, JSContext *cx, nsAString &result)
   178 {
   179   result.Truncate();
   181   mozilla::Maybe<JSAutoCompartment> ac;
   182   if (value->isObject()) {
   183     JS::Rooted<JSObject*> obj(cx, &value->toObject());
   184     ac.construct(cx, obj);
   185   }
   187   nsJSONWriter writer;
   188   JS::Rooted<JS::Value> vp(cx, *value);
   189   if (!JS_Stringify(cx, &vp, JS::NullPtr(), JS::NullHandleValue, WriteCallback, &writer)) {
   190     return NS_ERROR_XPC_BAD_CONVERT_JS;
   191   }
   192   *value = vp;
   194   NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED);
   195   writer.FlushBuffer();
   196   result.Assign(writer.mOutputString);
   197   return NS_OK;
   198 }
   200 nsresult
   201 nsJSON::EncodeInternal(JSContext* cx, const JS::Value& aValue,
   202                        nsJSONWriter* writer)
   203 {
   204   // Backward compatibility:
   205   // nsIJSON does not allow to serialize anything other than objects
   206   if (!aValue.isObject()) {
   207     return NS_ERROR_INVALID_ARG;
   208   }
   209   JS::Rooted<JSObject*> obj(cx, &aValue.toObject());
   211   /* Backward compatibility:
   212    * Manually call toJSON if implemented by the object and check that
   213    * the result is still an object
   214    * Note: It is perfectly fine to not implement toJSON, so it is
   215    * perfectly fine for GetMethod to fail
   216    */
   217   JS::Rooted<JS::Value> val(cx, aValue);
   218   JS::Rooted<JS::Value> toJSON(cx);
   219   if (JS_GetProperty(cx, obj, "toJSON", &toJSON) &&
   220       toJSON.isObject() &&
   221       JS_ObjectIsCallable(cx, &toJSON.toObject())) {
   222     // If toJSON is implemented, it must not throw
   223     if (!JS_CallFunctionValue(cx, obj, toJSON, JS::HandleValueArray::empty(), &val)) {
   224       if (JS_IsExceptionPending(cx))
   225         // passing NS_OK will throw the pending exception
   226         return NS_OK;
   228       // No exception, but still failed
   229       return NS_ERROR_FAILURE;
   230     }
   232     // Backward compatibility:
   233     // nsIJSON does not allow to serialize anything other than objects
   234     if (val.isPrimitive())
   235       return NS_ERROR_INVALID_ARG;
   236   }
   237   // GetMethod may have thrown
   238   else if (JS_IsExceptionPending(cx))
   239     // passing NS_OK will throw the pending exception
   240     return NS_OK;
   242   // Backward compatibility:
   243   // function shall not pass, just "plain" objects and arrays
   244   JSType type = JS_TypeOfValue(cx, val);
   245   if (type == JSTYPE_FUNCTION)
   246     return NS_ERROR_INVALID_ARG;
   248   // We're good now; try to stringify
   249   if (!JS_Stringify(cx, &val, JS::NullPtr(), JS::NullHandleValue, WriteCallback, writer))
   250     return NS_ERROR_FAILURE;
   252   return NS_OK;
   253 }
   256 nsJSONWriter::nsJSONWriter() : mStream(nullptr),
   257                                mBuffer(nullptr),
   258                                mBufferCount(0),
   259                                mDidWrite(false),
   260                                mEncoder(nullptr)
   261 {
   262 }
   264 nsJSONWriter::nsJSONWriter(nsIOutputStream *aStream) : mStream(aStream),
   265                                                        mBuffer(nullptr),
   266                                                        mBufferCount(0),
   267                                                        mDidWrite(false),
   268                                                        mEncoder(nullptr)
   269 {
   270 }
   272 nsJSONWriter::~nsJSONWriter()
   273 {
   274   delete [] mBuffer;
   275 }
   277 nsresult
   278 nsJSONWriter::SetCharset(const char* aCharset)
   279 {
   280   nsresult rv = NS_OK;
   281   if (mStream) {
   282     mEncoder = EncodingUtils::EncoderForEncoding(aCharset);
   283     rv = mEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Signal,
   284                                           nullptr, '\0');
   285     NS_ENSURE_SUCCESS(rv, rv);
   286   }
   288   return rv;
   289 }
   291 nsresult
   292 nsJSONWriter::Write(const char16_t *aBuffer, uint32_t aLength)
   293 {
   294   if (mStream) {
   295     return WriteToStream(mStream, mEncoder, aBuffer, aLength);
   296   }
   298   if (!mDidWrite) {
   299     mBuffer = new char16_t[JSON_STREAM_BUFSIZE];
   300     if (!mBuffer)
   301       return NS_ERROR_OUT_OF_MEMORY;
   302     mDidWrite = true;
   303   }
   305   if (JSON_STREAM_BUFSIZE <= aLength + mBufferCount) {
   306     mOutputString.Append(mBuffer, mBufferCount);
   307     mBufferCount = 0;
   308   }
   310   if (JSON_STREAM_BUFSIZE <= aLength) {
   311     // we know mBufferCount is 0 because we know we hit the if above
   312     mOutputString.Append(aBuffer, aLength);
   313   } else {
   314     memcpy(&mBuffer[mBufferCount], aBuffer, aLength * sizeof(char16_t));
   315     mBufferCount += aLength;
   316   }
   318   return NS_OK;
   319 }
   321 bool nsJSONWriter::DidWrite()
   322 {
   323   return mDidWrite;
   324 }
   326 void
   327 nsJSONWriter::FlushBuffer()
   328 {
   329   mOutputString.Append(mBuffer, mBufferCount);
   330 }
   332 nsresult
   333 nsJSONWriter::WriteToStream(nsIOutputStream *aStream,
   334                             nsIUnicodeEncoder *encoder,
   335                             const char16_t *aBuffer,
   336                             uint32_t aLength)
   337 {
   338   nsresult rv;
   339   int32_t srcLength = aLength;
   340   uint32_t bytesWritten;
   342   // The bytes written to the stream might differ from the char16_t size
   343   int32_t aDestLength;
   344   rv = encoder->GetMaxLength(aBuffer, srcLength, &aDestLength);
   345   NS_ENSURE_SUCCESS(rv, rv);
   347   // create the buffer we need
   348   char* destBuf = (char *) NS_Alloc(aDestLength);
   349   if (!destBuf)
   350     return NS_ERROR_OUT_OF_MEMORY;
   352   rv = encoder->Convert(aBuffer, &srcLength, destBuf, &aDestLength);
   353   if (NS_SUCCEEDED(rv))
   354     rv = aStream->Write(destBuf, aDestLength, &bytesWritten);
   356   NS_Free(destBuf);
   357   mDidWrite = true;
   359   return rv;
   360 }
   362 NS_IMETHODIMP
   363 nsJSON::Decode(const nsAString& json, JSContext* cx,
   364                JS::MutableHandle<JS::Value> aRetval)
   365 {
   366   nsresult rv = WarnDeprecatedMethod(DecodeWarning);
   367   if (NS_FAILED(rv))
   368     return rv;
   370   const char16_t *data;
   371   uint32_t len = NS_StringGetData(json, &data);
   372   nsCOMPtr<nsIInputStream> stream;
   373   rv = NS_NewByteInputStream(getter_AddRefs(stream),
   374                              reinterpret_cast<const char*>(data),
   375                              len * sizeof(char16_t),
   376                              NS_ASSIGNMENT_DEPEND);
   377   NS_ENSURE_SUCCESS(rv, rv);
   378   return DecodeInternal(cx, stream, len, false, aRetval);
   379 }
   381 NS_IMETHODIMP
   382 nsJSON::DecodeFromStream(nsIInputStream *aStream, int32_t aContentLength,
   383                          JSContext* cx, JS::MutableHandle<JS::Value> aRetval)
   384 {
   385   return DecodeInternal(cx, aStream, aContentLength, true, aRetval);
   386 }
   388 NS_IMETHODIMP
   389 nsJSON::DecodeToJSVal(const nsAString &str, JSContext *cx,
   390                       JS::MutableHandle<JS::Value> result)
   391 {
   392   if (!JS_ParseJSON(cx, static_cast<const jschar*>(PromiseFlatString(str).get()),
   393                     str.Length(), result)) {
   394     return NS_ERROR_UNEXPECTED;
   395   }
   396   return NS_OK;
   397 }
   399 nsresult
   400 nsJSON::DecodeInternal(JSContext* cx,
   401                        nsIInputStream *aStream,
   402                        int32_t aContentLength,
   403                        bool aNeedsConverter,
   404                        JS::MutableHandle<JS::Value> aRetval)
   405 {
   406   // Consume the stream
   407   nsCOMPtr<nsIChannel> jsonChannel;
   408   if (!mURI) {
   409     NS_NewURI(getter_AddRefs(mURI), NS_LITERAL_CSTRING("about:blank"), 0, 0 );
   410     if (!mURI)
   411       return NS_ERROR_OUT_OF_MEMORY;
   412   }
   414   nsresult rv =
   415     NS_NewInputStreamChannel(getter_AddRefs(jsonChannel), mURI, aStream,
   416                              NS_LITERAL_CSTRING("application/json"));
   417   if (!jsonChannel || NS_FAILED(rv))
   418     return NS_ERROR_FAILURE;
   420   nsRefPtr<nsJSONListener> jsonListener =
   421     new nsJSONListener(cx, aRetval.address(), aNeedsConverter);
   423   //XXX this stream pattern should be consolidated in netwerk
   424   rv = jsonListener->OnStartRequest(jsonChannel, nullptr);
   425   if (NS_FAILED(rv)) {
   426     jsonChannel->Cancel(rv);
   427     return rv;
   428   }
   430   nsresult status;
   431   jsonChannel->GetStatus(&status);
   432   uint64_t offset = 0;
   433   while (NS_SUCCEEDED(status)) {
   434     uint64_t available;
   435     rv = aStream->Available(&available);
   436     if (rv == NS_BASE_STREAM_CLOSED) {
   437       rv = NS_OK;
   438       break;
   439     }
   440     if (NS_FAILED(rv)) {
   441       jsonChannel->Cancel(rv);
   442       break;
   443     }
   444     if (!available)
   445       break; // blocking input stream has none available when done
   447     if (available > UINT32_MAX)
   448       available = UINT32_MAX;
   450     rv = jsonListener->OnDataAvailable(jsonChannel, nullptr,
   451                                        aStream,
   452                                        offset,
   453                                        (uint32_t)available);
   454     if (NS_FAILED(rv)) {
   455       jsonChannel->Cancel(rv);
   456       break;
   457     }
   459     offset += available;
   460     jsonChannel->GetStatus(&status);
   461   }
   462   NS_ENSURE_SUCCESS(rv, rv);
   464   rv = jsonListener->OnStopRequest(jsonChannel, nullptr, status);
   465   NS_ENSURE_SUCCESS(rv, rv);
   467   return NS_OK;
   468 }
   470 nsresult
   471 NS_NewJSON(nsISupports* aOuter, REFNSIID aIID, void** aResult)
   472 {
   473   nsJSON* json = new nsJSON();
   474   if (!json)
   475     return NS_ERROR_OUT_OF_MEMORY;
   477   NS_ADDREF(json);
   478   *aResult = json;
   480   return NS_OK;
   481 }
   483 nsJSONListener::nsJSONListener(JSContext *cx, JS::Value *rootVal,
   484                                bool needsConverter)
   485   : mNeedsConverter(needsConverter),
   486     mCx(cx),
   487     mRootVal(rootVal)
   488 {
   489 }
   491 nsJSONListener::~nsJSONListener()
   492 {
   493 }
   495 NS_INTERFACE_MAP_BEGIN(nsJSONListener)
   496   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsJSONListener)
   497   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   498   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   499 NS_INTERFACE_MAP_END
   501 NS_IMPL_ADDREF(nsJSONListener)
   502 NS_IMPL_RELEASE(nsJSONListener)
   504 NS_IMETHODIMP
   505 nsJSONListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
   506 {
   507   mSniffBuffer.Truncate();
   508   mDecoder = nullptr;
   510   return NS_OK;
   511 }
   513 NS_IMETHODIMP
   514 nsJSONListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
   515                               nsresult aStatusCode)
   516 {
   517   nsresult rv;
   519   // This can happen with short UTF-8 messages (<4 bytes)
   520   if (!mSniffBuffer.IsEmpty()) {
   521     // Just consume mSniffBuffer
   522     rv = ProcessBytes(nullptr, 0);
   523     NS_ENSURE_SUCCESS(rv, rv);
   524   }
   526   JS::Rooted<JS::Value> reviver(mCx, JS::NullValue()), value(mCx);
   528   JS::ConstTwoByteChars chars(reinterpret_cast<const jschar*>(mBufferedChars.Elements()),
   529                               mBufferedChars.Length());
   530   bool ok = JS_ParseJSONWithReviver(mCx, chars.get(),
   531                                       uint32_t(mBufferedChars.Length()),
   532                                       reviver, &value);
   534   *mRootVal = value;
   535   mBufferedChars.TruncateLength(0);
   536   return ok ? NS_OK : NS_ERROR_FAILURE;
   537 }
   539 NS_IMETHODIMP
   540 nsJSONListener::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
   541                                 nsIInputStream *aStream,
   542                                 uint64_t aOffset, uint32_t aLength)
   543 {
   544   nsresult rv = NS_OK;
   546   if (mNeedsConverter && mSniffBuffer.Length() < 4) {
   547     uint32_t readCount = (aLength < 4) ? aLength : 4;
   548     rv = NS_ConsumeStream(aStream, readCount, mSniffBuffer);
   549     NS_ENSURE_SUCCESS(rv, rv);
   551     if (mSniffBuffer.Length() < 4)
   552       return NS_OK;
   553   }
   555   char buffer[JSON_STREAM_BUFSIZE];
   556   unsigned long bytesRemaining = aLength - mSniffBuffer.Length();
   557   while (bytesRemaining) {
   558     unsigned int bytesRead;
   559     rv = aStream->Read(buffer,
   560                        std::min((unsigned long)sizeof(buffer), bytesRemaining),
   561                        &bytesRead);
   562     NS_ENSURE_SUCCESS(rv, rv);
   563     rv = ProcessBytes(buffer, bytesRead);
   564     NS_ENSURE_SUCCESS(rv, rv);
   565     bytesRemaining -= bytesRead;
   566   }
   568   return rv;
   569 }
   571 nsresult
   572 nsJSONListener::ProcessBytes(const char* aBuffer, uint32_t aByteLength)
   573 {
   574   nsresult rv;
   575   // Check for BOM, or sniff charset
   576   nsAutoCString charset;
   577   if (mNeedsConverter && !mDecoder) {
   578     if (!nsContentUtils::CheckForBOM((const unsigned char*) mSniffBuffer.get(),
   579                                       mSniffBuffer.Length(), charset)) {
   580       // OK, found no BOM, sniff the first character to see what this is
   581       // See section 3 of RFC4627 for details on why this works.
   582       const char *buffer = mSniffBuffer.get();
   583       if (mSniffBuffer.Length() >= 4) {
   584         if (buffer[0] == 0x00 && buffer[1] != 0x00 &&
   585             buffer[2] == 0x00 && buffer[3] != 0x00) {
   586           charset = "UTF-16BE";
   587         } else if (buffer[0] != 0x00 && buffer[1] == 0x00 &&
   588                    buffer[2] != 0x00 && buffer[3] == 0x00) {
   589           charset = "UTF-16LE";
   590         } else if (buffer[0] != 0x00 && buffer[1] != 0x00 &&
   591                    buffer[2] != 0x00 && buffer[3] != 0x00) {
   592           charset = "UTF-8";
   593         }
   594       } else {
   595         // Not enough bytes to sniff, assume UTF-8
   596         charset = "UTF-8";
   597       }
   598     }
   600     // We should have a unicode charset by now
   601     rv = CheckCharset(charset.get());
   602     NS_ENSURE_SUCCESS(rv, rv);
   603     mDecoder = EncodingUtils::DecoderForEncoding(charset);
   605     // consume the sniffed bytes
   606     rv = ConsumeConverted(mSniffBuffer.get(), mSniffBuffer.Length());
   607     NS_ENSURE_SUCCESS(rv, rv);
   608     mSniffBuffer.Truncate();
   609   }
   611   if (!aBuffer)
   612     return NS_OK;
   614   if (mNeedsConverter) {
   615     rv = ConsumeConverted(aBuffer, aByteLength);
   616   } else {
   617     uint32_t unichars = aByteLength / sizeof(char16_t);
   618     rv = Consume((char16_t *) aBuffer, unichars);
   619   }
   621   return rv;
   622 }
   624 nsresult
   625 nsJSONListener::ConsumeConverted(const char* aBuffer, uint32_t aByteLength)
   626 {
   627   nsresult rv;
   628   int32_t unicharLength = 0;
   629   int32_t srcLen = aByteLength;
   631   rv = mDecoder->GetMaxLength(aBuffer, srcLen, &unicharLength);
   632   NS_ENSURE_SUCCESS(rv, rv);
   634   char16_t* endelems = mBufferedChars.AppendElements(unicharLength);
   635   int32_t preLength = unicharLength;
   636   rv = mDecoder->Convert(aBuffer, &srcLen, endelems, &unicharLength);
   637   if (NS_FAILED(rv))
   638     return rv;
   639   NS_ABORT_IF_FALSE(preLength >= unicharLength, "GetMaxLength lied");
   640   if (preLength > unicharLength)
   641     mBufferedChars.TruncateLength(mBufferedChars.Length() - (preLength - unicharLength));
   642   return NS_OK;
   643 }
   645 nsresult
   646 nsJSONListener::Consume(const char16_t* aBuffer, uint32_t aByteLength)
   647 {
   648   if (!mBufferedChars.AppendElements(aBuffer, aByteLength))
   649     return NS_ERROR_FAILURE;
   651   return NS_OK;
   652 }

mercurial