nsPrimitiveHelpers.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2. *
  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/. */
  6. //
  7. // Part of the reason these routines are all in once place is so that as new
  8. // data flavors are added that are known to be one-byte or two-byte strings, or even
  9. // raw binary data, then we just have to go to one place to change how the data
  10. // moves into/out of the primitives and native line endings.
  11. //
  12. // If you add new flavors that have special consideration (binary data or one-byte
  13. // char* strings), please update all the helper classes in this file.
  14. //
  15. // For now, this is the assumption that we are making:
  16. // - text/plain is always a char*
  17. // - anything else is a char16_t*
  18. //
  19. #include "nsPrimitiveHelpers.h"
  20. #include "mozilla/UniquePtr.h"
  21. #include "nsCOMPtr.h"
  22. #include "nsXPCOM.h"
  23. #include "nsISupportsPrimitives.h"
  24. #include "nsITransferable.h"
  25. #include "nsIComponentManager.h"
  26. #include "nsLinebreakConverter.h"
  27. #include "nsReadableUtils.h"
  28. //
  29. // CreatePrimitiveForData
  30. //
  31. // Given some data and the flavor it corresponds to, creates the appropriate
  32. // nsISupports* wrapper for passing across IDL boundaries. Right now, everything
  33. // creates a two-byte |nsISupportsString|, except for "text/plain" and native
  34. // platform HTML (CF_HTML on win32)
  35. //
  36. void
  37. nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, const void* aDataBuff,
  38. uint32_t aDataLen, nsISupports** aPrimitive )
  39. {
  40. if ( !aPrimitive )
  41. return;
  42. if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 ||
  43. strcmp(aFlavor,kRTFMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
  44. nsCOMPtr<nsISupportsCString> primitive =
  45. do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
  46. if ( primitive ) {
  47. const char * start = reinterpret_cast<const char*>(aDataBuff);
  48. primitive->SetData(Substring(start, start + aDataLen));
  49. NS_ADDREF(*aPrimitive = primitive);
  50. }
  51. }
  52. else {
  53. nsCOMPtr<nsISupportsString> primitive =
  54. do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
  55. if (primitive ) {
  56. if (aDataLen % 2) {
  57. auto buffer = mozilla::MakeUnique<char[]>(aDataLen + 1);
  58. if (!MOZ_LIKELY(buffer))
  59. return;
  60. memcpy(buffer.get(), aDataBuff, aDataLen);
  61. buffer[aDataLen] = 0;
  62. const char16_t* start = reinterpret_cast<const char16_t*>(buffer.get());
  63. // recall that length takes length as characters, not bytes
  64. primitive->SetData(Substring(start, start + (aDataLen + 1) / 2));
  65. } else {
  66. const char16_t* start = reinterpret_cast<const char16_t*>(aDataBuff);
  67. // recall that length takes length as characters, not bytes
  68. primitive->SetData(Substring(start, start + (aDataLen / 2)));
  69. }
  70. NS_ADDREF(*aPrimitive = primitive);
  71. }
  72. }
  73. } // CreatePrimitiveForData
  74. //
  75. // CreatePrimitiveForCFHTML
  76. //
  77. // Platform specific CreatePrimitive, windows CF_HTML.
  78. //
  79. void
  80. nsPrimitiveHelpers :: CreatePrimitiveForCFHTML ( const void* aDataBuff,
  81. uint32_t* aDataLen, nsISupports** aPrimitive )
  82. {
  83. if (!aPrimitive)
  84. return;
  85. nsCOMPtr<nsISupportsString> primitive =
  86. do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
  87. if (!primitive)
  88. return;
  89. // We need to duplicate the input buffer, since the removal of linebreaks
  90. // might reallocte it.
  91. void* utf8 = moz_xmalloc(*aDataLen);
  92. if (!utf8)
  93. return;
  94. memcpy(utf8, aDataBuff, *aDataLen);
  95. int32_t signedLen = static_cast<int32_t>(*aDataLen);
  96. nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(kTextMime, &utf8, &signedLen);
  97. *aDataLen = signedLen;
  98. nsAutoString str(NS_ConvertUTF8toUTF16(reinterpret_cast<const char*>(utf8), *aDataLen));
  99. free(utf8);
  100. *aDataLen = str.Length() * sizeof(char16_t);
  101. primitive->SetData(str);
  102. NS_ADDREF(*aPrimitive = primitive);
  103. }
  104. //
  105. // CreateDataFromPrimitive
  106. //
  107. // Given a nsISupports* primitive and the flavor it represents, creates a new data
  108. // buffer with the data in it. This data will be null terminated, but the length
  109. // parameter does not reflect that.
  110. //
  111. void
  112. nsPrimitiveHelpers :: CreateDataFromPrimitive ( const char* aFlavor, nsISupports* aPrimitive,
  113. void** aDataBuff, uint32_t aDataLen )
  114. {
  115. if ( !aDataBuff )
  116. return;
  117. *aDataBuff = nullptr;
  118. if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
  119. nsCOMPtr<nsISupportsCString> plainText ( do_QueryInterface(aPrimitive) );
  120. if ( plainText ) {
  121. nsAutoCString data;
  122. plainText->GetData ( data );
  123. *aDataBuff = ToNewCString(data);
  124. }
  125. }
  126. else {
  127. nsCOMPtr<nsISupportsString> doubleByteText ( do_QueryInterface(aPrimitive) );
  128. if ( doubleByteText ) {
  129. nsAutoString data;
  130. doubleByteText->GetData ( data );
  131. *aDataBuff = ToNewUnicode(data);
  132. }
  133. }
  134. }
  135. //
  136. // ConvertPlatformToDOMLinebreaks
  137. //
  138. // Given some data, convert from the platform linebreaks into the LF expected by the
  139. // DOM. This will attempt to convert the data in place, but the buffer may still need to
  140. // be reallocated regardless (disposing the old buffer is taken care of internally, see
  141. // the note below).
  142. //
  143. // NOTE: this assumes that it can use 'free' to dispose of the old buffer.
  144. //
  145. nsresult
  146. nsLinebreakHelpers :: ConvertPlatformToDOMLinebreaks ( const char* inFlavor, void** ioData,
  147. int32_t* ioLengthInBytes )
  148. {
  149. NS_ASSERTION ( ioData && *ioData && ioLengthInBytes, "Bad Params");
  150. if ( !(ioData && *ioData && ioLengthInBytes) )
  151. return NS_ERROR_INVALID_ARG;
  152. nsresult retVal = NS_OK;
  153. if ( strcmp(inFlavor, kTextMime) == 0 || strcmp(inFlavor, kRTFMime) == 0) {
  154. char* buffAsChars = reinterpret_cast<char*>(*ioData);
  155. char* oldBuffer = buffAsChars;
  156. retVal = nsLinebreakConverter::ConvertLineBreaksInSitu ( &buffAsChars, nsLinebreakConverter::eLinebreakAny,
  157. nsLinebreakConverter::eLinebreakContent,
  158. *ioLengthInBytes, ioLengthInBytes );
  159. if ( NS_SUCCEEDED(retVal) ) {
  160. if ( buffAsChars != oldBuffer ) // check if buffer was reallocated
  161. free ( oldBuffer );
  162. *ioData = buffAsChars;
  163. }
  164. }
  165. else if ( strcmp(inFlavor, "image/jpeg") == 0 ) {
  166. // I'd assume we don't want to do anything for binary data....
  167. }
  168. else {
  169. char16_t* buffAsUnichar = reinterpret_cast<char16_t*>(*ioData);
  170. char16_t* oldBuffer = buffAsUnichar;
  171. int32_t newLengthInChars;
  172. retVal = nsLinebreakConverter::ConvertUnicharLineBreaksInSitu ( &buffAsUnichar, nsLinebreakConverter::eLinebreakAny,
  173. nsLinebreakConverter::eLinebreakContent,
  174. *ioLengthInBytes / sizeof(char16_t), &newLengthInChars );
  175. if ( NS_SUCCEEDED(retVal) ) {
  176. if ( buffAsUnichar != oldBuffer ) // check if buffer was reallocated
  177. free ( oldBuffer );
  178. *ioData = buffAsUnichar;
  179. *ioLengthInBytes = newLengthInChars * sizeof(char16_t);
  180. }
  181. }
  182. return retVal;
  183. } // ConvertPlatformToDOMLinebreaks