Source code

Revision control

Other Tools

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