Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/widget/nsPrimitiveHelpers.cpp
Line
Count
Source (jump to first uncovered line)
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
nsPrimitiveHelpers :: CreatePrimitiveForData ( const nsACString& aFlavor, const void* aDataBuff,
45
                                                 uint32_t aDataLen, nsISupports** aPrimitive )
46
0
{
47
0
  if ( !aPrimitive )
48
0
    return;
49
0
50
0
  if ( aFlavor.EqualsLiteral(kTextMime) ||
51
0
       aFlavor.EqualsLiteral(kNativeHTMLMime) ||
52
0
       aFlavor.EqualsLiteral(kRTFMime) ||
53
0
       aFlavor.EqualsLiteral(kCustomTypesMime)) {
54
0
    nsCOMPtr<nsISupportsCString> primitive =
55
0
        do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
56
0
    if ( primitive ) {
57
0
      const char * start = reinterpret_cast<const char*>(aDataBuff);
58
0
      primitive->SetData(Substring(start, start + aDataLen));
59
0
      NS_ADDREF(*aPrimitive = primitive);
60
0
    }
61
0
  }
62
0
  else {
63
0
    nsCOMPtr<nsISupportsString> primitive =
64
0
        do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
65
0
    if (primitive ) {
66
0
      if (aDataLen % 2) {
67
0
        auto buffer = mozilla::MakeUnique<char[]>(aDataLen + 1);
68
0
        if (!MOZ_LIKELY(buffer))
69
0
          return;
70
0
71
0
        memcpy(buffer.get(), aDataBuff, aDataLen);
72
0
        buffer[aDataLen] = 0;
73
0
        const char16_t* start = reinterpret_cast<const char16_t*>(buffer.get());
74
0
        // recall that length takes length as characters, not bytes
75
0
        primitive->SetData(Substring(start, start + (aDataLen + 1) / 2));
76
0
      } else {
77
0
        const char16_t* start = reinterpret_cast<const char16_t*>(aDataBuff);
78
0
        // recall that length takes length as characters, not bytes
79
0
        primitive->SetData(Substring(start, start + (aDataLen / 2)));
80
0
      }
81
0
      NS_ADDREF(*aPrimitive = primitive);
82
0
    }
83
0
  }
84
0
85
0
} // CreatePrimitiveForData
86
87
//
88
// CreatePrimitiveForCFHTML
89
//
90
// Platform specific CreatePrimitive, windows CF_HTML.
91
//
92
void
93
nsPrimitiveHelpers :: CreatePrimitiveForCFHTML ( const void* aDataBuff,
94
                                                 uint32_t* aDataLen, nsISupports** aPrimitive )
95
0
{
96
0
  if (!aPrimitive)
97
0
    return;
98
0
99
0
  nsCOMPtr<nsISupportsString> primitive =
100
0
    do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
101
0
  if (!primitive)
102
0
    return;
103
0
104
0
  // We need to duplicate the input buffer, since the removal of linebreaks
105
0
  // might reallocte it.
106
0
  void* utf8 = moz_xmalloc(*aDataLen);
107
0
  memcpy(utf8, aDataBuff, *aDataLen);
108
0
  int32_t signedLen = static_cast<int32_t>(*aDataLen);
109
0
  nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(nsDependentCString(kTextMime), &utf8, &signedLen);
110
0
  *aDataLen = signedLen;
111
0
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
0
}
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
nsPrimitiveHelpers :: CreateDataFromPrimitive ( const nsACString& aFlavor, nsISupports* aPrimitive,
129
                                                   void** aDataBuff, uint32_t aDataLen )
130
0
{
131
0
  if ( !aDataBuff )
132
0
    return;
133
0
134
0
  *aDataBuff = nullptr;
135
0
136
0
  if (aFlavor.EqualsLiteral(kTextMime) ||
137
0
      aFlavor.EqualsLiteral(kCustomTypesMime)) {
138
0
    nsCOMPtr<nsISupportsCString> plainText ( do_QueryInterface(aPrimitive) );
139
0
    if ( plainText ) {
140
0
      nsAutoCString data;
141
0
      plainText->GetData ( data );
142
0
      *aDataBuff = ToNewCString(data);
143
0
    }
144
0
  }
145
0
  else {
146
0
    nsCOMPtr<nsISupportsString> doubleByteText ( do_QueryInterface(aPrimitive) );
147
0
    if ( doubleByteText ) {
148
0
      nsAutoString data;
149
0
      doubleByteText->GetData ( data );
150
0
      *aDataBuff = ToNewUnicode(data);
151
0
    }
152
0
  }
153
0
154
0
}
155
156
157
//
158
// ConvertPlatformToDOMLinebreaks
159
//
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
163
// the note below).
164
//
165
// NOTE: this assumes that it can use 'free' to dispose of the old buffer.
166
//
167
nsresult
168
nsLinebreakHelpers :: ConvertPlatformToDOMLinebreaks ( const nsACString& inFlavor, void** ioData,
169
                                                          int32_t* ioLengthInBytes )
170
0
{
171
0
  NS_ASSERTION ( ioData && *ioData && ioLengthInBytes, "Bad Params");
172
0
  if ( !(ioData && *ioData && ioLengthInBytes) )
173
0
    return NS_ERROR_INVALID_ARG;
174
0
175
0
  nsresult retVal = NS_OK;
176
0
177
0
  if (inFlavor.EqualsLiteral(kTextMime) ||
178
0
      inFlavor.EqualsLiteral(kRTFMime)) {
179
0
    char* buffAsChars = reinterpret_cast<char*>(*ioData);
180
0
    char* oldBuffer = buffAsChars;
181
0
    retVal = nsLinebreakConverter::ConvertLineBreaksInSitu ( &buffAsChars, nsLinebreakConverter::eLinebreakAny,
182
0
                                                              nsLinebreakConverter::eLinebreakContent,
183
0
                                                              *ioLengthInBytes, ioLengthInBytes );
184
0
    if ( NS_SUCCEEDED(retVal) ) {
185
0
      if ( buffAsChars != oldBuffer )             // check if buffer was reallocated
186
0
        free ( oldBuffer );
187
0
      *ioData = buffAsChars;
188
0
    }
189
0
  }
190
0
  else if (inFlavor.EqualsLiteral("image/jpeg")) {
191
0
    // I'd assume we don't want to do anything for binary data....
192
0
  }
193
0
  else {
194
0
    char16_t* buffAsUnichar = reinterpret_cast<char16_t*>(*ioData);
195
0
    char16_t* oldBuffer = buffAsUnichar;
196
0
    int32_t newLengthInChars;
197
0
    retVal = nsLinebreakConverter::ConvertUnicharLineBreaksInSitu ( &buffAsUnichar, nsLinebreakConverter::eLinebreakAny,
198
0
                                                                     nsLinebreakConverter::eLinebreakContent,
199
0
                                                                     *ioLengthInBytes / sizeof(char16_t), &newLengthInChars );
200
0
    if ( NS_SUCCEEDED(retVal) ) {
201
0
      if ( buffAsUnichar != oldBuffer )           // check if buffer was reallocated
202
0
        free ( oldBuffer );
203
0
      *ioData = buffAsUnichar;
204
0
      *ioLengthInBytes = newLengthInChars * sizeof(char16_t);
205
0
    }
206
0
  }
207
0
208
0
  return retVal;
209
0
210
0
} // ConvertPlatformToDOMLinebreaks