michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsScriptableInputStream.h" michael@0: #include "nsMemory.h" michael@0: #include "nsString.h" michael@0: michael@0: NS_IMPL_ISUPPORTS(nsScriptableInputStream, nsIScriptableInputStream) michael@0: michael@0: // nsIScriptableInputStream methods michael@0: NS_IMETHODIMP michael@0: nsScriptableInputStream::Close(void) { michael@0: if (!mInputStream) return NS_ERROR_NOT_INITIALIZED; michael@0: return mInputStream->Close(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScriptableInputStream::Init(nsIInputStream *aInputStream) { michael@0: if (!aInputStream) return NS_ERROR_NULL_POINTER; michael@0: mInputStream = aInputStream; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScriptableInputStream::Available(uint64_t *_retval) { michael@0: if (!mInputStream) return NS_ERROR_NOT_INITIALIZED; michael@0: return mInputStream->Available(_retval); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScriptableInputStream::Read(uint32_t aCount, char **_retval) { michael@0: nsresult rv = NS_OK; michael@0: uint64_t count64 = 0; michael@0: char *buffer = nullptr; michael@0: michael@0: if (!mInputStream) return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: rv = mInputStream->Available(&count64); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // bug716556 - Ensure count+1 doesn't overflow michael@0: uint32_t count = XPCOM_MIN((uint32_t)XPCOM_MIN(count64, aCount), UINT32_MAX - 1); michael@0: buffer = (char*)moz_malloc(count+1); // make room for '\0' michael@0: if (!buffer) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: rv = ReadHelper(buffer, count); michael@0: if (NS_FAILED(rv)) { michael@0: nsMemory::Free(buffer); michael@0: return rv; michael@0: } michael@0: michael@0: buffer[count] = '\0'; michael@0: *_retval = buffer; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsScriptableInputStream::ReadBytes(uint32_t aCount, nsACString &_retval) { michael@0: if (!mInputStream) { michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: } michael@0: michael@0: _retval.SetLength(aCount); michael@0: if (_retval.Length() != aCount) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: char *ptr = _retval.BeginWriting(); michael@0: nsresult rv = ReadHelper(ptr, aCount); michael@0: if (NS_FAILED(rv)) { michael@0: _retval.Truncate(); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsScriptableInputStream::ReadHelper(char* aBuffer, uint32_t aCount) michael@0: { michael@0: uint32_t totalBytesRead = 0; michael@0: while (1) { michael@0: uint32_t bytesRead; michael@0: nsresult rv = mInputStream->Read(aBuffer + totalBytesRead, michael@0: aCount - totalBytesRead, michael@0: &bytesRead); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: totalBytesRead += bytesRead; michael@0: if (totalBytesRead == aCount) { michael@0: break; michael@0: } michael@0: michael@0: // If we have read zero bytes, we have hit EOF. michael@0: if (bytesRead == 0) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsScriptableInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) { michael@0: if (aOuter) return NS_ERROR_NO_AGGREGATION; michael@0: michael@0: nsScriptableInputStream *sis = new nsScriptableInputStream(); michael@0: if (!sis) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(sis); michael@0: nsresult rv = sis->QueryInterface(aIID, aResult); michael@0: NS_RELEASE(sis); michael@0: return rv; michael@0: }