The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.
ublic void ProcessFolderForHtml(string sourcePath, string outputHtmlPath)
{
string logoDataUri = GetBase64Image("OnlineConverterOSTtoPST.download.png", "image/png");
string folderIconDataUri = GetBase64Image("OnlineConverterOSTtoPST.download.gif", "image/gif");
string headerIconDataUri = GetBase64Image("OnlineConverterOSTtoPST.download (1).gif", "image/gif");
string plusIconDataUri = GetBase64Image("OnlineConverterOSTtoPST.Group 4545.png", "image/png");
string minusIconDataUri = GetBase64Image("OnlineConverterOSTtoPST.Group 4544.png", "image/png");
//string baseDir = AppDomain.CurrentDomain.BaseDirectory;
//string resourcesPath = Path.Combine(baseDir, "Resources");
//string logoPath = Path.Combine(resourcesPath, "download.png");
//string folderIconPath = Path.Combine(resourcesPath, "download.gif");
//string headerIconPath = Path.Combine(resourcesPath, "download (1).gif");
//string plusIconPath = Path.Combine(resourcesPath, "Group 4545.png");
//string minusIconPath = Path.Combine(resourcesPath, "Group 4544.png");
//string logoDataUri = "data:image/png;base64," + Convert.ToBase64String(File.ReadAllBytes(logoPath));
//string folderIconDataUri = "data:image/gif;base64," + Convert.ToBase64String(File.ReadAllBytes(folderIconPath));
//string headerIconDataUri = "data:image/gif;base64," + Convert.ToBase64String(File.ReadAllBytes(headerIconPath));
//string plusIconDataUri = "data:image/png;base64," + Convert.ToBase64String(File.ReadAllBytes(plusIconPath));
//string minusIconDataUri = "data:image/png;base64," + Convert.ToBase64String(File.ReadAllBytes(minusIconPath));
using (PersonalStorage pst = PersonalStorage.FromFile(sourcePath))
{
var html = new StringBuilder();
html.AppendLine("<!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'>");
html.AppendLine("<title>OLM to PST File Tree</title>");
html.AppendLine("<style>");
html.AppendLine(@"
body {
font-family: 'Segoe UI', sans-serif;
padding: 20px;
background: #fff;
}
ul.tree {
margin-top: 10px; /* reduce gap between heading and tree */
}
h2, .file-label {
margin: 0 !important;
padding: 0 !important;
line-height: 20px;
}
ul.tree {
margin-top: 4px !important;
//margin: 0 !important;
padding-left: 20px; /* Align with file label */
}
.tree li {
margin: 0 !important;
padding-left: 18px; /* Align with file label */
line-height: 16px;
}
.file-label {
margin-bottom: 0 !important;
}
ul.tree {
margin-top: -2px !important;
}
.tree > li {
margin-top: 0 !important;
padding-top: 0 !important;
}
ul.tree, .tree ul {
list-style: none;
margin: 0;
padding-left: 14px;
position: relative;
}
.tree li {
position: relative;
padding-left: 10px; /* reduced from 16px */
line-height: 16px; /* slightly tighter line spacing */
}
/* Remove dotted line for ROOT node */
.tree > li::before,
.tree > li::after {
content: none !important;
border: none !important;
}
//.tree li::before {
// content: '';
// position: absolute;
// top: 0;
// bottom: -12px;
// left: 3px;
// height:100%;
// border-left: 1px dotted gray;
// z-index: 0;
//}
.tree li::before {
content: '';
position: absolute;
top: 0;
bottom: -20px; /* Increased from -12px */
left: 3px;
height: 100%;
border-left: 1px dotted gray;
z-index: 0;
}
.tree li::after {
content: '';
position: absolute;
top: 10px;
left: 4px;
width: 18px;
border-top: 1px dotted gray;
z-index: 0;
}
.tree li:last-child::before {
height: 10px;
}
//.folder-label {
// display: inline-block;
// padding-left: 20px;
// background-image: url('" + folderIconDataUri + @"');
// background-size: 16px 16px;
// background-repeat: no-repeat;
// background-position: left center;
// vertical-align: middle;
// margin-left: 4px;
//}
.folder-label {
font-size: 13px; /* slightly larger than default */
display: inline-block;
padding-left: 18px;
background-image: url('" + folderIconDataUri + @"');
background-size: 16px 16px;
background-repeat: no-repeat;
background-position: left center;
vertical-align: middle;
margin-left: 2px;
}
.tree li.expanded > .folder-label {
background-image: url('" + headerIconDataUri + @"');
}
//.toggle-icon {
// display: inline-block;
// width: 18px;
// height: 18px;
// margin-left: -16px; /* adjust to center over dotted line */
// margin-right: 2px;
// cursor: pointer;
// background-image: url('" + plusIconDataUri + @"');
// background-size: 10px 10px;
// background-repeat: no-repeat;
// background-position: center;
// position: relative;
// vertical-align: middle;
// z-index: 1;
//}
.toggle-icon {
display: inline-block;
width: 18px;
height: 18px;
margin-left: -16px;
margin-right: 2px;
cursor: pointer;
background-image: url('" + plusIconDataUri + @"');
background-size: 10px 10px;
background-repeat: no-repeat;
background-position: center;
position: relative;
vertical-align: middle;
top: 1px; /* fine-tune vertical centering */
z-index: 1;
}
.tree li.expanded > .toggle-icon {
background-image: url('" + minusIconDataUri + @"');
}
.tree ul {
display: none;
}
.tree li.expanded > ul {
display: block;
}
");
html.AppendLine("</style></head><body>");
// Header
html.AppendLine("<table><tr>");
html.AppendLine($"<td><img src='{logoDataUri}' style='height:55px;' /></td>");
html.AppendLine("<td style='padding-left:20px;'>");
html.AppendLine("<div style='font-size:30px; font-weight:600;color:#333333;'>Stellar Converter OLM TO PST Online</div>");
html.AppendLine($"<div style='font-size:14px; font-style:italic;'>Generated on: {DateTime.Now:ddd MMM dd yyyy HH:mm:ss} by <a href='https://www.stellarinfo.com/support/' style='text-decoration:none; color:#900;'>https://www.stellarinfo.com/support/</a></div>");
html.AppendLine("</td></tr></table><hr/>");
// Tree root (OST file name)
string fileLabel = $"{Path.GetPathRoot(sourcePath).TrimEnd('\\')}-{Path.GetFileName(sourcePath)}";
html.AppendLine("<ul class='tree'>");
html.AppendLine("<li class='expanded'>");
html.AppendLine("<div style=\"font-size:14px; font-weight:500; color:#000000; padding-left:20px; background-image:url('" + headerIconDataUri + "'); background-size:18px 18px; background-repeat:no-repeat; background-position:left center;\">" + WebUtility.HtmlEncode(fileLabel) + "</div>");
// PST root folders
FolderInfo rootFolder = pst.RootFolder;
html.AppendLine("<ul>");
foreach (var topFolder in rootFolder.GetSubFolders())
{
if (IsGuid(topFolder.DisplayName))
continue;
//bool hasChildren = topFolder.GetSubFolders()?.Count > 0;
//int itemCount = topFolder.ContentCount;
//string folderDisplay = $"{topFolder.DisplayName} ({itemCount})";
bool hasChildren = topFolder.GetSubFolders()?.Count > 0;
int itemCount = topFolder.ContentCount;
// Remove "(0)" only at the end
string folderDisplay = GetDisplayName(topFolder.DisplayName);
// Append count only if greater than 0
if (itemCount > 0)
{
folderDisplay += $" ({itemCount})";
}
string liClass = hasChildren ? "expanded" : "";
string iconDataUri = hasChildren ? headerIconDataUri : folderIconDataUri;
html.AppendLine($"<li class='{liClass}'>");
if (hasChildren)
html.AppendLine("<span class='toggle-icon'></span>");
else
html.AppendLine("<span style='display:inline-block; width:10px;'></span>");
html.AppendLine("<div class='folder-label' style=\"background-image:url('" + iconDataUri + "');\">" + WebUtility.HtmlEncode(folderDisplay) + "</div>");
if (hasChildren)
GenerateHtmlTree(topFolder, html);
html.AppendLine("</li>");
}
html.AppendLine("</ul>");
html.AppendLine("</li></ul>");
// JS for toggle functionality
html.AppendLine(@"
<script>
document.querySelectorAll('.toggle-icon').forEach(function(icon) {
icon.addEventListener('click', function() {
var li = this.parentElement;
li.classList.toggle('expanded');
});
});
</script>");
html.AppendLine("</body></html>");
File.WriteAllText(outputHtmlPath, html.ToString());
// Console.WriteLine("HTML file tree generated at: " + htmlOutputPath);
}
}
private static string GetBase64Image(string resourceName, string mimeType)
{
var assembly = typeof(Program).Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
if (stream == null)
throw new FileNotFoundException("Resource not found: " + resourceName);
using (MemoryStream ms = new MemoryStream())
{
stream.CopyTo(ms);
string base64 = Convert.ToBase64String(ms.ToArray());
return $"data:{mimeType};base64,{base64}";
}
}
}