The next code embbeds Base85 C# encode/decode in Powershell.
---8< -----------------------------
$base85lib =
@"
using System;
using System.Text;
using System.IO;
using System.Linq;
namespace BaseN {
/// <summary>
/// C# implementation of ASCII85 encoding.
/// Based on C code from http://www.stillhq.com/cgi-bin/cvsweb/ascii85/
/// </summary>
/// <remarks>
/// Jeff Atwood
/// http://www.codinghorror.com/blog/archives/000410.html
/// Source code cloned from: https://github.com/coding-horror/ascii85
/// Modified by Anton Krouglov: EncodeFile and DecodeFile static methods added; namespace added
/// </remarks>
public class Ascii85
{
/// <summary>
/// Prefix mark that identifies an encoded ASCII85 string, traditionally '<~'
/// </summary>
public string PrefixMark = "<~";
/// <summary>
/// Suffix mark that identifies an encoded ASCII85 string, traditionally '~>'
/// </summary>
public string SuffixMark = "~>";
/// <summary>
/// Maximum line length for encoded ASCII85 string;
/// set to zero for one unbroken line.
/// </summary>
public int LineLength = 75;
/// <summary>
/// Add the Prefix and Suffix marks when encoding, and enforce their presence for decoding
/// </summary>
public bool EnforceMarks = true;
private const int _asciiOffset = 33;
private readonly byte[] _encodedBlock = new byte[5];
private readonly byte[] _decodedBlock = new byte[4];
private uint _tuple = 0;
private int _linePos = 0;
private readonly uint[] pow85 = { 85*85*85*85, 85*85*85, 85*85, 85, 1 };
/// <summary>
/// Decodes an ASCII85 encoded string into the original binary data
/// </summary>
/// <param name="s">ASCII85 encoded string</param>
/// <returns>byte array of decoded binary data</returns>
public byte[] Decode(string s)
{
if (EnforceMarks)
{
if (!s.StartsWith(PrefixMark) | !s.EndsWith(SuffixMark))
{
throw new Exception("ASCII85 encoded data should begin with '" + PrefixMark +
"' and end with '" + SuffixMark + "'");
}
}
// strip prefix and suffix if present
if (s.StartsWith(PrefixMark))
{
s = s.Substring(PrefixMark.Length);
}
if (s.EndsWith(SuffixMark))
{
s = s.Substring(0, s.Length - SuffixMark.Length);
}
MemoryStream ms = new MemoryStream();
int count = 0;
bool processChar = false;
foreach (char c in s)
{
switch (c)
{
case 'z':
if (count != 0)
{
throw new Exception("The character 'z' is invalid inside an ASCII85 block.");
}
_decodedBlock[0] = 0;
_decodedBlock[1] = 0;
_decodedBlock[2] = 0;
_decodedBlock[3] = 0;
ms.Write(_decodedBlock, 0, _decodedBlock.Length);
processChar = false;
break;
case '\n': case '\r': case '\t': case '\0': case '\f': case '\b':
processChar = false;
break;
default:
if (c < '!' || c > 'u')
{
throw new Exception("Bad character '" + c + "' found. ASCII85 only allows characters '!' to 'u'.");
}
processChar = true;
break;
}
if (processChar)
{
_tuple += ((uint)(c - _asciiOffset) * pow85[count]);
count++;
if (count == _encodedBlock.Length)
{
DecodeBlock();
ms.Write(_decodedBlock, 0, _decodedBlock.Length);
_tuple = 0;
count = 0;
}
}
}
// if we have some bytes left over at the end..
if (count != 0)
{
if (count == 1)
{
throw new Exception("The last block of ASCII85 data cannot be a single byte.");
}
count--;
_tuple += pow85[count];
DecodeBlock(count);
for (int i = 0; i < count; i++)
{
ms.WriteByte(_decodedBlock[i]);
}
}
return ms.ToArray();
}
/// <summary>
/// Encodes binary data into a plaintext ASCII85 format string
/// </summary>
/// <param name="ba">binary data to encode</param>
/// <returns>ASCII85 encoded string</returns>
public string Encode(byte[] ba)
{
StringBuilder sb = new StringBuilder((int)(ba.Length * (_encodedBlock.Length/_decodedBlock.Length)));
_linePos = 0;
if (EnforceMarks)
{
AppendString(sb, PrefixMark);
}
int count = 0;
_tuple = 0;
foreach (byte b in ba)
{
if (count >= _decodedBlock.Length - 1)
{
_tuple |= b;
if (_tuple == 0)
{
AppendChar(sb, 'z');
}
else
{
EncodeBlock(sb);
}
_tuple = 0;
count = 0;
}
else
{
_tuple |= (uint)(b << (24 - (count * 8)));
count++;
}
}
// if we have some bytes left over at the end..
if (count > 0)
{
EncodeBlock(count + 1, sb);
}
if (EnforceMarks)
{
AppendString(sb, SuffixMark);
}
return sb.ToString();
}
private void EncodeBlock(StringBuilder sb)
{
EncodeBlock(_encodedBlock.Length, sb);
}
private void EncodeBlock(int count, StringBuilder sb)
{
for (int i = _encodedBlock.Length - 1; i >= 0; i--)
{
_encodedBlock[i] = (byte)((_tuple % 85) + _asciiOffset);
_tuple /= 85;
}
for (int i = 0; i < count; i++)
{
char c = (char)_encodedBlock[i];
AppendChar(sb, c);
}
}
private void DecodeBlock()
{
DecodeBlock(_decodedBlock.Length);
}
private void DecodeBlock(int bytes)
{
for (int i = 0; i < bytes; i++)
{
_decodedBlock[i] = (byte)(_tuple >> 24 - (i * 8));
}
}
private void AppendString(StringBuilder sb, string s)
{
if (LineLength > 0 && (_linePos + s.Length > LineLength))
{
_linePos = 0;
sb.Append('\n');
}
else
{
_linePos += s.Length;
}
sb.Append(s);
}
private void AppendChar(StringBuilder sb, char c)
{
sb.Append(c);
_linePos++;
if (LineLength > 0 && (_linePos >= LineLength))
{
_linePos = 0;
sb.Append('\n');
}
}
/// <summary>
/// Encodes file to base85
/// </summary>
/// <param name="inFileName">path to source file</param>
/// <param name="outFileName">path to result file</param>
/// <param name="doReverse">reverse base85 straing; default - false</param>
public static void EncodeFile(string inFileName, string outFileName, bool doReverse = false)
{
var encoder = new Ascii85 { EnforceMarks = false, LineLength = 0 };
// read the file
byte[] ba;
using (var streamReader = new FileStream(inFileName, FileMode.Open))
{
ba = new byte[streamReader.Length];
streamReader.Read(ba, 0, (int)streamReader.Length);
streamReader.Close();
}
// encode it
var encodedString = encoder.Encode(ba);
//Console.WriteLine("file encoded in string of length " + encodedString.Length);
var encodedBytes = Encoding.ASCII.GetBytes(encodedString);
if (doReverse) encodedBytes = encodedBytes.AsEnumerable().Reverse().ToArray();
// write the file
using (var streamWriter = new FileStream(outFileName, FileMode.OpenOrCreate))
{
streamWriter.Write(encodedBytes, 0, encodedBytes.Length);
streamWriter.Close();
}
}
/// <summary>
/// Decodes file from base85
/// </summary>
/// <param name="inFileName">path to source file</param>
/// <param name="outFileName">path to result file</param>
/// <param name="doReverse">reverse base85 straing; default - false</param>
public static void DecodeFile(string inFileName, string outFileName, bool doReverse = false)
{
var encoder = new Ascii85 { EnforceMarks = false, LineLength = 0 };
// read the file
byte[] ba;
using (var streamReader = new FileStream(inFileName, FileMode.Open))
{
ba = new byte[streamReader.Length];
streamReader.Read(ba, 0, (int)streamReader.Length);
streamReader.Close();
}
if (doReverse) ba = ba.AsEnumerable().Reverse().ToArray();
var encodedString = Encoding.ASCII.GetString(ba);
// decode it
var decoded = encoder.Decode(encodedString);
//Console.WriteLine("decoded file length " + decoded.Length);
// write the file
using (var streamWriter = new FileStream(outFileName, FileMode.OpenOrCreate))
{
streamWriter.Write(decoded, 0, decoded.Length);
streamWriter.Close();
}
}
}
}
"@
$ErrorActionPreference = 'Stop'
Add-Type -TypeDefinition $base85lib
[BaseN.Ascii85]::EncodeFile('.\test.lnk', '.\test.lnk.base85')
[BaseN.Ascii85]::DecodeFile('.\test.lnk.base85', '.\test.lnk.result');