diff --git a/docs/reference/schemas/config/functions/dataUri.md b/docs/reference/schemas/config/functions/dataUri.md new file mode 100644 index 000000000..78cc6f675 --- /dev/null +++ b/docs/reference/schemas/config/functions/dataUri.md @@ -0,0 +1,191 @@ +--- +description: Reference for the 'dataUri' DSC configuration document function +ms.date: 12/20/2025 +ms.topic: reference +title: dataUri +--- + +# dataUri + +## Synopsis + +Converts a value to a data URI. + +## Syntax + +```Syntax +dataUri() +``` + +## Description + +The `dataUri()` function converts a string value to a [data URI][01] format. The function encodes +the input string as base64 and returns it as a data URI with the `text/plain` media type and +`utf8` charset. + +Data URIs are useful for embedding small text content directly in configuration documents, +especially when the content needs to be passed through systems that expect URI-formatted data. + +## Examples + +### Example 1 - Encode a script for transport + +Encoding a PowerShell script as a data URI ensures safe transport through systems that may have +issues with special characters or line breaks. + +```yaml +# dataUri.example.1.dsc.config.yaml +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +parameters: + scriptContent: + type: string + defaultValue: "Write-Host 'Hello, World!'" +resources: + - name: Encode script as data URI + type: Microsoft.DSC.Debug/Echo + properties: + output: + originalScript: "[parameters('scriptContent')]" + encodedScript: "[dataUri(parameters('scriptContent'))]" +``` + +```bash +dsc config get --file dataUri.example.1.dsc.config.yaml +``` + +```yaml +results: +- name: Encode script as data URI + type: Microsoft.DSC.Debug/Echo + result: + actualState: + output: + originalScript: Write-Host 'Hello, World!' + encodedScript: data:text/plain;charset=utf8;base64,V3JpdGUtSG9zdCAnSGVsbG8sIFdvcmxkISc= +messages: [] +hadErrors: false +``` + +### Example 2 - Encode JSON configuration for embedding + +The configuration encodes a JSON configuration string as a data URI, which is useful when passing +structured data through systems that expect URI-formatted content. + +```yaml +# dataUri.example.2.dsc.config.yaml +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: + - name: Encode JSON config as data URI + type: Microsoft.DSC.Debug/Echo + properties: + output: "[dataUri('{\"setting\":\"value\",\"enabled\":true}')]" +``` + +```bash +dsc config get --file dataUri.example.2.dsc.config.yaml +``` + +```yaml +results: +- name: Encode JSON config as data URI + type: Microsoft.DSC.Debug/Echo + result: + actualState: + output: data:text/plain;charset=utf8;base64,eyJzZXR0aW5nIjoidmFsdWUiLCJlbmFibGVkIjp0cnVlfQ== +messages: [] +hadErrors: false +``` + +### Example 3 - Compare base64 and dataUri encoding + +Unlike the [`base64()`][02] function which returns only the encoded content, `dataUri()` adds +the data URI prefix with media type information. Use `dataUri()` when the target system expects +the full data URI format. + +```yaml +# dataUri.example.3.dsc.config.yaml +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: + - name: Compare encoding methods + type: Microsoft.DSC.Debug/Echo + properties: + output: + base64Only: "[base64('Hello')]" + fullDataUri: "[dataUri('Hello')]" +``` + +```bash +dsc config get --file dataUri.example.3.dsc.config.yaml +``` + +```yaml +results: +- name: Compare encoding methods + type: Microsoft.DSC.Debug/Echo + result: + actualState: + output: + base64Only: SGVsbG8= + fullDataUri: data:text/plain;charset=utf8;base64,SGVsbG8= +messages: [] +hadErrors: false +``` + +### Example 4 - Encode multiline content + +Multiline content like configuration files or scripts can be encoded as a data URI to preserve +line breaks during transport. + +```yaml +# dataUri.example.4.dsc.config.yaml +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +resources: + - name: Encode multiline content + type: Microsoft.DSC.Debug/Echo + properties: + output: "[dataUri('line1\nline2\nline3')]" +``` + +```bash +dsc config get --file dataUri.example.4.dsc.config.yaml +``` + +```yaml +results: +- name: Encode multiline content + type: Microsoft.DSC.Debug/Echo + result: + actualState: + output: data:text/plain;charset=utf8;base64,bGluZTEKbGluZTIKbGluZTM= +messages: [] +hadErrors: false +``` + +## Parameters + +### stringToConvert + +The `dataUri()` function expects a single string as input. The function converts the value into a +data URI representation. If the value isn't a string, DSC raises an error when validating the +configuration document. + +```yaml +Type: string +Required: true +MinimumCount: 1 +MaximumCount: 1 +``` + +## Output + +The `dataUri()` function returns a data URI string in the format +`data:text/plain;charset=utf8;base64,` where `` is the base64 +representation of the **stringToConvert** value. + +```yaml +Type: string +``` + + +[01]: https://en.wikipedia.org/wiki/Data_URI_scheme +[02]: base64.md diff --git a/docs/reference/schemas/config/functions/dataUriToString.md b/docs/reference/schemas/config/functions/dataUriToString.md new file mode 100644 index 000000000..0a8eb309f --- /dev/null +++ b/docs/reference/schemas/config/functions/dataUriToString.md @@ -0,0 +1,222 @@ +--- +description: Reference for the 'dataUriToString' DSC configuration document function +ms.date: 12/20/2025 +ms.topic: reference +title: dataUriToString +--- + +# dataUriToString + +## Synopsis + +Converts a data URI formatted value to a string. + +## Syntax + +```Syntax +dataUriToString() +``` + +## Description + +The `dataUriToString()` function converts a [data URI][01] formatted value back to its original +string representation. This function is the inverse of the [`dataUri()`][02] function and is useful +for decoding data that was previously encoded as a data URI. + +The function supports both base64-encoded data URIs (those containing `;base64` in the metadata) +and URL-encoded data URIs. It automatically detects the encoding method and decodes accordingly. + +## Examples + +### Example 1 - Decode embedded script content + +Decoding a PowerShell script from a data URI is useful when receiving commands from external +systems that transmit data in this format. + +```yaml +# dataUriToString.example.1.dsc.config.yaml +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +parameters: + encodedScript: + type: string + defaultValue: "data:text/plain;charset=utf8;base64,V3JpdGUtSG9zdCAnSGVsbG8sIFdvcmxkISc=" +resources: + - name: Decode and display script + type: Microsoft.DSC.Debug/Echo + properties: + output: "[dataUriToString(parameters('encodedScript'))]" +``` + +```bash +dsc config get --file dataUriToString.example.1.dsc.config.yaml +``` + +```yaml +results: +- name: Decode and display script + type: Microsoft.DSC.Debug/Echo + result: + actualState: + output: Write-Host 'Hello, World!' +messages: [] +hadErrors: false +``` + +### Example 2 - Extract JSON configuration from data URI + +The configuration decodes a JSON configuration that was transmitted as a data URI, then parses it +using the [`json()`][06] function to access its properties. + +```yaml +# dataUriToString.example.2.dsc.config.yaml +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +parameters: + configDataUri: + type: string + defaultValue: "data:;base64,eyJzZXR0aW5nIjoidmFsdWUiLCJlbmFibGVkIjp0cnVlfQ==" +resources: + - name: Decode and parse JSON config + type: Microsoft.DSC.Debug/Echo + properties: + output: + rawJson: "[dataUriToString(parameters('configDataUri'))]" + parsedSetting: "[json(dataUriToString(parameters('configDataUri'))).setting]" +``` + +```bash +dsc config get --file dataUriToString.example.2.dsc.config.yaml +``` + +```yaml +results: +- name: Decode and parse JSON config + type: Microsoft.DSC.Debug/Echo + result: + actualState: + output: + rawJson: '{"setting":"value","enabled":true}' + parsedSetting: value +messages: [] +hadErrors: false +``` + +### Example 3 - Process data from Azure ARM template output + +Azure ARM templates and similar systems often use data URIs for content encoding. Use +`dataUriToString()` to decode this content back to its original form. + +```yaml +# dataUriToString.example.3.dsc.config.yaml +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +parameters: + armTemplateOutput: + type: string + defaultValue: "data:text/plain;charset=utf8;base64,SGVsbG8sIFdvcmxkIQ==" +resources: + - name: Process ARM template data URI output + type: Microsoft.DSC.Debug/Echo + properties: + output: "[dataUriToString(parameters('armTemplateOutput'))]" +``` + +```bash +dsc config get --file dataUriToString.example.3.dsc.config.yaml +``` + +```yaml +results: +- name: Process ARM template data URI output + type: Microsoft.DSC.Debug/Echo + result: + actualState: + output: Hello, World! +messages: [] +hadErrors: false +``` + +### Example 4 - Round-trip verification + +Encoding a string to a data URI and decoding it back verifies that data survives the +transformation correctly. Combine `dataUriToString()` with [`dataUri()`][02] to test this. + +```yaml +# dataUriToString.example.4.dsc.config.yaml +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +parameters: + originalContent: + type: string + defaultValue: "Configuration with special chars: <>&\"" +resources: + - name: Verify round-trip encoding + type: Microsoft.DSC.Debug/Echo + properties: + output: + original: "[parameters('originalContent')]" + afterRoundTrip: "[dataUriToString(dataUri(parameters('originalContent')))]" +``` + +```bash +dsc config get --file dataUriToString.example.4.dsc.config.yaml +``` + +```yaml +results: +- name: Verify round-trip encoding + type: Microsoft.DSC.Debug/Echo + result: + actualState: + output: + original: 'Configuration with special chars: <>&"' + afterRoundTrip: 'Configuration with special chars: <>&"' +messages: [] +hadErrors: false +``` + +## Parameters + +### dataUriToConvert + +The `dataUriToString()` function expects a single string containing a valid data URI. The data URI +must start with `data:` and contain a comma separating the metadata from the encoded data. If the +metadata contains `;base64`, the data is decoded as base64; otherwise, it's decoded as URL-encoded. + +```yaml +Type: string +Required: true +MinimumCount: 1 +MaximumCount: 1 +``` + +## Output + +The `dataUriToString()` function returns the decoded string representation of the +**dataUriToConvert** parameter. + +```yaml +Type: string +``` + +## Exceptions + +The `dataUriToString()` function raises errors for the following conditions: + +- **Invalid data URI format**: When the input string doesn't start with `data:` or doesn't contain + a comma separator +- **Invalid base64 encoding**: When the data portion contains invalid base64 characters (for + base64-encoded data URIs) +- **Invalid UTF-8**: When the decoded bytes do not form valid UTF-8 text + +## Related functions + +- [`dataUri()`][02] - Converts a value to a data URI +- [`base64()`][03] - Encodes a string to base64 format +- [`base64ToString()`][04] - Decodes a base64 string +- [`parameters()`][05] - Retrieves parameter values + + +[01]: https://en.wikipedia.org/wiki/Data_URI_scheme +[02]: ./dataUri.md +[03]: ./base64.md +[04]: ./base64ToString.md +[05]: ./parameters.md +[06]: ./json.md diff --git a/docs/reference/schemas/config/functions/overview.md b/docs/reference/schemas/config/functions/overview.md index bc1d7635f..e71ee8e83 100644 --- a/docs/reference/schemas/config/functions/overview.md +++ b/docs/reference/schemas/config/functions/overview.md @@ -671,6 +671,8 @@ The following list of functions are for manipulating strings: - [concat()][concat] - Return a combined string where the input strings are concatenated in the order they're specified. - [contains()][contains] - Check if an array contains a value or an object contains a key. +- [dataUri()][dataUri] - Convert a value to a data URI. +- [dataUriToString()][dataUriToString] - Convert a data URI formatted value to a string. - [empty()][empty] - Check if a value (string, array, or object) is empty. - [endsWith()][endsWith] - Check if a string ends with a specified suffix. - [first()][first] - Return the first element of an array or the first character of a string. @@ -729,6 +731,8 @@ The following list of functions create or convert values of a given type: [copyIndex]: ./copyIndex.md [createArray]: ./createArray.md [createObject]: ./createObject.md +[dataUri]: ./dataUri.md +[dataUriToString]: ./dataUriToString.md [div]: ./div.md [empty]: ./empty.md [endsWith]: ./endsWith.md diff --git a/dsc/tests/dsc_functions.tests.ps1 b/dsc/tests/dsc_functions.tests.ps1 index 453bc5767..f559817b1 100644 --- a/dsc/tests/dsc_functions.tests.ps1 +++ b/dsc/tests/dsc_functions.tests.ps1 @@ -1714,4 +1714,67 @@ Describe 'tests for function expressions' { $out.results[0].result.actualState.output | Should -BeNullOrEmpty } } + + It 'dataUri function works for: ' -TestCases @( + @{ expression = "[dataUri('Hello')]"; expected = 'data:text/plain;charset=utf8;base64,SGVsbG8=' } + @{ expression = "[dataUri('')]"; expected = 'data:text/plain;charset=utf8;base64,' } + @{ expression = "[dataUri('Hello, World!')]"; expected = 'data:text/plain;charset=utf8;base64,SGVsbG8sIFdvcmxkIQ==' } + @{ expression = "[dataUri('héllo')]"; expected = 'data:text/plain;charset=utf8;base64,aMOpbGxv' } + @{ expression = "[dataUri(concat('Hello', ', World!'))]"; expected = 'data:text/plain;charset=utf8;base64,SGVsbG8sIFdvcmxkIQ==' } + ) { + param($expression, $expected) + + $config_yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Echo + type: Microsoft.DSC.Debug/Echo + properties: + output: `"$expression`" +"@ + $out = $config_yaml | dsc config get -f - | ConvertFrom-Json + $out.results[0].result.actualState.output | Should -Be $expected + } + + It 'dataUriToString function works for: ' -TestCases @( + @{ expression = "[dataUriToString('data:text/plain;charset=utf8;base64,SGVsbG8=')]"; expected = 'Hello' } + @{ expression = "[dataUriToString('data:;base64,SGVsbG8sIFdvcmxkIQ==')]"; expected = 'Hello, World!' } + @{ expression = "[dataUriToString('data:text/plain;base64,')]"; expected = '' } + @{ expression = "[dataUriToString('data:text/plain;charset=utf8;base64,aMOpbGxv')]"; expected = 'héllo' } + @{ expression = "[dataUriToString(dataUri('test message'))]"; expected = 'test message' } + ) { + param($expression, $expected) + + $config_yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Echo + type: Microsoft.DSC.Debug/Echo + properties: + output: `"$expression`" +"@ + $out = $config_yaml | dsc config get -f - | ConvertFrom-Json + $out.results[0].result.actualState.output | Should -Be $expected + } + + It 'dataUriToString function error handling: ' -TestCases @( + @{ expression = "[dataUriToString('not a data uri')]" ; expectedError = 'Invalid data URI format' } + @{ expression = "[dataUriToString('data:text/plain;base64')]" ; expectedError = 'Invalid data URI format' } + @{ expression = "[dataUriToString('data:;base64,invalid!@#')]" ; expectedError = 'Invalid base64 encoding' } + ) { + param($expression, $expectedError) + + $config_yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Echo + type: Microsoft.DSC.Debug/Echo + properties: + output: `"$expression`" +"@ + $null = dsc -l trace config get -i $config_yaml 2>$TestDrive/error.log + $LASTEXITCODE | Should -Not -Be 0 + $errorContent = Get-Content $TestDrive/error.log -Raw + $errorContent | Should -Match $expectedError + } } diff --git a/lib/dsc-lib/locales/en-us.toml b/lib/dsc-lib/locales/en-us.toml index d900998e7..bf8476e24 100644 --- a/lib/dsc-lib/locales/en-us.toml +++ b/lib/dsc-lib/locales/en-us.toml @@ -319,6 +319,17 @@ invoked = "createObject function" argsMustBePairs = "Arguments must be provided in key-value pairs" keyMustBeString = "Object keys must be strings" +[functions.dataUri] +description = "Converts a value to a data URI" + +[functions.dataUriToString] +description = "Converts a data URI formatted value to a string" +invoked = "dataUriToString function" +invalidDataUri = "Invalid data URI format" +invalidBase64 = "Invalid base64 encoding in data URI" +invalidUtf8 = "Decoded bytes do not form valid UTF-8" +invalidEncoding = "Invalid encoding in data URI" + [functions.div] description = "Divides the first number by the second" invoked = "div function" diff --git a/lib/dsc-lib/src/functions/data_uri.rs b/lib/dsc-lib/src/functions/data_uri.rs new file mode 100644 index 000000000..b45e5a9d1 --- /dev/null +++ b/lib/dsc-lib/src/functions/data_uri.rs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use base64::{Engine as _, engine::general_purpose}; + +use crate::DscError; +use crate::configure::context::Context; +use crate::functions::{FunctionArgKind, FunctionCategory, FunctionMetadata}; +use rust_i18n::t; +use serde_json::Value; +use super::Function; + +#[derive(Debug, Default)] +pub struct DataUri {} + +impl Function for DataUri { + fn get_metadata(&self) -> FunctionMetadata { + FunctionMetadata { + name: "dataUri".to_string(), + description: t!("functions.dataUri.description").to_string(), + category: vec![FunctionCategory::String], + min_args: 1, + max_args: 1, + accepted_arg_ordered_types: vec![vec![FunctionArgKind::String]], + remaining_arg_accepted_types: None, + return_types: vec![FunctionArgKind::String], + } + } + + fn invoke(&self, args: &[Value], _context: &Context) -> Result { + let string_to_convert = args[0].as_str().unwrap_or_default(); + let base64_encoded = general_purpose::STANDARD.encode(string_to_convert); + let result = format!("data:text/plain;charset=utf8;base64,{base64_encoded}"); + Ok(Value::String(result)) + } +} + +#[cfg(test)] +mod tests { + use crate::configure::context::Context; + use crate::parser::Statement; + + #[test] + fn test_data_uri_basic() { + let mut parser = Statement::new().unwrap(); + let result = parser.parse_and_execute("[dataUri('Hello')]", &Context::new()).unwrap(); + assert_eq!(result, "data:text/plain;charset=utf8;base64,SGVsbG8="); + } + + #[test] + fn test_data_uri_empty_string() { + let mut parser = Statement::new().unwrap(); + let result = parser.parse_and_execute("[dataUri('')]", &Context::new()).unwrap(); + assert_eq!(result, "data:text/plain;charset=utf8;base64,"); + } + + #[test] + fn test_data_uri_with_spaces() { + let mut parser = Statement::new().unwrap(); + let result = parser.parse_and_execute("[dataUri('Hello, World!')]", &Context::new()).unwrap(); + assert_eq!(result, "data:text/plain;charset=utf8;base64,SGVsbG8sIFdvcmxkIQ=="); + } + + #[test] + fn test_data_uri_unicode() { + let mut parser = Statement::new().unwrap(); + let result = parser.parse_and_execute("[dataUri('héllo')]", &Context::new()).unwrap(); + assert_eq!(result, "data:text/plain;charset=utf8;base64,aMOpbGxv"); + } + + #[test] + fn test_data_uri_number_arg_fails() { + let mut parser = Statement::new().unwrap(); + let result = parser.parse_and_execute("[dataUri(123)]", &Context::new()); + assert!(result.is_err()); + } +} diff --git a/lib/dsc-lib/src/functions/data_uri_to_string.rs b/lib/dsc-lib/src/functions/data_uri_to_string.rs new file mode 100644 index 000000000..e3f558c0e --- /dev/null +++ b/lib/dsc-lib/src/functions/data_uri_to_string.rs @@ -0,0 +1,161 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use base64::{Engine as _, engine::general_purpose}; + +use crate::DscError; +use crate::configure::context::Context; +use crate::functions::{FunctionArgKind, FunctionCategory, FunctionMetadata}; +use rust_i18n::t; +use serde_json::Value; +use super::Function; +use tracing::debug; + +#[derive(Debug, Default)] +pub struct DataUriToString {} + +impl Function for DataUriToString { + fn get_metadata(&self) -> FunctionMetadata { + FunctionMetadata { + name: "dataUriToString".to_string(), + description: t!("functions.dataUriToString.description").to_string(), + category: vec![FunctionCategory::String], + min_args: 1, + max_args: 1, + accepted_arg_ordered_types: vec![vec![FunctionArgKind::String]], + remaining_arg_accepted_types: None, + return_types: vec![FunctionArgKind::String], + } + } + + fn invoke(&self, args: &[Value], _context: &Context) -> Result { + debug!("{}", t!("functions.dataUriToString.invoked")); + + let data_uri = args[0].as_str().unwrap(); + + if !data_uri.starts_with("data:") { + return Err(DscError::FunctionArg( + "dataUriToString".to_string(), + t!("functions.dataUriToString.invalidDataUri").to_string(), + )); + } + + // Find the base64 marker and extract the encoded content + // Format: data:[][;base64], + let Some(comma_pos) = data_uri.find(',') else { + return Err(DscError::FunctionArg( + "dataUriToString".to_string(), + t!("functions.dataUriToString.invalidDataUri").to_string(), + )); + }; + + let metadata = &data_uri[5..comma_pos]; // Skip "data:" + let encoded_data = &data_uri[comma_pos + 1..]; + + // Check if it's base64 encoded + if metadata.contains(";base64") { + // Decode base64 + let decoded_bytes = general_purpose::STANDARD.decode(encoded_data).map_err(|_| { + DscError::FunctionArg( + "dataUriToString".to_string(), + t!("functions.dataUriToString.invalidBase64").to_string(), + ) + })?; + + let result = String::from_utf8(decoded_bytes).map_err(|_| { + DscError::FunctionArg( + "dataUriToString".to_string(), + t!("functions.dataUriToString.invalidUtf8").to_string(), + ) + })?; + + Ok(Value::String(result)) + } else { + // TODO: Not sure if this is also done in ARM + let decoded = urlencoding::decode(encoded_data).map_err(|_| { + DscError::FunctionArg( + "dataUriToString".to_string(), + t!("functions.dataUriToString.invalidEncoding").to_string(), + ) + })?; + Ok(Value::String(decoded.into_owned())) + } + } +} + +#[cfg(test)] +mod tests { + use crate::configure::context::Context; + use crate::parser::Statement; + use serde_json::Value; + + #[test] + fn test_data_uri_to_string_basic() { + let mut parser = Statement::new().unwrap(); + let result = parser + .parse_and_execute("[dataUriToString('data:text/plain;charset=utf8;base64,SGVsbG8=')]", &Context::new()) + .unwrap(); + assert_eq!(result, Value::String("Hello".to_string())); + } + + #[test] + fn test_data_uri_to_string_with_comma() { + let mut parser = Statement::new().unwrap(); + let result = parser + .parse_and_execute("[dataUriToString('data:;base64,SGVsbG8sIFdvcmxkIQ==')]", &Context::new()) + .unwrap(); + assert_eq!(result, Value::String("Hello, World!".to_string())); + } + + #[test] + fn test_data_uri_to_string_empty() { + let mut parser = Statement::new().unwrap(); + let result = parser + .parse_and_execute("[dataUriToString('data:text/plain;base64,')]", &Context::new()) + .unwrap(); + assert_eq!(result, Value::String("".to_string())); + } + + #[test] + fn test_data_uri_to_string_unicode() { + let mut parser = Statement::new().unwrap(); + let result = parser + .parse_and_execute("[dataUriToString('data:text/plain;charset=utf8;base64,aMOpbGxv')]", &Context::new()) + .unwrap(); + assert_eq!(result, Value::String("héllo".to_string())); + } + + #[test] + fn test_data_uri_to_string_invalid_uri() { + let mut parser = Statement::new().unwrap(); + let result = parser + .parse_and_execute("[dataUriToString('not a data uri')]", &Context::new()); + assert!(result.is_err()); + } + + #[test] + fn test_data_uri_to_string_no_comma() { + let mut parser = Statement::new().unwrap(); + let result = parser + .parse_and_execute("[dataUriToString('data:text/plain;base64')]", &Context::new()); + assert!(result.is_err()); + } + + #[test] + fn test_data_uri_to_string_round_trip() { + let mut parser = Statement::new().unwrap(); + let result = parser + .parse_and_execute("[dataUriToString(dataUri('Hello, World!'))]", &Context::new()) + .unwrap(); + assert_eq!(result, Value::String("Hello, World!".to_string())); + } + + #[test] + fn test_data_uri_to_string_url_encoded() { + let mut parser = Statement::new().unwrap(); + let result = parser + .parse_and_execute("[dataUriToString('data:text/plain,Hello%20World')]", &Context::new()) + .unwrap(); + assert_eq!(result, Value::String("Hello World".to_string())); + } +} diff --git a/lib/dsc-lib/src/functions/mod.rs b/lib/dsc-lib/src/functions/mod.rs index 5c53bd3be..1bfb95a3d 100644 --- a/lib/dsc-lib/src/functions/mod.rs +++ b/lib/dsc-lib/src/functions/mod.rs @@ -27,6 +27,8 @@ pub mod contains; pub mod context; pub mod copy_index; pub mod create_array; +pub mod data_uri; +pub mod data_uri_to_string; pub mod create_object; pub mod div; pub mod empty; @@ -167,6 +169,8 @@ impl FunctionDispatcher { Box::new(copy_index::CopyIndex{}), Box::new(create_array::CreateArray{}), Box::new(create_object::CreateObject{}), + Box::new(data_uri::DataUri{}), + Box::new(data_uri_to_string::DataUriToString{}), Box::new(div::Div{}), Box::new(empty::Empty{}), Box::new(ends_with::EndsWith{}),