|  | /* | 
|  | *  Copyright (c) 2025 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | use base64::alphabet; | 
|  | use base64::engine::general_purpose; | 
|  | use base64::engine::DecodePaddingMode; | 
|  | use base64::Engine; | 
|  | use cxx::CxxString; | 
|  | use std::pin::Pin; | 
|  |  | 
|  | #[cxx::bridge(namespace = "webrtc")] | 
|  | mod ffi { | 
|  | #[repr(u8)] | 
|  | enum Base64DecodeSetting { | 
|  | Strict, | 
|  | Forgiving, | 
|  | } | 
|  |  | 
|  | extern "Rust" { | 
|  | fn rs_base64_encode(data: &[u8]) -> String; | 
|  | fn rs_base64_decode( | 
|  | data: &[u8], | 
|  | options: Base64DecodeSetting, | 
|  | output: Pin<&mut CxxString>, | 
|  | ) -> bool; | 
|  | } | 
|  | } | 
|  |  | 
|  | fn rs_base64_encode(data: &[u8]) -> String { | 
|  | general_purpose::STANDARD.encode(data) | 
|  | } | 
|  |  | 
|  | const FORGIVING_ENGINE: general_purpose::GeneralPurpose = general_purpose::GeneralPurpose::new( | 
|  | &alphabet::STANDARD, | 
|  | general_purpose::GeneralPurposeConfig::new() | 
|  | .with_decode_padding_mode(DecodePaddingMode::Indifferent), | 
|  | ); | 
|  |  | 
|  | fn rs_base64_decode( | 
|  | data: &[u8], | 
|  | options: ffi::Base64DecodeSetting, | 
|  | output: Pin<&mut CxxString>, | 
|  | ) -> bool { | 
|  | let result = match options { | 
|  | ffi::Base64DecodeSetting::Strict => general_purpose::STANDARD.decode(data), | 
|  | ffi::Base64DecodeSetting::Forgiving => { | 
|  | let data_without_whitespace: Vec<u8> = | 
|  | data.iter().filter(|&c| !c.is_ascii_whitespace()).copied().collect(); | 
|  | FORGIVING_ENGINE.decode(data_without_whitespace) | 
|  | } | 
|  | _ => unreachable!(), | 
|  | }; | 
|  |  | 
|  | match result { | 
|  | Ok(vec) => { | 
|  | output.push_bytes(vec.as_slice()); | 
|  | true | 
|  | } | 
|  | Err(_) => false, | 
|  | } | 
|  | } |