Based on code found in github repo https://github.com/Stenway/RSV-Challenge
Last active
January 9, 2024 17:44
-
-
Save irwins/06fd11510f5ad64d64badefba8af822f to your computer and use it in GitHub Desktop.
PowerShell RSV
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region functions | |
function Encode-Rsv { | |
param ( | |
[Parameter(Mandatory=$true)] | |
[Array]$rows | |
) | |
$parts = @() | |
foreach ($row in $rows) { | |
foreach ($value in $row) { | |
if ($null -eq $value) { | |
$parts += [byte]0xFE | |
} elseif ($value.Length -gt 0) { | |
$parts += [System.Text.Encoding]::UTF8.GetBytes($value) | |
} | |
$parts += [byte]0xFF | |
} | |
$parts += [byte]0xFD | |
} | |
return [System.Byte[]]$parts | |
} | |
function Decode-Rsv { | |
param ( | |
[byte[]]$bytes | |
) | |
if ($bytes.Length -gt 0 -and $bytes[-1] -ne 0xFD) { | |
throw "Incomplete RSV document" | |
} | |
$result = @() | |
$current_row = @() | |
$value_start_index = 0 | |
for ($i = 0; $i -lt $bytes.Length; $i++) { | |
if ($bytes[$i] -eq 0xFF) { | |
$length = $i - $value_start_index | |
if ($length -eq 0) { | |
$current_row += "" | |
#Write-Output "Empty string $($current_row)" | |
} | |
elseif ($length -eq 1 -and $bytes[$value_start_index] -eq 0xFE) { | |
$current_row += $null | |
#Write-Output "Null $($current_row)" | |
} | |
else { | |
$value_bytes = $bytes[$value_start_index..($i - 1)] | |
$current_row += [System.Text.Encoding]::Default.GetString($value_bytes) | |
#Write-Output "String $($current_row)" | |
} | |
$value_start_index = $i + 1 | |
} | |
elseif ($bytes[$i] -eq 0xFD) { | |
if ($i -gt 0 -and $value_start_index -ne $i) { | |
throw "Incomplete RSV row" | |
} | |
#Write-Output $current_row | |
$result += @(,$current_row) | |
$current_row = @() | |
$value_start_index = $i + 1 | |
} | |
} | |
return $result | |
} | |
#endregion | |
#region main | |
#region Short test | |
$rows = @( | |
@("Hello", "π", $null, ""), | |
@("A\0B\nC", "Test π"), | |
@(), | |
@("") | |
) | |
$rowsToJson = $rows | ConvertTo-Json -Compress -Depth 100 -EscapeHandling Default | |
$rowsToJson | |
#$rowsToJson Output is: [["Hello","π",null,""],["A\0B\nC","Test π"],[],[""]] | |
#endregion | |
#Encode | |
$encodedBytes = Encode-Rsv -rows $rows | |
$encodedBytes | |
#Save to rsv file | |
$rsvFilePath = "rsv/playground/test.rsv" | |
[System.IO.File]::WriteAllBytes($rsvFilePath, $encodedBytes) | |
#load from rsv file | |
$loadFromFile = [System.IO.File]::ReadAllBytes($rsvFilePath) | |
$loadFromFile | |
$decodedBytes = Decode-Rsv -bytes $loadFromFile | |
$decodedBytes | ConvertTo-Json -Compress -Depth 100 -EscapeHandling Default | |
#$decodedBytes Output is: [["Hello","π",null,""],["A\0B\nC","Test π"],[],[""]] | |
#endregion |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fs::File; | |
use std::io::prelude::*; | |
fn encode_rsv(rows: &[Vec<Option<&str>>]) -> Vec<u8> { | |
let mut parts: Vec<u8> = Vec::new(); | |
for row in rows { | |
for value in row { | |
match value { | |
None => parts.push(0xFE), | |
Some(v) => { | |
if !v.is_empty() { | |
parts.extend_from_slice(v.as_bytes()); | |
} | |
} | |
} | |
parts.push(0xFF); | |
} | |
parts.push(0xFD); | |
} | |
parts | |
} | |
fn decode_rsv(bytes: &[u8]) -> Vec<Vec<Option<String>>> { | |
let mut result: Vec<Vec<Option<String>>> = Vec::new(); | |
let mut current_row: Vec<Option<String>> = Vec::new(); | |
let mut value_start_index = 0; | |
for (i, &byte) in bytes.iter().enumerate() { | |
if byte == 0xFF { | |
let length = i - value_start_index; | |
if length == 0 { | |
current_row.push(None); | |
} else if length == 1 && bytes[value_start_index] == 0xFE { | |
current_row.push(None); | |
} else { | |
let value_bytes = &bytes[value_start_index..i]; | |
let value = String::from_utf8_lossy(value_bytes).to_string(); | |
current_row.push(Some(value)); | |
} | |
value_start_index = i + 1; | |
} else if byte == 0xFD { | |
if i > 0 && value_start_index != i { | |
panic!("Incomplete RSV row"); | |
} | |
result.push(current_row); | |
current_row = Vec::new(); | |
value_start_index = i + 1; | |
} | |
} | |
result | |
} | |
fn main() { | |
let rows: Vec<Vec<Option<&str>>> = vec![ | |
vec!["Hello", "π", None, ""], | |
vec!["A\0B\nC", "Test π"], | |
vec![], | |
vec![""], | |
]; | |
// Encode | |
let encoded_bytes = encode_rsv(&rows); | |
println!("{:?}", encoded_bytes); | |
// Save to RSV file | |
let rsv_file_path = "rsv/playground/test.rsv"; | |
let mut file = File::create(rsv_file_path).expect("Failed to create file"); | |
file.write_all(&encoded_bytes).expect("Failed to write to file"); | |
// Load from RSV file | |
let mut load_from_file = Vec::new(); | |
let mut file = File::open(rsv_file_path).expect("Failed to open file"); | |
file.read_to_end(&mut load_from_file).expect("Failed to read from file"); | |
let decoded_bytes = decode_rsv(&load_from_file); | |
println!("{:?}", decoded_bytes); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment