Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ boa_macros = { version = "~1.0.0-dev", path = "core/macros" }
boa_parser = { version = "~1.0.0-dev", path = "core/parser" }
boa_runtime = { version = "~1.0.0-dev", path = "core/runtime" }
boa_string = { version = "~1.0.0-dev", path = "core/string" }
boa_wintertc = { version = "~1.0.0-dev", path = "core/wintertc" }

# Utility Repo Crates
tag_ptr = { version = "~0.1.0", path = "utils/tag_ptr" }
Expand Down
2 changes: 1 addition & 1 deletion core/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ rust-version.workspace = true

[dependencies]
boa_engine.workspace = true
base64.workspace = true
boa_gc.workspace = true
boa_wintertc.workspace = true
bus = { workspace = true, optional = true }
bytemuck.workspace = true
either = { workspace = true, optional = true }
Expand Down
82 changes: 0 additions & 82 deletions core/runtime/src/base64/mod.rs

This file was deleted.

2 changes: 1 addition & 1 deletion core/runtime/src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub struct Base64Extension;

impl RuntimeExtension for Base64Extension {
fn register(self, realm: Option<Realm>, context: &mut Context) -> JsResult<()> {
crate::base64::register(realm, context)
boa_wintertc::base64::register(realm, context)
}
}

Expand Down
8 changes: 7 additions & 1 deletion core/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,15 @@
clippy::let_unit_value
)]

pub mod base64;
pub mod console;

/// Base64 utility methods (`atob` and `btoa`), re-exported from [`boa_wintertc`].
///
/// This API is part of the `WinterTC` (TC55) Minimum Common Web API and is implemented in
/// `boa_wintertc`. It is re-exported here so `boa_runtime` users keep a single import path.
#[doc(inline)]
pub use boa_wintertc::base64;

#[doc(inline)]
pub use console::{Console, ConsoleState, DefaultLogger, Logger, NullLogger};

Expand Down
6 changes: 6 additions & 0 deletions core/wintertc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ rust-version.workspace = true

[dependencies]
boa_engine.workspace = true
base64.workspace = true

[dev-dependencies]
indoc.workspace = true
textwrap.workspace = true
futures-lite.workspace = true

[lints]
workspace = true
Expand Down
91 changes: 77 additions & 14 deletions core/wintertc/src/base64/mod.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,86 @@
//! TC55 `atob` / `btoa` implementation.
//! Base64 utility methods (`atob` and `btoa`).
//!
//! Spec: <https://html.spec.whatwg.org/multipage/webappapis.html#atob>
//! See <https://html.spec.whatwg.org/multipage/webappapis.html#atob>.
//!
//! # TC55 Status
//!
//! `atob` and `btoa` are required in the `WinterTC` TC55 Minimum Common Web API.
//!
//! # TODO
//!
//! - Migrate `atob` and `btoa` from `boa_runtime::base64`.
#![allow(clippy::needless_pass_by_value)]

use boa_engine::realm::Realm;
use boa_engine::{Context, JsResult, boa_module};

#[cfg(test)]
mod tests;

/// A forgiving Base64 engine that accepts input with or without padding,
/// matching the [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode)
/// algorithm used by `atob`.
const FORGIVING: base64::engine::GeneralPurpose = base64::engine::GeneralPurpose::new(
&base64::alphabet::STANDARD,
base64::engine::general_purpose::GeneralPurposeConfig::new()
.with_decode_padding_mode(base64::engine::DecodePaddingMode::Indifferent),
);

/// JavaScript module containing the `atob` and `btoa` functions.
#[boa_module]
pub mod js_module {
use super::FORGIVING;
use base64::Engine as _;
use boa_engine::{JsResult, js_error};

/// The [`btoa()`][mdn] method creates a Base64-encoded ASCII string from
/// a binary string (i.e., a string in which each character is treated as
/// a byte of binary data).
///
/// # Errors
/// Throws a `DOMException` (`InvalidCharacterError`) if the string
/// contains any character whose code point is greater than `0xFF`.
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa
#[allow(clippy::cast_possible_truncation)]
pub fn btoa(data: String) -> JsResult<String> {
let bytes: Vec<u8> = data
.chars()
.map(|c| {
let cp = c as u32;
if cp > 0xFF {
Err(js_error!("InvalidCharacterError: The string to be encoded contains characters outside of the Latin1 range."))
} else {
Ok(cp as u8)
}
})
.collect::<JsResult<Vec<u8>>>()?;

/// Register `atob` and `btoa` into the given context.
Ok(base64::engine::general_purpose::STANDARD.encode(&bytes))
}

/// The [`atob()`][mdn] method decodes a string of data which has been
/// encoded using Base64 encoding.
///
/// # Errors
/// Throws a `DOMException` (`InvalidCharacterError`) if the input is
/// not valid Base64.
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window/atob
pub fn atob(data: String) -> JsResult<String> {
let cleaned: String = data
.chars()
.filter(|c| !matches!(c, ' ' | '\t' | '\n' | '\x0C' | '\r'))
.collect();

let bytes = FORGIVING.decode(cleaned.as_bytes()).map_err(|_| {
js_error!("InvalidCharacterError: The string to be decoded is not correctly encoded.")
})?;

Ok(bytes.into_iter().map(char::from).collect())
}
}

/// Register the `atob` and `btoa` functions in the global context.
///
/// # Errors
///
/// Returns a [`boa_engine::JsError`] if registration fails.
pub fn register(
_realm: Option<boa_engine::realm::Realm>,
_ctx: &mut boa_engine::Context,
) -> boa_engine::JsResult<()> {
Ok(())
/// Returns an error if the functions cannot be registered.
pub fn register(realm: Option<Realm>, context: &mut Context) -> JsResult<()> {
js_module::boa_register(realm, context)
}
File renamed without changes.
Loading
Loading