Source code

Revision control

Other Tools

1
// Copyright 2015-2016 Mozilla Foundation. See the COPYRIGHT
2
// file at the top-level directory of this distribution.
3
//
4
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
7
// option. This file may not be copied, modified, or distributed
8
// except according to those terms.
9
10
// Adapted from third_party/rust/encoding_rs/src/lib.rs, so the
11
// "top-level directory" in the above notice refers to
12
// third_party/rust/encoding_rs/.
13
14
extern crate encoding_rs;
15
extern crate nserror;
16
extern crate nsstring;
17
18
use encoding_rs::*;
19
use nserror::*;
20
use nsstring::*;
21
use std::slice;
22
23
/// Takes `Option<usize>`, the destination string and a value
24
/// to return on failure and tries to start a bulk write of the
25
/// destination string with the capacity given by the `usize`
26
/// wrapped in the first argument. Returns the bulk write
27
/// handle.
28
macro_rules! try_start_bulk_write {
29
($needed:expr,
30
$dst:ident,
31
$ret:expr) => ({
32
let needed = match $needed {
33
Some(needed) => {
34
needed
35
}
36
None => {
37
return $ret;
38
}
39
};
40
match unsafe { $dst.bulk_write(needed, 0, false) } {
41
Err(_) => {
42
return $ret;
43
},
44
Ok(handle) => {
45
handle
46
}
47
}
48
})
49
}
50
51
#[no_mangle]
52
pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring(encoding: *mut *const Encoding,
53
src: *const u8,
54
src_len: usize,
55
dst: *mut nsAString)
56
-> nsresult {
57
let (rv, enc) = decode_to_nsstring(&**encoding, slice::from_raw_parts(src, src_len), &mut *dst);
58
*encoding = enc as *const Encoding;
59
rv
60
}
61
62
pub fn decode_to_nsstring(encoding: &'static Encoding,
63
src: &[u8],
64
dst: &mut nsAString)
65
-> (nsresult, &'static Encoding) {
66
if let Some((enc, bom_length)) = Encoding::for_bom(src) {
67
return (decode_to_nsstring_without_bom_handling(enc, &src[bom_length..], dst), enc);
68
}
69
(decode_to_nsstring_without_bom_handling(encoding, src, dst), encoding)
70
}
71
72
#[no_mangle]
73
pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring_with_bom_removal(encoding: *const Encoding, src: *const u8, src_len: usize, dst: *mut nsAString) -> nsresult{
74
decode_to_nsstring_with_bom_removal(&*encoding, slice::from_raw_parts(src, src_len), &mut *dst)
75
}
76
77
pub fn decode_to_nsstring_with_bom_removal(encoding: &'static Encoding,
78
src: &[u8],
79
dst: &mut nsAString)
80
-> nsresult {
81
let without_bom = if encoding == UTF_8 && src.starts_with(b"\xEF\xBB\xBF") {
82
&src[3..]
83
} else if (encoding == UTF_16LE && src.starts_with(b"\xFF\xFE")) ||
84
(encoding == UTF_16BE && src.starts_with(b"\xFE\xFF")) {
85
&src[2..]
86
} else {
87
src
88
};
89
decode_to_nsstring_without_bom_handling(encoding, without_bom, dst)
90
}
91
92
#[no_mangle]
93
pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring_without_bom_handling(encoding: *const Encoding, src: *const u8, src_len: usize, dst: *mut nsAString) -> nsresult{
94
decode_to_nsstring_without_bom_handling(&*encoding,
95
slice::from_raw_parts(src, src_len),
96
&mut *dst)
97
}
98
99
pub fn decode_to_nsstring_without_bom_handling(encoding: &'static Encoding,
100
src: &[u8],
101
dst: &mut nsAString)
102
-> nsresult {
103
let mut decoder = encoding.new_decoder_without_bom_handling();
104
let mut handle = try_start_bulk_write!(decoder.max_utf16_buffer_length(src.len()),
105
dst,
106
NS_ERROR_OUT_OF_MEMORY);
107
let (result, read, written, had_errors) = decoder.decode_to_utf16(src, handle.as_mut_slice(), true);
108
debug_assert_eq!(result, CoderResult::InputEmpty);
109
debug_assert_eq!(read, src.len());
110
debug_assert!(written <= handle.as_mut_slice().len());
111
let _ = handle.finish(written, true);
112
if had_errors {
113
return NS_OK_HAD_REPLACEMENTS;
114
}
115
NS_OK
116
}
117
118
#[no_mangle]
119
pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring_without_bom_handling_and_without_replacement
120
(encoding: *const Encoding,
121
src: *const u8,
122
src_len: usize,
123
dst: *mut nsAString)
124
-> nsresult {
125
decode_to_nsstring_without_bom_handling_and_without_replacement(&*encoding,
126
slice::from_raw_parts(src,
127
src_len),
128
&mut *dst)
129
}
130
131
pub fn decode_to_nsstring_without_bom_handling_and_without_replacement(encoding: &'static Encoding, src: &[u8], dst: &mut nsAString) -> nsresult{
132
let mut decoder = encoding.new_decoder_without_bom_handling();
133
let mut handle = try_start_bulk_write!(decoder.max_utf16_buffer_length(src.len()),
134
dst,
135
NS_ERROR_OUT_OF_MEMORY);
136
let (result, read, written) = decoder
137
.decode_to_utf16_without_replacement(src, handle.as_mut_slice(), true);
138
match result {
139
DecoderResult::InputEmpty => {
140
debug_assert_eq!(read, src.len());
141
debug_assert!(written <= handle.as_mut_slice().len());
142
let _ = handle.finish(written, true);
143
NS_OK
144
}
145
DecoderResult::Malformed(_, _) => {
146
// Let handle's drop() run
147
NS_ERROR_UDEC_ILLEGALINPUT
148
}
149
DecoderResult::OutputFull => unreachable!(),
150
}
151
}
152
153
#[no_mangle]
154
pub unsafe extern "C" fn mozilla_encoding_encode_from_utf16(encoding: *mut *const Encoding,
155
src: *const u16,
156
src_len: usize,
157
dst: *mut nsACString)
158
-> nsresult {
159
let (rv, enc) = encode_from_utf16(&**encoding, slice::from_raw_parts(src, src_len), &mut *dst);
160
*encoding = enc as *const Encoding;
161
rv
162
}
163
164
pub fn encode_from_utf16(encoding: &'static Encoding,
165
src: &[u16],
166
dst: &mut nsACString)
167
-> (nsresult, &'static Encoding) {
168
let output_encoding = encoding.output_encoding();
169
let mut encoder = output_encoding.new_encoder();
170
let mut handle = try_start_bulk_write!(encoder.max_buffer_length_from_utf16_if_no_unmappables(src.len()),
171
dst,
172
(NS_ERROR_OUT_OF_MEMORY, output_encoding));
173
174
let mut total_read = 0;
175
let mut total_written = 0;
176
let mut total_had_errors = false;
177
loop {
178
let (result, read, written, had_errors) = encoder
179
.encode_from_utf16(&src[total_read..],
180
&mut (handle.as_mut_slice())[total_written..],
181
true);
182
total_read += read;
183
total_written += written;
184
total_had_errors |= had_errors;
185
match result {
186
CoderResult::InputEmpty => {
187
debug_assert_eq!(total_read, src.len());
188
debug_assert!(total_written <= handle.as_mut_slice().len());
189
let _ = handle.finish(total_written, true);
190
if total_had_errors {
191
return (NS_OK_HAD_REPLACEMENTS, output_encoding);
192
}
193
return (NS_OK, output_encoding);
194
}
195
CoderResult::OutputFull => {
196
if let Some(needed) =
197
checked_add(total_written,
198
encoder.max_buffer_length_from_utf16_if_no_unmappables(src.len() -
199
total_read)) {
200
if unsafe { handle.restart_bulk_write(needed, total_written, false).is_ok() } {
201
continue;
202
}
203
}
204
return (NS_ERROR_OUT_OF_MEMORY, output_encoding);
205
}
206
}
207
}
208
}
209
210
#[no_mangle]
211
pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring(encoding: *mut *const Encoding,
212
src: *const nsACString,
213
dst: *mut nsACString)
214
-> nsresult {
215
debug_assert_ne!(src as usize, dst as usize);
216
let (rv, enc) = decode_to_nscstring(&**encoding, &*src, &mut *dst);
217
*encoding = enc as *const Encoding;
218
rv
219
}
220
221
pub fn decode_to_nscstring(encoding: &'static Encoding,
222
src: &nsACString,
223
dst: &mut nsACString)
224
-> (nsresult, &'static Encoding) {
225
if let Some((enc, bom_length)) = Encoding::for_bom(src) {
226
return (decode_from_slice_to_nscstring_without_bom_handling(enc,
227
&src[bom_length..],
228
dst,
229
0),
230
enc);
231
}
232
(decode_to_nscstring_without_bom_handling(encoding, src, dst), encoding)
233
}
234
235
#[no_mangle]
236
pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring_with_bom_removal(encoding: *const Encoding, src: *const nsACString, dst: *mut nsACString) -> nsresult{
237
debug_assert_ne!(src as usize, dst as usize);
238
decode_to_nscstring_with_bom_removal(&*encoding, &*src, &mut *dst)
239
}
240
241
pub fn decode_to_nscstring_with_bom_removal(encoding: &'static Encoding,
242
src: &nsACString,
243
dst: &mut nsACString)
244
-> nsresult {
245
let without_bom = if encoding == UTF_8 && src.starts_with(b"\xEF\xBB\xBF") {
246
&src[3..]
247
} else if (encoding == UTF_16LE && src.starts_with(b"\xFF\xFE")) ||
248
(encoding == UTF_16BE && src.starts_with(b"\xFE\xFF")) {
249
&src[2..]
250
} else {
251
return decode_to_nscstring_without_bom_handling(encoding, src, dst);
252
};
253
decode_from_slice_to_nscstring_without_bom_handling(encoding, without_bom, dst, 0)
254
}
255
256
#[no_mangle]
257
pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring_without_bom_handling(encoding: *const Encoding, src: *const nsACString, dst: *mut nsACString) -> nsresult{
258
debug_assert_ne!(src as usize, dst as usize);
259
decode_to_nscstring_without_bom_handling(&*encoding, &*src, &mut *dst)
260
}
261
262
pub fn decode_to_nscstring_without_bom_handling(encoding: &'static Encoding,
263
src: &nsACString,
264
dst: &mut nsACString)
265
-> nsresult {
266
let bytes = &src[..];
267
let valid_up_to = if encoding == UTF_8 {
268
Encoding::utf8_valid_up_to(bytes)
269
} else if encoding.is_ascii_compatible() {
270
Encoding::ascii_valid_up_to(bytes)
271
} else if encoding == ISO_2022_JP {
272
Encoding::iso_2022_jp_ascii_valid_up_to(bytes)
273
} else {
274
return decode_from_slice_to_nscstring_without_bom_handling(encoding, src, dst, 0);
275
};
276
if valid_up_to == bytes.len() {
277
if dst.fallible_assign(src).is_err() {
278
return NS_ERROR_OUT_OF_MEMORY;
279
}
280
return NS_OK;
281
}
282
decode_from_slice_to_nscstring_without_bom_handling(encoding, src, dst, valid_up_to)
283
}
284
285
#[no_mangle]
286
pub unsafe extern "C" fn mozilla_encoding_decode_from_slice_to_nscstring_without_bom_handling(encoding: *const Encoding, src: *const u8, src_len: usize, dst: *mut nsACString, already_validated: usize) -> nsresult {
287
decode_from_slice_to_nscstring_without_bom_handling(&*encoding, slice::from_raw_parts(src, src_len), &mut *dst, already_validated)
288
}
289
290
fn decode_from_slice_to_nscstring_without_bom_handling(encoding: &'static Encoding,
291
src: &[u8],
292
dst: &mut nsACString,
293
already_validated: usize)
294
-> nsresult {
295
let bytes = src;
296
let mut decoder = encoding.new_decoder_without_bom_handling();
297
let mut handle = try_start_bulk_write!(Some(src.len()),
298
dst,
299
NS_ERROR_OUT_OF_MEMORY);
300
301
if already_validated != 0 {
302
&mut (handle.as_mut_slice())[..already_validated].copy_from_slice(&bytes[..already_validated]);
303
}
304
let mut total_read = already_validated;
305
let mut total_written = already_validated;
306
let mut total_had_errors = false;
307
loop {
308
let (result, read, written, had_errors) =
309
decoder.decode_to_utf8(&bytes[total_read..],
310
&mut (handle.as_mut_slice())[total_written..],
311
true);
312
total_read += read;
313
total_written += written;
314
total_had_errors |= had_errors;
315
match result {
316
CoderResult::InputEmpty => {
317
debug_assert_eq!(total_read, bytes.len());
318
let _ = handle.finish(total_written, true);
319
if total_had_errors {
320
return NS_OK_HAD_REPLACEMENTS;
321
}
322
return NS_OK;
323
}
324
CoderResult::OutputFull => {
325
// Allocate for the worst case. That is, we should come
326
// here at most once per invocation of this method.
327
if let Some(needed) =
328
checked_add(total_written,
329
decoder.max_utf8_buffer_length(bytes.len() -
330
total_read)) {
331
if unsafe { handle.restart_bulk_write(needed, total_written, false).is_ok() } {
332
continue;
333
}
334
}
335
return NS_ERROR_OUT_OF_MEMORY;
336
}
337
}
338
}
339
}
340
341
#[no_mangle]
342
pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring_without_bom_handling_and_without_replacement
343
(encoding: *const Encoding,
344
src: *const nsACString,
345
dst: *mut nsACString)
346
-> nsresult {
347
decode_to_nscstring_without_bom_handling_and_without_replacement(&*encoding, &*src, &mut *dst)
348
}
349
350
pub fn decode_to_nscstring_without_bom_handling_and_without_replacement(encoding: &'static Encoding, src: &nsACString, dst: &mut nsACString) -> nsresult{
351
let bytes = &src[..];
352
if encoding == UTF_8 {
353
let valid_up_to = Encoding::utf8_valid_up_to(bytes);
354
if valid_up_to == bytes.len() {
355
if dst.fallible_assign(src).is_err() {
356
return NS_ERROR_OUT_OF_MEMORY;
357
}
358
return NS_OK;
359
}
360
return NS_ERROR_UDEC_ILLEGALINPUT;
361
}
362
let valid_up_to = if encoding.is_ascii_compatible() {
363
Encoding::ascii_valid_up_to(bytes)
364
} else if encoding == ISO_2022_JP {
365
Encoding::iso_2022_jp_ascii_valid_up_to(bytes)
366
} else {
367
0
368
};
369
if valid_up_to == bytes.len() {
370
if dst.fallible_assign(src).is_err() {
371
return NS_ERROR_OUT_OF_MEMORY;
372
}
373
return NS_OK;
374
}
375
let mut decoder = encoding.new_decoder_without_bom_handling();
376
let mut handle = try_start_bulk_write!(checked_add(valid_up_to,
377
decoder.max_utf8_buffer_length_without_replacement(bytes.len() -
378
valid_up_to)),
379
dst,
380
NS_ERROR_OUT_OF_MEMORY);
381
let (result, read, written) = {
382
let dest = handle.as_mut_slice();
383
dest[..valid_up_to].copy_from_slice(&bytes[..valid_up_to]);
384
decoder
385
.decode_to_utf8_without_replacement(&src[valid_up_to..], &mut dest[valid_up_to..], true)
386
};
387
match result {
388
DecoderResult::InputEmpty => {
389
debug_assert_eq!(valid_up_to + read, src.len());
390
debug_assert!(valid_up_to + written <= handle.as_mut_slice().len());
391
let _ = handle.finish(valid_up_to + written, true);
392
NS_OK
393
}
394
DecoderResult::Malformed(_, _) => {
395
// let handle's drop() run
396
NS_ERROR_UDEC_ILLEGALINPUT
397
}
398
DecoderResult::OutputFull => unreachable!(),
399
}
400
}
401
402
#[no_mangle]
403
pub unsafe extern "C" fn mozilla_encoding_encode_from_nscstring(encoding: *mut *const Encoding,
404
src: *const nsACString,
405
dst: *mut nsACString)
406
-> nsresult {
407
let (rv, enc) = encode_from_nscstring(&**encoding, &*src, &mut *dst);
408
*encoding = enc as *const Encoding;
409
rv
410
}
411
412
pub fn encode_from_nscstring(encoding: &'static Encoding,
413
src: &nsACString,
414
dst: &mut nsACString)
415
-> (nsresult, &'static Encoding) {
416
let output_encoding = encoding.output_encoding();
417
let bytes = &src[..];
418
if output_encoding == UTF_8 {
419
let valid_up_to = Encoding::utf8_valid_up_to(bytes);
420
if valid_up_to == bytes.len() {
421
if dst.fallible_assign(src).is_err() {
422
return (NS_ERROR_OUT_OF_MEMORY, output_encoding);
423
}
424
return (NS_OK, output_encoding);
425
}
426
return (NS_ERROR_UDEC_ILLEGALINPUT, output_encoding);
427
}
428
let valid_up_to = if output_encoding == ISO_2022_JP {
429
Encoding::iso_2022_jp_ascii_valid_up_to(bytes)
430
} else {
431
debug_assert!(output_encoding.is_ascii_compatible());
432
Encoding::ascii_valid_up_to(bytes)
433
};
434
if valid_up_to == bytes.len() {
435
if dst.fallible_assign(src).is_err() {
436
return (NS_ERROR_OUT_OF_MEMORY, output_encoding);
437
}
438
return (NS_OK, output_encoding);
439
}
440
441
// Encoder requires valid UTF-8. Using std instead of encoding_rs
442
// to avoid unsafe blocks.
443
let trail = if let Ok(trail) = ::std::str::from_utf8(&bytes[valid_up_to..]) {
444
trail
445
} else {
446
return (NS_ERROR_UDEC_ILLEGALINPUT, output_encoding);
447
};
448
449
let mut encoder = output_encoding.new_encoder();
450
let mut handle = try_start_bulk_write!(checked_add(valid_up_to,
451
encoder.max_buffer_length_from_utf8_if_no_unmappables(trail.len())),
452
dst,
453
(NS_ERROR_OUT_OF_MEMORY, output_encoding));
454
455
if valid_up_to != 0 {
456
// to_mut() shouldn't fail right after setting length.
457
&mut (handle.as_mut_slice())[..valid_up_to].copy_from_slice(&bytes[..valid_up_to]);
458
}
459
460
// `total_read` tracks `trail` only but `total_written` tracks the overall situation!
461
// This asymmetry is here, because trail is materialized as `str` without resorting
462
// to unsafe code here.
463
let mut total_read = 0;
464
let mut total_written = valid_up_to;
465
let mut total_had_errors = false;
466
loop {
467
let (result, read, written, had_errors) = encoder
468
.encode_from_utf8(&trail[total_read..],
469
&mut (handle.as_mut_slice())[total_written..],
470
true);
471
total_read += read;
472
total_written += written;
473
total_had_errors |= had_errors;
474
match result {
475
CoderResult::InputEmpty => {
476
debug_assert_eq!(valid_up_to + total_read, src.len());
477
debug_assert!(total_written <= handle.as_mut_slice().len());
478
let _ = handle.finish(total_written, true);
479
if total_had_errors {
480
return (NS_OK_HAD_REPLACEMENTS, output_encoding);
481
}
482
return (NS_OK, output_encoding);
483
}
484
CoderResult::OutputFull => {
485
if let Some(needed) =
486
checked_add(total_written,
487
encoder
488
.max_buffer_length_from_utf8_if_no_unmappables(trail.len() -
489
total_read)) {
490
if unsafe { handle.restart_bulk_write(needed, total_written, false).is_ok() } {
491
continue;
492
}
493
}
494
return (NS_ERROR_OUT_OF_MEMORY, output_encoding);
495
}
496
}
497
}
498
}
499
500
#[inline(always)]
501
fn checked_add(num: usize, opt: Option<usize>) -> Option<usize> {
502
if let Some(n) = opt {
503
n.checked_add(num)
504
} else {
505
None
506
}
507
}