1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
8 // Part of the reason these routines are all in once place is so that as new
9 // data flavors are added that are known to be one-byte or two-byte strings, or
10 // even raw binary data, then we just have to go to one place to change how the
11 // data moves into/out of the primitives and native line endings.
13 // If you add new flavors that have special consideration (binary data or
14 // one-byte char* strings), please update all the helper classes in this file.
16 // For now, this is the assumption that we are making:
17 // - text/plain is always a char*
18 // - anything else is a char16_t*
21 #include "nsPrimitiveHelpers.h"
23 #include "mozilla/UniquePtr.h"
24 #include "nsComponentManagerUtils.h"
27 #include "nsISupportsPrimitives.h"
28 #include "nsITransferable.h"
29 #include "nsLinebreakConverter.h"
30 #include "nsReadableUtils.h"
33 // CreatePrimitiveForData
35 // Given some data and the flavor it corresponds to, creates the appropriate
36 // nsISupports* wrapper for passing across IDL boundaries. Right now, everything
37 // creates a two-byte |nsISupportsString|, except for "text/plain" and native
38 // platform HTML (CF_HTML on win32)
40 void nsPrimitiveHelpers ::CreatePrimitiveForData(const nsACString
& aFlavor
,
41 const void* aDataBuff
,
43 nsISupports
** aPrimitive
) {
44 if (!aPrimitive
) return;
46 if (aFlavor
.EqualsLiteral(kNativeHTMLMime
) ||
47 aFlavor
.EqualsLiteral(kRTFMime
) ||
48 aFlavor
.EqualsLiteral(kCustomTypesMime
)) {
49 nsCOMPtr
<nsISupportsCString
> primitive
=
50 do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID
);
52 const char* start
= reinterpret_cast<const char*>(aDataBuff
);
53 primitive
->SetData(Substring(start
, start
+ aDataLen
));
54 NS_ADDREF(*aPrimitive
= primitive
);
57 nsCOMPtr
<nsISupportsString
> primitive
=
58 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
);
61 auto buffer
= mozilla::MakeUnique
<char[]>(aDataLen
+ 1);
62 if (!MOZ_LIKELY(buffer
)) return;
64 memcpy(buffer
.get(), aDataBuff
, aDataLen
);
66 const char16_t
* start
= reinterpret_cast<const char16_t
*>(buffer
.get());
67 // recall that length takes length as characters, not bytes
68 primitive
->SetData(Substring(start
, start
+ (aDataLen
+ 1) / 2));
70 const char16_t
* start
= reinterpret_cast<const char16_t
*>(aDataBuff
);
71 // recall that length takes length as characters, not bytes
72 primitive
->SetData(Substring(start
, start
+ (aDataLen
/ 2)));
74 NS_ADDREF(*aPrimitive
= primitive
);
78 } // CreatePrimitiveForData
81 // CreatePrimitiveForCFHTML
83 // Platform specific CreatePrimitive, windows CF_HTML.
85 void nsPrimitiveHelpers ::CreatePrimitiveForCFHTML(const void* aDataBuff
,
87 nsISupports
** aPrimitive
) {
88 if (!aPrimitive
) return;
90 nsCOMPtr
<nsISupportsString
> primitive
=
91 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
);
92 if (!primitive
) return;
94 // We need to duplicate the input buffer, since the removal of linebreaks
95 // might reallocte it.
96 void* utf8
= moz_xmalloc(*aDataLen
);
97 memcpy(utf8
, aDataBuff
, *aDataLen
);
98 int32_t signedLen
= static_cast<int32_t>(*aDataLen
);
99 nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(true, &utf8
, &signedLen
);
100 *aDataLen
= signedLen
;
103 NS_ConvertUTF8toUTF16(reinterpret_cast<const char*>(utf8
), *aDataLen
));
105 *aDataLen
= str
.Length() * sizeof(char16_t
);
106 primitive
->SetData(str
);
107 NS_ADDREF(*aPrimitive
= primitive
);
111 // CreateDataFromPrimitive
113 // Given a nsISupports* primitive and the flavor it represents, creates a new
114 // data buffer with the data in it. This data will be null terminated, but the
115 // length parameter does not reflect that.
117 void nsPrimitiveHelpers::CreateDataFromPrimitive(const nsACString
& aFlavor
,
118 nsISupports
* aPrimitive
,
120 uint32_t* aDataLen
) {
121 if (!aDataBuff
) return;
123 *aDataBuff
= nullptr;
126 if (aFlavor
.EqualsLiteral(kCustomTypesMime
)) {
127 nsCOMPtr
<nsISupportsCString
> plainText(do_QueryInterface(aPrimitive
));
130 plainText
->GetData(data
);
131 *aDataBuff
= ToNewCString(data
);
132 *aDataLen
= data
.Length() * sizeof(char);
135 nsCOMPtr
<nsISupportsString
> doubleByteText(do_QueryInterface(aPrimitive
));
136 if (doubleByteText
) {
138 doubleByteText
->GetData(data
);
139 *aDataBuff
= ToNewUnicode(data
);
140 *aDataLen
= data
.Length() * sizeof(char16_t
);
146 // ConvertPlatformToDOMLinebreaks
148 // Given some data, convert from the platform linebreaks into the LF expected by
149 // the DOM. This will attempt to convert the data in place, but the buffer may
150 // still need to be reallocated regardless (disposing the old buffer is taken
151 // care of internally, see the note below).
153 // NOTE: this assumes that it can use 'free' to dispose of the old buffer.
155 nsresult
nsLinebreakHelpers ::ConvertPlatformToDOMLinebreaks(
156 bool aIsSingleByteChars
, void** ioData
, int32_t* ioLengthInBytes
) {
157 NS_ASSERTION(ioData
&& *ioData
&& ioLengthInBytes
, "Bad Params");
158 if (!(ioData
&& *ioData
&& ioLengthInBytes
)) return NS_ERROR_INVALID_ARG
;
160 nsresult retVal
= NS_OK
;
162 // RTF and CF_HTML on Windows are transfered as single-byte characters.
163 if (aIsSingleByteChars
) {
164 char* buffAsChars
= reinterpret_cast<char*>(*ioData
);
165 char* oldBuffer
= buffAsChars
;
166 retVal
= nsLinebreakConverter::ConvertLineBreaksInSitu(
167 &buffAsChars
, nsLinebreakConverter::eLinebreakAny
,
168 nsLinebreakConverter::eLinebreakContent
, *ioLengthInBytes
,
170 if (NS_SUCCEEDED(retVal
)) {
171 if (buffAsChars
!= oldBuffer
) // check if buffer was reallocated
173 *ioData
= buffAsChars
;
176 char16_t
* buffAsUnichar
= reinterpret_cast<char16_t
*>(*ioData
);
177 char16_t
* oldBuffer
= buffAsUnichar
;
178 int32_t newLengthInChars
;
179 retVal
= nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(
180 &buffAsUnichar
, nsLinebreakConverter::eLinebreakAny
,
181 nsLinebreakConverter::eLinebreakContent
,
182 *ioLengthInBytes
/ sizeof(char16_t
), &newLengthInChars
);
183 if (NS_SUCCEEDED(retVal
)) {
184 if (buffAsUnichar
!= oldBuffer
) // check if buffer was reallocated
186 *ioData
= buffAsUnichar
;
187 *ioLengthInBytes
= newLengthInChars
* sizeof(char16_t
);
193 } // ConvertPlatformToDOMLinebreaks