nsConverterOutputStream.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /* vim:set expandtab ts=4 sw=4 sts=4 cin: */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsCOMPtr.h"
  6. #include "nsIOutputStream.h"
  7. #include "nsString.h"
  8. #include "nsConverterOutputStream.h"
  9. #include "nsIUnicodeEncoder.h"
  10. #include "mozilla/dom/EncodingUtils.h"
  11. using mozilla::dom::EncodingUtils;
  12. NS_IMPL_ISUPPORTS(nsConverterOutputStream,
  13. nsIUnicharOutputStream,
  14. nsIConverterOutputStream)
  15. nsConverterOutputStream::~nsConverterOutputStream()
  16. {
  17. Close();
  18. }
  19. NS_IMETHODIMP
  20. nsConverterOutputStream::Init(nsIOutputStream* aOutStream,
  21. const char* aCharset,
  22. uint32_t aBufferSize /* ignored */,
  23. char16_t aReplacementChar)
  24. {
  25. NS_PRECONDITION(aOutStream, "Null output stream!");
  26. nsAutoCString label;
  27. if (!aCharset) {
  28. label.AssignLiteral("UTF-8");
  29. } else {
  30. label = aCharset;
  31. }
  32. nsAutoCString encoding;
  33. if (label.EqualsLiteral("UTF-16")) {
  34. // Make sure to output a BOM when UTF-16 requested
  35. encoding.Assign(label);
  36. } else if (!EncodingUtils::FindEncodingForLabelNoReplacement(label,
  37. encoding)) {
  38. return NS_ERROR_UCONV_NOCONV;
  39. }
  40. mConverter = EncodingUtils::EncoderForEncoding(encoding);
  41. mOutStream = aOutStream;
  42. int32_t behaviour = aReplacementChar ? nsIUnicodeEncoder::kOnError_Replace
  43. : nsIUnicodeEncoder::kOnError_Signal;
  44. return mConverter->
  45. SetOutputErrorBehavior(behaviour,
  46. nullptr,
  47. aReplacementChar);
  48. }
  49. NS_IMETHODIMP
  50. nsConverterOutputStream::Write(uint32_t aCount, const char16_t* aChars,
  51. bool* aSuccess)
  52. {
  53. if (!mOutStream) {
  54. NS_ASSERTION(!mConverter, "Closed streams shouldn't have converters");
  55. return NS_BASE_STREAM_CLOSED;
  56. }
  57. NS_ASSERTION(mConverter, "Must have a converter when not closed");
  58. int32_t inLen = aCount;
  59. int32_t maxLen;
  60. nsresult rv = mConverter->GetMaxLength(aChars, inLen, &maxLen);
  61. NS_ENSURE_SUCCESS(rv, rv);
  62. nsAutoCString buf;
  63. buf.SetLength(maxLen);
  64. if (buf.Length() != (uint32_t) maxLen)
  65. return NS_ERROR_OUT_OF_MEMORY;
  66. int32_t outLen = maxLen;
  67. rv = mConverter->Convert(aChars, &inLen, buf.BeginWriting(), &outLen);
  68. if (NS_FAILED(rv))
  69. return rv;
  70. if (rv == NS_ERROR_UENC_NOMAPPING) {
  71. // Yes, NS_ERROR_UENC_NOMAPPING is a success code
  72. return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
  73. }
  74. NS_ASSERTION((uint32_t) inLen == aCount,
  75. "Converter didn't consume all the data!");
  76. uint32_t written;
  77. rv = mOutStream->Write(buf.get(), outLen, &written);
  78. *aSuccess = NS_SUCCEEDED(rv) && written == uint32_t(outLen);
  79. return rv;
  80. }
  81. NS_IMETHODIMP
  82. nsConverterOutputStream::WriteString(const nsAString& aString, bool* aSuccess)
  83. {
  84. int32_t inLen = aString.Length();
  85. nsAString::const_iterator i;
  86. aString.BeginReading(i);
  87. return Write(inLen, i.get(), aSuccess);
  88. }
  89. NS_IMETHODIMP
  90. nsConverterOutputStream::Flush()
  91. {
  92. if (!mOutStream)
  93. return NS_OK; // Already closed.
  94. char buf[1024];
  95. int32_t size = sizeof(buf);
  96. nsresult rv = mConverter->Finish(buf, &size);
  97. NS_ASSERTION(rv != NS_OK_UENC_MOREOUTPUT,
  98. "1024 bytes ought to be enough for everyone");
  99. if (NS_FAILED(rv))
  100. return rv;
  101. if (size == 0)
  102. return NS_OK;
  103. uint32_t written;
  104. rv = mOutStream->Write(buf, size, &written);
  105. if (NS_FAILED(rv)) {
  106. NS_WARNING("Flush() lost data!");
  107. return rv;
  108. }
  109. if (written != uint32_t(size)) {
  110. NS_WARNING("Flush() lost data!");
  111. return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
  112. }
  113. return rv;
  114. }
  115. NS_IMETHODIMP
  116. nsConverterOutputStream::Close()
  117. {
  118. if (!mOutStream)
  119. return NS_OK; // Already closed.
  120. nsresult rv1 = Flush();
  121. nsresult rv2 = mOutStream->Close();
  122. mOutStream = nullptr;
  123. mConverter = nullptr;
  124. return NS_FAILED(rv1) ? rv1 : rv2;
  125. }