Line data Source code
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 :
8 : //
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.
13 : //
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.
16 : //
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*
20 : //
21 :
22 :
23 : #include "nsPrimitiveHelpers.h"
24 :
25 : #include "mozilla/UniquePtr.h"
26 : #include "nsCOMPtr.h"
27 : #include "nsXPCOM.h"
28 : #include "nsISupportsPrimitives.h"
29 : #include "nsITransferable.h"
30 : #include "nsIComponentManager.h"
31 : #include "nsLinebreakConverter.h"
32 : #include "nsReadableUtils.h"
33 :
34 :
35 : //
36 : // CreatePrimitiveForData
37 : //
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)
42 : //
43 : void
44 0 : nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, const void* aDataBuff,
45 : uint32_t aDataLen, nsISupports** aPrimitive )
46 : {
47 0 : if ( !aPrimitive )
48 0 : return;
49 :
50 0 : if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 ||
51 0 : strcmp(aFlavor,kRTFMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
52 : nsCOMPtr<nsISupportsCString> primitive =
53 0 : do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
54 0 : if ( primitive ) {
55 0 : const char * start = reinterpret_cast<const char*>(aDataBuff);
56 0 : primitive->SetData(Substring(start, start + aDataLen));
57 0 : NS_ADDREF(*aPrimitive = primitive);
58 0 : }
59 : }
60 : else {
61 : nsCOMPtr<nsISupportsString> primitive =
62 0 : do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
63 0 : if (primitive ) {
64 0 : if (aDataLen % 2) {
65 0 : auto buffer = mozilla::MakeUnique<char[]>(aDataLen + 1);
66 0 : if (!MOZ_LIKELY(buffer))
67 0 : return;
68 :
69 0 : memcpy(buffer.get(), aDataBuff, aDataLen);
70 0 : buffer[aDataLen] = 0;
71 0 : const char16_t* start = reinterpret_cast<const char16_t*>(buffer.get());
72 : // recall that length takes length as characters, not bytes
73 0 : primitive->SetData(Substring(start, start + (aDataLen + 1) / 2));
74 : } else {
75 0 : const char16_t* start = reinterpret_cast<const char16_t*>(aDataBuff);
76 : // recall that length takes length as characters, not bytes
77 0 : primitive->SetData(Substring(start, start + (aDataLen / 2)));
78 : }
79 0 : NS_ADDREF(*aPrimitive = primitive);
80 : }
81 : }
82 :
83 : } // CreatePrimitiveForData
84 :
85 : //
86 : // CreatePrimitiveForCFHTML
87 : //
88 : // Platform specific CreatePrimitive, windows CF_HTML.
89 : //
90 : void
91 0 : nsPrimitiveHelpers :: CreatePrimitiveForCFHTML ( const void* aDataBuff,
92 : uint32_t* aDataLen, nsISupports** aPrimitive )
93 : {
94 0 : if (!aPrimitive)
95 0 : return;
96 :
97 : nsCOMPtr<nsISupportsString> primitive =
98 0 : do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
99 0 : if (!primitive)
100 0 : return;
101 :
102 : // We need to duplicate the input buffer, since the removal of linebreaks
103 : // might reallocte it.
104 0 : void* utf8 = moz_xmalloc(*aDataLen);
105 0 : if (!utf8)
106 0 : return;
107 0 : memcpy(utf8, aDataBuff, *aDataLen);
108 0 : int32_t signedLen = static_cast<int32_t>(*aDataLen);
109 0 : nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(kTextMime, &utf8, &signedLen);
110 0 : *aDataLen = signedLen;
111 :
112 0 : nsAutoString str(NS_ConvertUTF8toUTF16(reinterpret_cast<const char*>(utf8), *aDataLen));
113 0 : free(utf8);
114 0 : *aDataLen = str.Length() * sizeof(char16_t);
115 0 : primitive->SetData(str);
116 0 : NS_ADDREF(*aPrimitive = primitive);
117 : }
118 :
119 :
120 : //
121 : // CreateDataFromPrimitive
122 : //
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.
126 : //
127 : void
128 0 : nsPrimitiveHelpers :: CreateDataFromPrimitive ( const char* aFlavor, nsISupports* aPrimitive,
129 : void** aDataBuff, uint32_t aDataLen )
130 : {
131 0 : if ( !aDataBuff )
132 0 : return;
133 :
134 0 : *aDataBuff = nullptr;
135 :
136 0 : if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kCustomTypesMime) == 0) {
137 0 : nsCOMPtr<nsISupportsCString> plainText ( do_QueryInterface(aPrimitive) );
138 0 : if ( plainText ) {
139 0 : nsAutoCString data;
140 0 : plainText->GetData ( data );
141 0 : *aDataBuff = ToNewCString(data);
142 0 : }
143 : }
144 : else {
145 0 : nsCOMPtr<nsISupportsString> doubleByteText ( do_QueryInterface(aPrimitive) );
146 0 : if ( doubleByteText ) {
147 0 : nsAutoString data;
148 0 : doubleByteText->GetData ( data );
149 0 : *aDataBuff = ToNewUnicode(data);
150 : }
151 : }
152 :
153 : }
154 :
155 :
156 : //
157 : // ConvertPlatformToDOMLinebreaks
158 : //
159 : // Given some data, convert from the platform linebreaks into the LF expected by the
160 : // DOM. This will attempt to convert the data in place, but the buffer may still need to
161 : // be reallocated regardless (disposing the old buffer is taken care of internally, see
162 : // the note below).
163 : //
164 : // NOTE: this assumes that it can use 'free' to dispose of the old buffer.
165 : //
166 : nsresult
167 0 : nsLinebreakHelpers :: ConvertPlatformToDOMLinebreaks ( const char* inFlavor, void** ioData,
168 : int32_t* ioLengthInBytes )
169 : {
170 0 : NS_ASSERTION ( ioData && *ioData && ioLengthInBytes, "Bad Params");
171 0 : if ( !(ioData && *ioData && ioLengthInBytes) )
172 0 : return NS_ERROR_INVALID_ARG;
173 :
174 0 : nsresult retVal = NS_OK;
175 :
176 0 : if ( strcmp(inFlavor, kTextMime) == 0 || strcmp(inFlavor, kRTFMime) == 0) {
177 0 : char* buffAsChars = reinterpret_cast<char*>(*ioData);
178 0 : char* oldBuffer = buffAsChars;
179 0 : retVal = nsLinebreakConverter::ConvertLineBreaksInSitu ( &buffAsChars, nsLinebreakConverter::eLinebreakAny,
180 : nsLinebreakConverter::eLinebreakContent,
181 0 : *ioLengthInBytes, ioLengthInBytes );
182 0 : if ( NS_SUCCEEDED(retVal) ) {
183 0 : if ( buffAsChars != oldBuffer ) // check if buffer was reallocated
184 0 : free ( oldBuffer );
185 0 : *ioData = buffAsChars;
186 0 : }
187 : }
188 0 : else if ( strcmp(inFlavor, "image/jpeg") == 0 ) {
189 : // I'd assume we don't want to do anything for binary data....
190 : }
191 : else {
192 0 : char16_t* buffAsUnichar = reinterpret_cast<char16_t*>(*ioData);
193 0 : char16_t* oldBuffer = buffAsUnichar;
194 : int32_t newLengthInChars;
195 0 : retVal = nsLinebreakConverter::ConvertUnicharLineBreaksInSitu ( &buffAsUnichar, nsLinebreakConverter::eLinebreakAny,
196 : nsLinebreakConverter::eLinebreakContent,
197 0 : *ioLengthInBytes / sizeof(char16_t), &newLengthInChars );
198 0 : if ( NS_SUCCEEDED(retVal) ) {
199 0 : if ( buffAsUnichar != oldBuffer ) // check if buffer was reallocated
200 0 : free ( oldBuffer );
201 0 : *ioData = buffAsUnichar;
202 0 : *ioLengthInBytes = newLengthInChars * sizeof(char16_t);
203 : }
204 : }
205 :
206 0 : return retVal;
207 :
208 : } // ConvertPlatformToDOMLinebreaks
|