1use super::*;
4use super::super::regex::{self, RegExpData};
7
8pub(crate) fn text_encode(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
10 let s = arg(a, 0).to_js_string();
11 Ok(make_uint8array(it, s.as_bytes().to_vec()))
12}
13pub(crate) fn text_encode_into(_it: &mut Interp, _this: Value, a: &[Value]) -> Result<Value, Value> {
20 let source = arg(a, 0).to_js_string();
21 let dest = arg(a, 1);
22 let Value::Object(dest_obj) = &dest else {
23 return Ok(Value::Undefined);
24 };
25 let capacity = match &dest_obj.borrow().kind {
26 ObjKind::Array(items) => items.len(),
27 _ => 0,
28 };
29 let mut read_units = 0usize;
30 let mut written_bytes: alloc::vec::Vec<u8> = alloc::vec::Vec::new();
31 for c in source.chars() {
32 let mut buf = [0u8; 4];
33 let bytes = c.encode_utf8(&mut buf).as_bytes();
34 if written_bytes.len() + bytes.len() > capacity {
35 break;
36 }
37 written_bytes.extend_from_slice(bytes);
38 read_units += c.len_utf16();
39 }
40 if let ObjKind::Array(items) = &mut dest_obj.borrow_mut().kind {
41 for (i, b) in written_bytes.iter().enumerate() {
42 if let Some(slot) = items.get_mut(i) {
43 *slot = Value::Number(*b as f64);
44 }
45 }
46 }
47 let result = Obj::plain();
48 {
49 let mut b = result.borrow_mut();
50 b.props.insert("read".into(), Value::Number(read_units as f64));
51 b.props
52 .insert("written".into(), Value::Number(written_bytes.len() as f64));
53 }
54 Ok(Value::Object(result))
55}
56pub(crate) fn normalize_text_encoding_label(label: &str) -> &'static str {
60 match label.trim().to_lowercase().as_str() {
61 "utf-16le" | "utf-16" => "utf-16le",
62 "utf-16be" => "utf-16be",
63 _ => "utf-8",
64 }
65}
66pub(crate) fn decode_utf16_bytes(bytes: &[u8], little_endian: bool) -> alloc::string::String {
69 let units: alloc::vec::Vec<u16> = bytes
70 .chunks(2)
71 .map(|c| {
72 let lo = *c.first().unwrap_or(&0) as u16;
73 let hi = *c.get(1).unwrap_or(&0) as u16;
74 if little_endian {
75 lo | (hi << 8)
76 } else {
77 (lo << 8) | hi
78 }
79 })
80 .collect();
81 core::char::decode_utf16(units)
82 .map(|r| r.unwrap_or(core::char::REPLACEMENT_CHARACTER))
83 .collect()
84}
85pub(crate) fn utf8_incomplete_trailing_len(bytes: &[u8]) -> usize {
90 let len = bytes.len();
91 for back in 1..=3.min(len) {
92 let b = bytes[len - back];
93 if b & 0b1100_0000 == 0b1000_0000 {
94 continue; }
96 let needed = if b & 0b1000_0000 == 0 {
97 1
98 } else if b & 0b1110_0000 == 0b1100_0000 {
99 2
100 } else if b & 0b1111_0000 == 0b1110_0000 {
101 3
102 } else if b & 0b1111_1000 == 0b1111_0000 {
103 4
104 } else {
105 1 };
107 return if needed > back { back } else { 0 };
108 }
109 0
110}
111pub(crate) fn text_decode(_it: &mut Interp, this: Value, a: &[Value]) -> Result<Value, Value> {
120 let mut bytes: Vec<u8> = if let Value::Object(o) = &this {
121 match o.borrow().props.get("_pending") {
122 Some(Value::Object(p)) => match &p.borrow().kind {
123 ObjKind::Array(items) => items.iter().map(|v| v.to_number() as u8).collect(),
124 _ => Vec::new(),
125 },
126 _ => Vec::new(),
127 }
128 } else {
129 Vec::new()
130 };
131 let mut arg0_bytes_f64 = alloc::vec::Vec::new();
140 blob_part_bytes(&arg(a, 0), &mut arg0_bytes_f64);
141 bytes.extend(arg0_bytes_f64.iter().map(|v| *v as i64 as u8));
142 let stream = obj_prop(&arg(a, 1), "stream").map(|v| v.truthy()).unwrap_or(false);
143 let enc = if let Value::Object(o) = &this {
144 o.borrow()
145 .props
146 .get("encoding")
147 .map(|v| v.to_js_string())
148 .unwrap_or_else(|| String::from("utf-8"))
149 } else {
150 String::from("utf-8")
151 };
152 let pending_len = if stream {
153 match enc.as_str() {
154 "utf-16le" | "utf-16be" => bytes.len() % 2,
155 _ => utf8_incomplete_trailing_len(&bytes),
156 }
157 } else {
158 0
159 };
160 let ready_len = bytes.len() - pending_len;
161 let (ready, pending) = bytes.split_at(ready_len);
162 if let Value::Object(o) = &this {
163 let pending_vals: Vec<Value> = pending.iter().map(|&b| Value::Number(b as f64)).collect();
164 o.borrow_mut()
165 .props
166 .insert("_pending".into(), Value::Object(Obj::array(pending_vals)));
167 }
168 let decoded = match enc.as_str() {
169 "utf-16le" => decode_utf16_bytes(ready, true),
170 "utf-16be" => decode_utf16_bytes(ready, false),
171 _ => alloc::string::String::from_utf8_lossy(ready).into_owned(),
172 };
173 Ok(Value::str(decoded))
174}
175pub(crate) fn text_encoder_ctor(_it: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
176 let o = Obj::plain();
177 {
178 let mut b = o.borrow_mut();
179 b.props.insert("encoding".into(), Value::str("utf-8"));
180 b.props.insert("encode".into(), nv("encode", text_encode));
181 b.props
182 .insert("encodeInto".into(), nv("encodeInto", text_encode_into));
183 }
184 Ok(Value::Object(o))
185}
186pub(crate) fn text_decoder_ctor(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
189 let label = arg(a, 0).to_js_string();
190 let enc = if label.is_empty() {
191 "utf-8"
192 } else {
193 normalize_text_encoding_label(&label)
194 };
195 let o = Obj::plain();
196 {
197 let mut b = o.borrow_mut();
198 b.props.insert("encoding".into(), Value::str(enc));
199 b.props.insert("decode".into(), nv("decode", text_decode));
200 }
201 Ok(Value::Object(o))
202}
203
204pub(crate) fn url_create_object_url(it: &mut Interp, t: Value, _a: &[Value]) -> Result<Value, Value> {
212 let id = crypto_random_uuid(it, t, &[])?.to_js_string();
213 Ok(Value::str(alloc::format!("blob:{id}")))
214}
215pub(crate) fn url_revoke_object_url(_it: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
218 Ok(Value::Undefined)
219}
220pub(crate) fn crypto_random_uuid(_it: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
221 let mut bytes = [0u8; 16];
222 for b in bytes.iter_mut() {
223 *b = (next_rand_u64() & 0xff) as u8;
224 }
225 bytes[6] = (bytes[6] & 0x0f) | 0x40; bytes[8] = (bytes[8] & 0x3f) | 0x80; let mut s = String::new();
228 for (i, b) in bytes.iter().enumerate() {
229 if i == 4 || i == 6 || i == 8 || i == 10 {
230 s.push('-');
231 }
232 s.push_str(&format!("{:02x}", b));
233 }
234 Ok(Value::str(s))
235}
236pub(crate) fn crypto_get_random_values(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
243 let v = arg(a, 0);
244 if let Value::Object(o) = &v {
245 let kind = o
246 .borrow()
247 .props
248 .get("_ta_kind")
249 .map(|v| v.to_js_string())
250 .map(|tag| TaKind::from_name(tag.as_str()));
251 let mut b = o.borrow_mut();
252 if let ObjKind::Array(items) = &mut b.kind {
253 for it2 in items.iter_mut() {
254 let raw = Value::Number(next_rand_u64() as f64);
255 *it2 = Value::Number(match kind {
256 Some(k) => k.convert(&raw),
257 None => (next_rand_u64() & 0xff) as f64,
258 });
259 }
260 }
261 }
262 Ok(v)
263}
264
265pub(crate) fn deep_clone_value(
273 it: &mut Interp,
274 v: &Value,
275 seen: &mut Vec<(super::super::value::ObjRef, super::super::value::ObjRef)>,
276) -> Result<Value, Value> {
277 deep_clone_value_depth(it, v, seen, 0)
278}
279
280fn deep_clone_value_depth(
281 it: &mut Interp,
282 v: &Value,
283 seen: &mut Vec<(super::super::value::ObjRef, super::super::value::ObjRef)>,
284 depth: usize,
285) -> Result<Value, Value> {
286 if depth > 30 {
295 return Err(make_dom_exception("DataCloneError", "Exceeded maximum call stack size / nesting depth limit"));
296 }
297 let error_proto = match it.global.borrow().vars.get("Error") {
298 Some(Value::Object(ctor)) => match ctor.borrow().props.get("prototype") {
299 Some(Value::Object(p)) => Some(p.clone()),
300 _ => None,
301 },
302 _ => None,
303 };
304 match v {
305 Value::Object(o) => {
306 if let Some((_, cloned)) = seen.iter().find(|(orig, _)| Rc::ptr_eq(orig, o)) {
307 return Ok(Value::Object(cloned.clone()));
308 }
309 if o.borrow().is_callable() {
318 return Err(make_dom_exception("DataCloneError", "could not be cloned"));
319 }
320 if matches!(&o.borrow().kind, ObjKind::PromiseObj(_)) {
329 return Err(make_dom_exception("DataCloneError", "could not be cloned"));
330 }
331 if matches!(&o.borrow().kind, ObjKind::Proxy { .. }) {
340 let target = unwrap_proxy_target(o);
341 let cloned = deep_clone_value_depth(it, &Value::Object(target), seen, depth + 1)?;
342 if let Value::Object(c) = &cloned {
343 seen.push((o.clone(), c.clone()));
344 }
345 return Ok(cloned);
346 }
347 if let ObjKind::DateObj(ms) = &o.borrow().kind {
354 return Ok(Value::Object(Obj::date_obj(*ms)));
355 }
356 let regex_info = match &o.borrow().kind {
357 ObjKind::RegExpObj(r) => {
358 let d = r.borrow();
359 Some((d.re.source.clone(), d.re.flags.clone(), d.last_index))
360 }
361 _ => None,
362 };
363 if let Some((source, flags, last_index)) = regex_info {
364 let re = regex::Regex::new(&source, &flags);
365 return Ok(Value::Object(Obj::regexp(RegExpData { re, last_index })));
366 }
367 let is_array = matches!(&o.borrow().kind, ObjKind::Array(_));
368 if is_array {
369 let ta_kind_tag = o.borrow().props.get("_ta_kind").map(|v| v.to_js_string());
376 if let Some(tag) = ta_kind_tag {
377 let items = match &o.borrow().kind {
378 ObjKind::Array(items) => items.iter().map(|v| v.to_number()).collect(),
379 _ => unreachable!(),
380 };
381 let new_val = make_typed_array(it, items, TaKind::from_name(tag.as_str()));
382 if let Value::Object(new) = &new_val {
383 seen.push((o.clone(), new.clone()));
384 }
385 return Ok(new_val);
386 }
387 let new = Obj::array(Vec::new());
388 seen.push((o.clone(), new.clone()));
389 let items = match &o.borrow().kind {
390 ObjKind::Array(items) => items.clone(),
391 _ => unreachable!(),
392 };
393 let mut cloned_items: Vec<Value> = Vec::with_capacity(items.len());
394 for x in &items {
395 cloned_items.push(deep_clone_value_depth(it, x, seen, depth + 1)?);
396 }
397 if let ObjKind::Array(v) = &mut new.borrow_mut().kind {
398 *v = cloned_items;
399 }
400 return Ok(Value::Object(new));
401 }
402 let is_map = matches!(&o.borrow().kind, ObjKind::MapObj(_));
406 if is_map {
407 let new = Obj::map_obj(Vec::new());
408 seen.push((o.clone(), new.clone()));
409 let entries = match &o.borrow().kind {
410 ObjKind::MapObj(e) => e.clone(),
411 _ => unreachable!(),
412 };
413 let mut cloned: Vec<(Value, Value)> = Vec::with_capacity(entries.len());
414 for (k, val) in &entries {
415 let ck = deep_clone_value_depth(it, k, seen, depth + 1)?;
416 let cv = deep_clone_value_depth(it, val, seen, depth + 1)?;
417 cloned.push((ck, cv));
418 }
419 if let ObjKind::MapObj(e) = &mut new.borrow_mut().kind {
420 *e = cloned;
421 }
422 return Ok(Value::Object(new));
423 }
424 let is_set = matches!(&o.borrow().kind, ObjKind::SetObj(_));
425 if is_set {
426 let new = Obj::set_obj(Vec::new());
427 seen.push((o.clone(), new.clone()));
428 let items = match &o.borrow().kind {
429 ObjKind::SetObj(s) => s.clone(),
430 _ => unreachable!(),
431 };
432 let mut cloned: Vec<Value> = Vec::with_capacity(items.len());
433 for x in &items {
434 cloned.push(deep_clone_value_depth(it, x, seen, depth + 1)?);
435 }
436 if let ObjKind::SetObj(s) = &mut new.borrow_mut().kind {
437 *s = cloned;
438 }
439 return Ok(Value::Object(new));
440 }
441 if let Some(Value::Object(bytes_obj)) = o.borrow().props.get("_blob_bytes").cloned() {
448 let bytes: alloc::vec::Vec<f64> = match &bytes_obj.borrow().kind {
449 ObjKind::Array(items) => items.iter().map(|v| v.to_number()).collect(),
450 _ => alloc::vec::Vec::new(),
451 };
452 let mime = o.borrow().props.get("type").map(|v| v.to_js_string()).unwrap_or_default();
453 let file_meta = o.borrow().props.get("name").cloned().map(|name| {
463 let last_modified =
464 o.borrow().props.get("lastModified").cloned().unwrap_or(Value::Number(0.0));
465 let webkit_relative_path =
466 o.borrow().props.get("webkitRelativePath").cloned().unwrap_or_else(|| Value::str(""));
467 (name, last_modified, webkit_relative_path)
468 });
469 let new_val = make_blob(bytes, mime);
470 if let (Value::Object(new), Some((name, last_modified, webkit_relative_path))) = (&new_val, file_meta) {
471 new.borrow_mut().props.insert("name".into(), name);
472 new.borrow_mut().props.insert("lastModified".into(), last_modified);
473 new.borrow_mut().props.insert("webkitRelativePath".into(), webkit_relative_path);
474 }
475 if let Value::Object(new) = &new_val {
476 seen.push((o.clone(), new.clone()));
477 }
478 return Ok(new_val);
479 }
480 if let Some(Value::Object(bytes_obj)) = o.borrow().props.get("_dv_bytes").cloned() {
481 let byte_values: alloc::vec::Vec<Value> = match &bytes_obj.borrow().kind {
482 ObjKind::Array(items) => items.clone(),
483 _ => alloc::vec::Vec::new(),
484 };
485 let new_buffer = make_arraybuffer_with_bytes(byte_values.iter().map(|v| v.to_number()).collect());
486 let new_val = make_dataview(new_buffer, 0, byte_values);
487 if let Value::Object(new) = &new_val {
488 seen.push((o.clone(), new.clone()));
489 }
490 return Ok(new_val);
491 }
492 let is_arraybuffer = {
496 let b = o.borrow();
497 b.props.contains_key("byteLength")
498 && matches!(b.props.get("slice"), Some(Value::Object(f)) if f.borrow().is_callable())
499 };
500 if is_arraybuffer {
501 let is_resizable = matches!(o.borrow().props.get("resizable"), Some(Value::Bool(true)));
509 let max_byte_length = o.borrow().props.get("maxByteLength").map(|v| v.to_number() as usize);
510 let bytes_prop = o.borrow().props.get("_bytes").cloned();
511 let byte_length = o
512 .borrow()
513 .props
514 .get("byteLength")
515 .map(|v| v.to_number() as usize)
516 .unwrap_or(0);
517 let new_val = make_arraybuffer_ex(byte_length, if is_resizable { max_byte_length } else { None });
518 if let (Value::Object(new), Some(Value::Object(bytes_obj))) = (&new_val, &bytes_prop) {
519 let bytes: Vec<Value> = match &bytes_obj.borrow().kind {
520 ObjKind::Array(items) => items.clone(),
521 _ => Vec::new(),
522 };
523 new.borrow_mut().props.insert("_bytes".into(), Value::Object(Obj::array(bytes)));
524 }
525 if let Value::Object(new) = &new_val {
526 seen.push((o.clone(), new.clone()));
527 }
528 return Ok(new_val);
529 }
530 let is_error = error_proto.as_ref().is_some_and(|ep| {
540 let mut cur = o.borrow().proto.clone();
541 let mut guard = 0;
542 while let Some(c) = cur {
543 if Rc::ptr_eq(&c, ep) {
544 return true;
545 }
546 cur = c.borrow().proto.clone();
547 guard += 1;
548 if guard > 1000 {
549 break;
550 }
551 }
552 false
553 });
554 let new = Obj::plain();
555 if is_error {
556 new.borrow_mut().proto = o.borrow().proto.clone();
557 }
558 seen.push((o.clone(), new.clone()));
559 let props: Vec<(String, Value)> =
560 o.borrow().props.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
561 for (k, val) in props {
562 let cv = deep_clone_value_depth(it, &val, seen, depth + 1)?;
563 new.borrow_mut().props.insert(k, cv);
564 }
565 Ok(Value::Object(new))
566 }
567 other => Ok(other.clone()),
568 }
569}
570pub(crate) fn structured_clone(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
578 let mut seen = Vec::new();
579 let result = deep_clone_value(it, &arg(a, 0), &mut seen)?;
580 if let Value::Object(opts) = arg(a, 1) {
581 let transfer_list = opts.borrow().props.get("transfer").cloned();
582 if let Some(list) = transfer_list {
583 for item in this_items(&list) {
584 if let Value::Object(o) = &item {
585 let is_arraybuffer = {
586 let b = o.borrow();
587 b.props.contains_key("byteLength")
588 && matches!(b.props.get("slice"), Some(Value::Object(f)) if f.borrow().is_callable())
589 };
590 if is_arraybuffer {
591 let mut b = o.borrow_mut();
592 b.props.insert("detached".into(), Value::Bool(true));
593 b.props.shift_remove("_bytes");
594 }
595 }
596 }
597 }
598 }
599 Ok(result)
600}
601