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/. */
9 // Part of the reason these routines are all in once place is so that as new
10 // data flavors are added that are known to be one-byte or two-byte strings, or even
11 // raw binary data, then we just have to go to one place to change how the data
12 // moves into/out of the primitives and native line endings.
14 // If you add new flavors that have special consideration (binary data or one-byte
15 // char* strings), please update all the helper classes in this file.
17 // For now, this is the assumption that we are making:
18 // - text/plain is always a char*
19 // - anything else is a char16_t*
23 #include "nsPrimitiveHelpers.h"
25 #include "mozilla/UniquePtr.h"
28 #include "nsISupportsPrimitives.h"
29 #include "nsITransferable.h"
30 #include "nsIComponentManager.h"
31 #include "nsLinebreakConverter.h"
32 #include "nsReadableUtils.h"
36 // CreatePrimitiveForData
38 // Given some data and the flavor it corresponds to, creates the appropriate
39 // nsISupports* wrapper for passing across IDL boundaries. Right now, everything
40 // creates a two-byte |nsISupportsString|, except for "text/plain" and native
41 // platform HTML (CF_HTML on win32)
44 nsPrimitiveHelpers :: CreatePrimitiveForData ( const nsACString
& aFlavor
, const void* aDataBuff
,
45 uint32_t aDataLen
, nsISupports
** aPrimitive
)
50 if ( aFlavor
.EqualsLiteral(kTextMime
) ||
51 aFlavor
.EqualsLiteral(kNativeHTMLMime
) ||
52 aFlavor
.EqualsLiteral(kRTFMime
) ||
53 aFlavor
.EqualsLiteral(kCustomTypesMime
)) {
54 nsCOMPtr
<nsISupportsCString
> primitive
=
55 do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID
);
57 const char * start
= reinterpret_cast<const char*>(aDataBuff
);
58 primitive
->SetData(Substring(start
, start
+ aDataLen
));
59 NS_ADDREF(*aPrimitive
= primitive
);
63 nsCOMPtr
<nsISupportsString
> primitive
=
64 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
);
67 auto buffer
= mozilla::MakeUnique
<char[]>(aDataLen
+ 1);
68 if (!MOZ_LIKELY(buffer
))
71 memcpy(buffer
.get(), aDataBuff
, aDataLen
);
73 const char16_t
* start
= reinterpret_cast<const char16_t
*>(buffer
.get());
74 // recall that length takes length as characters, not bytes
75 primitive
->SetData(Substring(start
, start
+ (aDataLen
+ 1) / 2));
77 const char16_t
* start
= reinterpret_cast<const char16_t
*>(aDataBuff
);
78 // recall that length takes length as characters, not bytes
79 primitive
->SetData(Substring(start
, start
+ (aDataLen
/ 2)));
81 NS_ADDREF(*aPrimitive
= primitive
);
85 } // CreatePrimitiveForData
88 // CreatePrimitiveForCFHTML
90 // Platform specific CreatePrimitive, windows CF_HTML.
93 nsPrimitiveHelpers :: CreatePrimitiveForCFHTML ( const void* aDataBuff
,
94 uint32_t* aDataLen
, nsISupports
** aPrimitive
)
99 nsCOMPtr
<nsISupportsString
> primitive
=
100 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
);
104 // We need to duplicate the input buffer, since the removal of linebreaks
105 // might reallocte it.
106 void* utf8
= moz_xmalloc(*aDataLen
);
107 memcpy(utf8
, aDataBuff
, *aDataLen
);
108 int32_t signedLen
= static_cast<int32_t>(*aDataLen
);
109 nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(nsDependentCString(kTextMime
), &utf8
, &signedLen
);
110 *aDataLen
= signedLen
;
112 nsAutoString
str(NS_ConvertUTF8toUTF16(reinterpret_cast<const char*>(utf8
), *aDataLen
));
114 *aDataLen
= str
.Length() * sizeof(char16_t
);
115 primitive
->SetData(str
);
116 NS_ADDREF(*aPrimitive
= primitive
);
121 // CreateDataFromPrimitive
123 // Given a nsISupports* primitive and the flavor it represents, creates a new data
124 // buffer with the data in it. This data will be null terminated, but the length
125 // parameter does not reflect that.
128 nsPrimitiveHelpers :: CreateDataFromPrimitive ( const nsACString
& aFlavor
, nsISupports
* aPrimitive
,
129 void** aDataBuff
, uint32_t aDataLen
)
134 *aDataBuff
= nullptr;
136 if (aFlavor
.EqualsLiteral(kTextMime
) ||
137 aFlavor
.EqualsLiteral(kCustomTypesMime
)) {
138 nsCOMPtr
<nsISupportsCString
> plainText ( do_QueryInterface(aPrimitive
) );
141 plainText
->GetData ( data
);
142 *aDataBuff
= ToNewCString(data
);
146 nsCOMPtr
<nsISupportsString
> doubleByteText ( do_QueryInterface(aPrimitive
) );
147 if ( doubleByteText
) {
149 doubleByteText
->GetData ( data
);
150 *aDataBuff
= ToNewUnicode(data
);
158 // ConvertPlatformToDOMLinebreaks
160 // Given some data, convert from the platform linebreaks into the LF expected by the
161 // DOM. This will attempt to convert the data in place, but the buffer may still need to
162 // be reallocated regardless (disposing the old buffer is taken care of internally, see
165 // NOTE: this assumes that it can use 'free' to dispose of the old buffer.
168 nsLinebreakHelpers :: ConvertPlatformToDOMLinebreaks ( const nsACString
& inFlavor
, void** ioData
,
169 int32_t* ioLengthInBytes
)
171 NS_ASSERTION ( ioData
&& *ioData
&& ioLengthInBytes
, "Bad Params");
172 if ( !(ioData
&& *ioData
&& ioLengthInBytes
) )
173 return NS_ERROR_INVALID_ARG
;
175 nsresult retVal
= NS_OK
;
177 if (inFlavor
.EqualsLiteral(kTextMime
) ||
178 inFlavor
.EqualsLiteral(kRTFMime
)) {
179 char* buffAsChars
= reinterpret_cast<char*>(*ioData
);
180 char* oldBuffer
= buffAsChars
;
181 retVal
= nsLinebreakConverter::ConvertLineBreaksInSitu ( &buffAsChars
, nsLinebreakConverter::eLinebreakAny
,
182 nsLinebreakConverter::eLinebreakContent
,
183 *ioLengthInBytes
, ioLengthInBytes
);
184 if ( NS_SUCCEEDED(retVal
) ) {
185 if ( buffAsChars
!= oldBuffer
) // check if buffer was reallocated
187 *ioData
= buffAsChars
;
190 else if (inFlavor
.EqualsLiteral("image/jpeg")) {
191 // I'd assume we don't want to do anything for binary data....
194 char16_t
* buffAsUnichar
= reinterpret_cast<char16_t
*>(*ioData
);
195 char16_t
* oldBuffer
= buffAsUnichar
;
196 int32_t newLengthInChars
;
197 retVal
= nsLinebreakConverter::ConvertUnicharLineBreaksInSitu ( &buffAsUnichar
, nsLinebreakConverter::eLinebreakAny
,
198 nsLinebreakConverter::eLinebreakContent
,
199 *ioLengthInBytes
/ sizeof(char16_t
), &newLengthInChars
);
200 if ( NS_SUCCEEDED(retVal
) ) {
201 if ( buffAsUnichar
!= oldBuffer
) // check if buffer was reallocated
203 *ioData
= buffAsUnichar
;
204 *ioLengthInBytes
= newLengthInChars
* sizeof(char16_t
);
210 } // ConvertPlatformToDOMLinebreaks