Add project files.

This commit is contained in:
Andy Howard
2021-05-05 15:36:28 +01:00
parent 949836d24c
commit a4cf706eb3
353 changed files with 60029 additions and 0 deletions
@@ -0,0 +1,239 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.StaticFiles;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace Sarand.Net.Standard.Base.Helpers
{
//==========================================================================
public static class SacsContentTypeHelper
{
//-------------------------------------------------------------------
// Definition - Content Type Data.
public class ContentTypeData
{
protected ContentTypeData(List<String> extensions, String caption, String contentType, Sacs.MimeType mime)
{
ContentType = contentType;
Caption = caption;
Extensions.AddRange(extensions);
Mime = mime;
}
public String PreferredContentType { get; protected set; }
public String ContentType { get; }
public String Caption { get; }
public List<String> Extensions { get; } = new List<string>();
public Sacs.MimeType Mime { get; }
}
private class ContentTypeData_Internal : ContentTypeData
{
public ContentTypeData_Internal(String extension, String caption, String contentType, Sacs.MimeType mime = Sacs.MimeType.Unknown) :
base(StringListUtil.Split(extension, ",", true, true, true), caption, contentType, mime)
{ }
public new String PreferredContentType { set { base.PreferredContentType = value; } }
}
//-------------------------------------------------------------------
// Data members.
private static readonly List<ContentTypeData> contentTypes;
private static FileExtensionContentTypeProvider provider = null;
private static readonly HashSet<Sacs.MimeType> allowedMimeTypes_CandidateCV = new HashSet<Sacs.MimeType>()
{
Sacs.MimeType.MsDoc,
Sacs.MimeType.MsDocx,
Sacs.MimeType.OpenDocText,
Sacs.MimeType.Pdf,
Sacs.MimeType.Rtf
};
//-------------------------------------------------------------------
// Static initialisation.
static SacsContentTypeHelper()
{
// A few useful content types for reference.
contentTypes = new List<ContentTypeData>()
{
// Data.
new ContentTypeData_Internal("txt", "Text, (generally ASCII or ISO 8859-n)", "text/plain", Sacs.MimeType.Text),
new ContentTypeData_Internal("csv", "Comma separated variable", "text/csv", Sacs.MimeType.Csv),
new ContentTypeData_Internal("xml", "XML (not readable from casual users)", "application/xml", Sacs.MimeType.Xml) { PreferredContentType = "text/xml" },
new ContentTypeData_Internal("xml", "XML (readable from casual users)", "text/xml", Sacs.MimeType.Xml),
new ContentTypeData_Internal("zip", "ZIP archive", "application/x-zip-compressed", Sacs.MimeType.Zip),
new ContentTypeData_Internal("zip", "ZIP archive", "application/zip", Sacs.MimeType.Zip) { PreferredContentType = "application/x-zip-compressed" },
new ContentTypeData_Internal("bin", "Generic binary data", "application/octet-stream", Sacs.MimeType.Bin),
// Web.
new ContentTypeData_Internal("html,htm", "HyperText Markup Language (HTML)", "text/html", Sacs.MimeType.Html),
new ContentTypeData_Internal("css", "Cascading Style Sheets (CSS)", "text/css", Sacs.MimeType.Css),
new ContentTypeData_Internal("js", "JavaScript", "application/javascript", Sacs.MimeType.Javascript),
new ContentTypeData_Internal("js", "JavaScript", "text/javascript", Sacs.MimeType.Javascript) { PreferredContentType = "application/javascript" },
new ContentTypeData_Internal("json", "JSON format", "application/json", Sacs.MimeType.Json),
// Images.
new ContentTypeData_Internal("png", "Portable Network Graphics", "image/png", Sacs.MimeType.Png),
new ContentTypeData_Internal("jpg,jpeg", "JPEG images", "image/jpeg", Sacs.MimeType.Jpeg),
new ContentTypeData_Internal("bmp", "Windows OS/2 Bitmap Graphics", "image/bmp", Sacs.MimeType.Bmp),
new ContentTypeData_Internal("gif", "Graphics Interchange Format (GIF)", "image/gif", Sacs.MimeType.Gif),
new ContentTypeData_Internal("tif,tiff", "Tagged Image File Format (TIFF)", "image/tiff", Sacs.MimeType.Tif),
// Documents.
new ContentTypeData_Internal("pdf", "Adobe Portable Document Format (PDF)", "application/pdf", Sacs.MimeType.Pdf),
// Text documents.
new ContentTypeData_Internal("rtf", "Rich text format file", "application/rtf", Sacs.MimeType.Rtf),
new ContentTypeData_Internal("me", "ReadMe text file", "application/x-troff-me"),
new ContentTypeData_Internal("doc", "Microsoft Word", "application/msword", Sacs.MimeType.MsDoc),
new ContentTypeData_Internal("docx", "Microsoft Word (OpenXML)", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", Sacs.MimeType.MsDocx),
new ContentTypeData_Internal("odt", "OpenDocument text document", "application/vnd.oasis.opendocument.text", Sacs.MimeType.OpenDocText),
// Spreadsheets.
new ContentTypeData_Internal("xls", "Microsoft Excel", "application/vnd.ms-excel", Sacs.MimeType.MsXls),
new ContentTypeData_Internal("xlsx", "Microsoft Excel (OpenXML)", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", Sacs.MimeType.MsXlsx),
new ContentTypeData_Internal("ods", "OpenDocument spreadsheet document", "application/vnd.oasis.opendocument.spreadsheet", Sacs.MimeType.OpenDocSpreadsheet),
// Miscellaneous.
new ContentTypeData_Internal("aac", "AAC audio", "audio/aac"),
new ContentTypeData_Internal("abw", "AbiWord document", "application/x-abiword"),
new ContentTypeData_Internal("arc", "Archive document (multiple files embedded)", "application/x-freearc"),
new ContentTypeData_Internal("avi", "AVI: Audio Video Interleave", "video/x-msvideo"),
new ContentTypeData_Internal("azw", "Amazon Kindle eBook format", "application/vnd.amazon.ebook"),
new ContentTypeData_Internal("bz", "BZip archive", "application/x-bzip"),
new ContentTypeData_Internal("bz2", "BZip2 archive", "application/x-bzip2"),
new ContentTypeData_Internal("csh", "C-Shell script", "application/x-csh"),
new ContentTypeData_Internal("csv", "Comma-separated values (CSV)", "text/csv"),
new ContentTypeData_Internal("eot", "MS Embedded OpenType fonts", "application/vnd.ms-fontobject"),
new ContentTypeData_Internal("epub", "Electronic publication (EPUB)", "application/epub+zip"),
new ContentTypeData_Internal("gz", "GZip Compressed Archive", "application/x-gzip"),
new ContentTypeData_Internal("gz", "GZip Compressed Archive", "application/gzip") { PreferredContentType = "application/x-gzip" },
new ContentTypeData_Internal("ico", "Icon format", "image/x-icon"),
new ContentTypeData_Internal("ico", "Icon format", "image/vnd.microsoft.icon") { PreferredContentType = "image/x-icon" },
new ContentTypeData_Internal("ics", "iCalendar format", "text/calendar"),
new ContentTypeData_Internal("jar", "Java Archive (JAR)", "application/java-archive"),
new ContentTypeData_Internal("jsonld", "JSON-LD format", "application/ld+json"),
new ContentTypeData_Internal("midi,mid", "Musical Instrument Digital Interface (MIDI)", "audio/mid"),
new ContentTypeData_Internal("midi,mid", "Musical Instrument Digital Interface (MIDI)", "audio/midi") { PreferredContentType = "audio/mid" },
new ContentTypeData_Internal("midi,mid", "Musical Instrument Digital Interface (MIDI)", "audio/x-midi") { PreferredContentType = "audio/mid" },
new ContentTypeData_Internal("mjs", "JavaScript module", "text/javascript"),
new ContentTypeData_Internal("mp3", "MP3 audio", "audio/mpeg"),
new ContentTypeData_Internal("mpeg", "MPEG Video", "video/mpeg"),
new ContentTypeData_Internal("mpkg", "Apple Installer Package", "application/vnd.apple.installer+xml"),
new ContentTypeData_Internal("odp", "OpenDocument presentation document", "application/vnd.oasis.opendocument.presentation"),
new ContentTypeData_Internal("oga", "OGG audio", "audio/ogg"),
new ContentTypeData_Internal("ogv", "OGG video", "video/ogg"),
new ContentTypeData_Internal("ogx", "OGG", "application/ogg"),
new ContentTypeData_Internal("opus", "Opus audio", "audio/opus"),
new ContentTypeData_Internal("otf", "OpenType font", "font/otf"),
new ContentTypeData_Internal("php", "Hypertext Preprocessor (Personal Home Page)", "application/x-httpd-php"),
new ContentTypeData_Internal("ppt", "Microsoft PowerPoint", "application/vnd.ms-powerpoint"),
new ContentTypeData_Internal("pptx", "Microsoft PowerPoint (OpenXML)", "application/vnd.openxmlformats-officedocument.presentationml.presentation"),
new ContentTypeData_Internal("rar", "RAR archive", "application/vnd.rar"),
new ContentTypeData_Internal("rtf", "Rich Text Format (RTF)", "application/rtf"),
new ContentTypeData_Internal("sh", "Bourne shell script", "application/x-sh"),
new ContentTypeData_Internal("svg", "Scalable Vector Graphics (SVG)", "image/svg+xml"),
new ContentTypeData_Internal("swf", "Small web format (SWF) or Adobe Flash document", "application/x-shockwave-flash"),
new ContentTypeData_Internal("tar", "Tape Archive (TAR)", "application/x-tar"),
new ContentTypeData_Internal("ts", "MPEG transport stream", "video/vnd.dlna.mpeg-tts"),
new ContentTypeData_Internal("ts", "MPEG transport stream", "video/mp2t") { PreferredContentType = "video/vnd.dlna.mpeg-tts" },
new ContentTypeData_Internal("ttf", "TrueType Font", "application/x-font-ttf"),
new ContentTypeData_Internal("ttf", "TrueType Font", "font/ttf") { PreferredContentType = "application/x-font-ttf" },
new ContentTypeData_Internal("vsd", "Microsoft Visio", "application/vnd.visio"),
new ContentTypeData_Internal("wav", "Waveform Audio Format", "audio/wav"),
new ContentTypeData_Internal("webm", "WEBM video", "video/webm"),
new ContentTypeData_Internal("weba", "WEBM audio", "audio/webm"),
new ContentTypeData_Internal("webp", "WEBP image", "image/webp"),
new ContentTypeData_Internal("woff", "Web Open Font Format (WOFF)", "application/font-woff"),
new ContentTypeData_Internal("woff", "Web Open Font Format (WOFF)", "font/woff") { PreferredContentType = "application/font-woff" },
new ContentTypeData_Internal("woff2", "Web Open Font Format (WOFF)", "font/woff2"),
new ContentTypeData_Internal("xhtml", "XHTML", "application/xhtml+xml"),
new ContentTypeData_Internal("xul", "XUL", "application/vnd.mozilla.xul+xml"),
new ContentTypeData_Internal("3gp", "3GPP video container", "video/3gpp"),
new ContentTypeData_Internal("3gp", "3GPP audio container", "audio/3gpp") { PreferredContentType = "video/3gpp" },
new ContentTypeData_Internal("3g2", "3GPP2 video container", "video/3gpp2"),
new ContentTypeData_Internal("3g2", "3GPP2 audio container", "audio/3gpp2") { PreferredContentType = "video/3gpp2" },
new ContentTypeData_Internal("7z", "7-zip archive", "application/x-7z-compressed")
};
}
//-------------------------------------------------------------------
// Properties.
/// <summary>Generic content type used for 'unknown' document types.</summary>
public static String ContentTypeDefault { get; } = "application/octet-stream";
/// <summary>Selection of comon content types.</summary>
public static List<ContentTypeData> ContentTypes { get { return new List<ContentTypeData>(contentTypes); } }
public static FileExtensionContentTypeProvider Provider
{
get
{
if (provider == null)
provider = new FileExtensionContentTypeProvider();
return provider;
}
}
//-------------------------------------------------------------------
/// <summary>Generic content types that might have a better preferred content type when converting, eg. from extension.</summary>
private static readonly List<String> genericContentTypes = new List<string>() { "application/octet-stream", "application/oleobject" };
/// <summary>
/// Given a file path, determine the MIME type.
/// <para>Ref. NuGet package Microsoft.AspNetCore.StaticFiles</para>
/// </summary>
public static String GetContentTypeFromFilename(this String fileName)
{
string contentType = "";
if (!Provider.TryGetContentType(fileName, out contentType) || genericContentTypes.ContainsCI(contentType))
{
// Locate suitable 'common' content type definition.
String extension = Regex.Replace(Path.GetExtension(fileName), "^\\.", "");
// Use the 'primary' definition for the extension, with no 'preferred' content type.
ContentTypeData contentTypeData = contentTypes.Find(item => item.Extensions.ContainsCI(extension) && StringUtil.IsEmpty(item.PreferredContentType));
if (contentTypeData != null)
contentType = contentTypeData.ContentType;
}
if (StringUtil.IsEmpty(contentType))
contentType = ContentTypeDefault;
return contentType;
}
//----------------------------------------------------------------------
/// <summary>
/// Interpret the content type for the specified file.
/// <para>- The file's content type if not generic (application/octet-stream, application/oleobject).</para>
/// <para>- The content type derived from the file's extension if available</para>
/// <para>- Generic content type: application/octet-stream.</para>
/// </summary>
public static String GetContentTypeFromFormFile(String contentType, String fileName)
{
// Return file's content type if specific.
if (!StringUtil.IsEmpty(contentType) && !genericContentTypes.ContainsCI(contentType))
return contentType;
// Otherwise, interpret filename's content type.
if (!StringUtil.IsEmpty(fileName))
return SacsContentTypeHelper.GetContentTypeFromFilename(fileName);
return ContentTypeDefault;
}
/// <summary>
/// Interpret the content type for the specified file.
/// <para>- The file's content type if not generic (application/octet-stream, application/oleobject).</para>
/// <para>- The content type derived from the file's extension if available</para>
/// <para>- Generic content type: application/octet-stream.</para>
/// </summary>
public static String GetContentTypeFromFormFile(this IFormFile formFile)
{
return GetContentTypeFromFormFile(formFile.ContentType, formFile.FileName);
}
//----------------------------------------------------------------------
/// <summary>Convert the content type to enumerated Mime.</summary>
public static Sacs.MimeType GetMimeTypeFromContentType(this String contentType)
{
if (StringUtil.IsEmpty(contentType)) return Sacs.MimeType.Unknown;
ContentTypeData contentTypeData = contentTypes.Find(item => item.ContentType.EqualsCI(contentType));
if (contentTypeData != null)
return contentTypeData.Mime;
return Sacs.MimeType.Unknown;
}
//----------------------------------------------------------------------
}
//==========================================================================
}
@@ -0,0 +1,266 @@
using CsvHelper;
using CsvHelper.Configuration;
using Sarand.Net.Standard.Base.Core;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
namespace Sarand.Net.Standard.Base.Helpers
{
//=======================================================================
public static class SacsCsvHelper
{
//-------------------------------------------------------------------
// Definitions.
/// <summary>
/// Encapsulate CSV Reader and the text object that it is to parse.
/// </summary>
private class ReaderClass : SacsDisposable
{
public ReaderClass() : this(DefaultCulture) { }
public ReaderClass(CultureInfo culture)
{
Reader = new StringReader("");
CsvReader = new CsvReader(Reader, culture ?? DefaultCulture);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
CsvReader.Dispose();
Reader.Dispose();
}
}
public StringReader Reader { get; }
public CsvReader CsvReader { get; }
}
/// <summary>
/// Encapsulate CSV Writer and the text stream that it is to generate.
/// </summary>
private class WriterClass : SacsDisposable
{
// Construction.
public WriterClass() : this(DefaultCulture) { }
public WriterClass(CultureInfo culture)
{
Writer = new StringWriter() { NewLine = "" };
CsvWriter = new CsvWriter(Writer, culture ?? DefaultCulture);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
CsvWriter.Dispose();
Writer.Dispose();
}
}
// Properties.
public StringWriter Writer { get; }
public CsvWriter CsvWriter { get; }
// To CSV.
public String ToCsv(IEnumerable<String> values)
{
foreach (String field in values)
CsvWriter.WriteField(field);
CsvWriter.NextRecord();
// NB Shouldn't need to strip line delimiters as the writer's NewLine is blank but CsvHelper v16 still adds the delimiter.
String record = Writer.GetStringBuilder().ToString().Replace("\r", "").Replace("\n", "");
// Clear the String Writer data. [Ref. https://stackoverflow.com/questions/12839982/clear-all-content-in-xmltextwriter-and-stringwriter]
Writer.GetStringBuilder().Clear();
return record;
}
}
//-------------------------------------------------------------------
// Properties.
public static CultureInfo DefaultCulture { get; set; } = CultureInfo.InvariantCulture;
//-------------------------------------------------------------------
// C o n f i g u r a t i o n D e f a u l t s
//-------------------------------------------------------------------
// AllowComments false bool
// BadDataFound {Method = {Void BadDataFound(CsvHelper.ReadingContext)}} System.Action<CsvHelper.ReadingContext>
// BufferSize 2048 int
// Comment 35 '#' char
// CountBytes false bool
// CultureInfo {en-GB} System.Globalization.CultureInfo
// Delimiter "," string
// DetectColumnCountChanges false bool
// DoubleQuoteString "\"\"" string
// DynamicPropertySort null System.Collections.Generic.IComparer<string>
// Encoding {System.Text.UTF8Encoding} System.Text.Encoding {System.Text.UTF8Encoding}
// Escape 34 '"' char
// GetConstructor {Method = {System.Reflection.ConstructorInfo GetConstructor(System.Type)}} System.Func<System.Type, System.Reflection.ConstructorInfo>
// HasHeaderRecord true bool
// HeaderValidated {Method = {Void HeaderValidated(Boolean, System.String[], Int32, CsvHelper.ReadingContext)}} System.Action<bool, string[], int, CsvHelper.ReadingContext>
// IgnoreBlankLines true bool
// IgnoreQuotes false bool
// IgnoreReferences false bool
// IncludePrivateMembers false bool
// InjectionCharacters {char[4]} char[]
// InjectionEscapeCharacter 9 '\t' char
// LineBreakInQuotedFieldIsBadData false bool
// Maps {CsvHelper.Configuration.ClassMapCollection} CsvHelper.Configuration.ClassMapCollection
// MemberTypes Properties CsvHelper.Configuration.MemberTypes
// MissingFieldFound {Method = {Void MissingFieldFound(System.String[], Int32, CsvHelper.ReadingContext)}} System.Action<string[], int, CsvHelper.ReadingContext>
// PrepareHeaderForMatch {Method = {System.String PrepareHeaderForMatch(System.String, Int32)}} System.Func<string, int, string>
// Quote 34 '"' char
// QuoteString "\"" string
// ReadingExceptionOccurred {Method = {Boolean ReadingExceptionOccurred(CsvHelper.CsvHelperException)}} System.Func<CsvHelper.CsvHelperException, bool>
// ReferenceHeaderPrefix null System.Func<System.Type, string, string>
// SanitizeForInjection false bool
// ShouldQuote {Method = {Boolean ShouldQuote(System.String, CsvHelper.WritingContext)}} System.Func<string, CsvHelper.WritingContext, bool>
// ShouldSkipRecord {Method = {Boolean ShouldSkipRecord(System.String[])}} System.Func<string[], bool>
// ShouldUseConstructorParameters {Method = {Boolean ShouldUseConstructorParameters(System.Type)}} System.Func<System.Type, bool>
// TrimOptions None CsvHelper.Configuration.TrimOptions
// TypeConverterCache {CsvHelper.TypeConversion.TypeConverterCache} CsvHelper.TypeConversion.TypeConverterCache
// TypeConverterOptionsCache {CsvHelper.TypeConversion.TypeConverterOptionsCache} CsvHelper.TypeConversion.TypeConverterOptionsCache
// UseNewObjectForNullReferenceMembers true bool
//-------------------------------------------------------------------
public class ParserConfig /* IParserConfiguration */
{
/// <summary>Culture</summary>
public CultureInfo Culture { get; set; } = CultureInfo.InvariantCulture;
/// <summary>Gets or sets the size of the buffer used for reading CSV files. Default: 2048.</summary>
public int BufferSize { get; set; } = 2048;
/// <summary>
/// Gets or sets a value indicating whether the number of bytes should be counted while parsing.
/// <para>This will slow down parsing because it needs to get the byte count of every char for the given encoding.</para>
/// <para>The CsvHelper.Configuration.IParserConfiguration.Encoding needs to be set correctly for this to be accurate.</para>
/// <para>Default: false.</para>
/// </summary>
public bool CountBytes { get; set; } = false;
/// <summary>Gets or sets the encoding used when counting bytes.</summary>
public Encoding Encoding { get; set; } = Encoding.UTF8;
/// <summary>
/// Gets or sets the function that is called when bad field data is found.
/// <para>A field has bad data if it contains a quote and the field is not quoted (escaped).</para>
/// <para>You can supply your own function to do other things like logging the issue instead of throwing an exception.</para>
/// <para>Arguments: context</para>
/// </summary>
public Action<ReadingContext> BadDataFound { get; set; }
/// <summary>
/// Gets or sets a value indicating if a line break found in a quote field should be considered bad data.
/// <para>True to consider a line break bad data, otherwise false.</para>
/// <para>Defaults to false.</para>
/// </summary>
public bool LineBreakInQuotedFieldIsBadData { get; set; } = false;
/// <summary>
/// Gets or sets the character used to denote a line that is commented out.
/// <para>Default: '#'.</para>
/// </summary>
public char Comment { get; set; } = '#';
/// <summary>
/// <para>Gets or sets a value indicating if comments are allowed.</para>
/// <para>True to allow commented out lines, otherwise false (default).</para></summary>
public bool AllowComments { get; set; } = false;
/// <summary>
/// Gets or sets a value indicating if blank lines should be ignored when reading.
/// <para>True to ignore, otherwise false.</para>
/// <para>Default: true.</para>
/// </summary>
public bool IgnoreBlankLines { get; set; } = true;
/// <summary>Gets or sets a value indicating if quotes should be ingored when parsing and treated like any other character.</summary>
public bool IgnoreQuotes { get; set; } = false;
/// <summary>
/// Gets or sets the character used to quote fields.
/// <para>Default: '"'.</para>
/// </summary>
public char Quote { get; set; } = '"';
/// <summary>
/// Gets or sets the delimiter used to separate fields.
/// <para>Default: CultureInfo.CurrentCulture.TextInfo.ListSeparator (',').</para>
/// </summary>
public string Delimiter { get; set; }
/// <summary>
/// Gets or sets the escape character used to escape a quote inside a field.
/// <para>Default: '"'.</para>
/// </summary>
public char Escape { get; set; } = '"';
/// <summary>
/// Gets or sets the field trimming options.
/// <para>Default: None</para>
/// </summary>
public TrimOptions TrimOptions { get; set; } = TrimOptions.None;
}
//-------------------------------------------------------------------
// C o n v e r t T o C S V
//-------------------------------------------------------------------
public static List<String[]> ParseCsv(String data, ParserConfig parserConfig = null)
{
List<String[]> records = new List<string[]>();
using (TextReader reader = new StringReader(data))
using (CsvParser csvParser = new CsvParser(reader, parserConfig?.Culture ?? CultureInfo.InvariantCulture))
{
if (parserConfig != null)
{
if (parserConfig.BufferSize > 0)
csvParser.Configuration.BufferSize = parserConfig.BufferSize;
csvParser.Configuration.CountBytes = parserConfig.CountBytes;
csvParser.Configuration.Encoding = parserConfig.Encoding;
if (parserConfig.BadDataFound != null)
csvParser.Configuration.BadDataFound = parserConfig.BadDataFound;
csvParser.Configuration.LineBreakInQuotedFieldIsBadData = parserConfig.LineBreakInQuotedFieldIsBadData;
csvParser.Configuration.Comment = parserConfig.Comment;
csvParser.Configuration.AllowComments = parserConfig.AllowComments;
csvParser.Configuration.IgnoreBlankLines = parserConfig.IgnoreBlankLines;
csvParser.Configuration.IgnoreQuotes = parserConfig.IgnoreQuotes;
csvParser.Configuration.Quote = parserConfig.Quote;
if (parserConfig.Delimiter != null)
csvParser.Configuration.Delimiter = parserConfig.Delimiter;
csvParser.Configuration.Escape = parserConfig.Escape;
csvParser.Configuration.TrimOptions = parserConfig.TrimOptions;
}
while (true)
{
String[] record = csvParser.Read();
if (record == null) break;
records.Add(record);
}
}
return records;
}
//-------------------------------------------------------------------
// C o n v e r t T o C S V
//-------------------------------------------------------------------
// Single record.
public static String ToCsv(IEnumerable<String> values)
{
return ToCsv(values, DefaultCulture);
}
public static String ToCsv(IEnumerable<String> values, CultureInfo culture)
{
String record = "";
using (WriterClass writer = new WriterClass(culture ?? DefaultCulture))
{
record = writer.ToCsv(values);
}
return record;
}
//-------------------------------------------------------------------
// Multiple records.
public static List<String> ToCsv(IEnumerable<IEnumerable<String>> data)
{
return ToCsv(data, DefaultCulture);
}
public static List<String> ToCsv(IEnumerable<IEnumerable<String>> data, CultureInfo culture)
{
List<String> records = new List<string>();
using (WriterClass writer = new WriterClass(culture ?? DefaultCulture))
{
foreach (String[] values in data)
records.Add(writer.ToCsv(values));
}
return records;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,87 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
using System.Text.RegularExpressions;
namespace Sarand.Net.Standard.Base.Helpers
{
//=======================================================================
public static class SacsDataValidationHelper
{
//-------------------------------------------------------------------
/// <summary>
/// Validate the email address.
/// <para>Ref. https://stackoverflow.com/questions/1365407/c-sharp-code-to-validate-email-address</para>
/// </summary>
public static bool IsValidEmailAddress(String value)
{
if (StringUtil.IsEmpty(value)) return false;
if (!new EmailAddressAttribute().IsValid(value)) return false;
// Exclude spaces.
if (Regex.Matches(value, " ").Count > 0) return false;
// Exclude consecutive dots.
if (Regex.Matches(value, "\\.\\.").Count > 0) return false;
// Check for at least one dot after @ [to ensure john@smith is invalid].
if (Regex.Matches(value, "@[^@.]+\\.").Count < 1) return false;
return true;
}
//-------------------------------------------------------------------
/// <summary>
/// Validate the phone number.
/// <para>Ref. https://www.twilio.com/blog/validating-phone-numbers-effectively-with-c-and-the-net-frameworks</para>
/// </summary>
public static bool IsValidPhone(String value)
{
if (StringUtil.IsEmpty(value)) return false;
if (!new PhoneAttribute().IsValid(value)) return false;
// Apply minimum length.
if (StringUtil.GetLength(value) < 8) return false;
return true;
}
//-------------------------------------------------------------------
// Tax identification number.
// European country Tax Identification Numbers:
// https://ec.europa.eu/taxation_customs/vies/faqvies.do#item_11
//-------------------------------------------------------------------
/// <summary>
/// Validate the tax identification number.
/// </summary>
public static bool IsValidTaxIdentificationNumber(String countryCode, String value)
{
if (StringUtil.IsEmpty(value)) return false;
//---------------------------------------------------------------
// GB, United Kingdom.
// Standard:
// GB999 9999 99 block of 3 digits, block of 4 digits and block of 2 digits [00-96]
// Branch:
// GB999 9999 99 9995 as above followed by block of 3 digits
// Government departments:
// GBGD9996 'GD' followed by block of 3 or 4 digits
// Health Authoritites:
// GBHA9997 'HA' followed by block of 3 or 4 digits
//---------------------------------------------------------------
// Apply minimum length.
if (StringUtil.GetLength(value) < 8) return false;
// Country prefix.
if (!value.StartsWith("GB")) return false;
return true;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,128 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace Sarand.Net.Standard.Base.Helpers
{
//=======================================================================
public static class SacsEncryptionHelper
{
//-------------------------------------------------------------------
/// <summary>Number of byes in key. [32 bytes = 256 bits]</summary>
public static int KeyLength { get; } = 32;
/// <summary>Default encoding: UTF8.</summary>
public static Encoding DefaultEncoding { get; } = Encoding.UTF8;
//-------------------------------------------------------------------
// Symmetric Encryption in .NET Core
// System.Security.Cryptography implements and provides the APIs for encryption in .NET Core.
// Ref. https://damienbod.com/2020/08/19/symmetric-and-asymmetric-encryption-in-net-core/
//-------------------------------------------------------------------
public static bool IsBase64(String value, int expectedLength = 0)
{
try
{
Byte[] decoded = Convert.FromBase64String(value);
if (expectedLength > 0 && decoded.Length != expectedLength)
return false;
}
catch (Exception) { return false; }
return true;
}
public static String EncodePlainKey(String plainKey, int keyLength = 32, Encoding encoding = null)
{
if (StringUtil.IsEmpty(plainKey))
throw new NotSupportedException("Plain key must not be null/blank");
// Ensure key if 32 bytes long.
while (StringUtil.GetLength(plainKey) < keyLength)
plainKey += plainKey;
plainKey = StringUtil.Left(plainKey, keyLength);
// Encode to base-64.
encoding = encoding ?? DefaultEncoding;
return Convert.ToBase64String(encoding.GetBytes(plainKey));
}
//-------------------------------------------------------------------
// Generate random key and IV.
// NB Can use own key if suitable - 32 character value in base-64 format.
public static String InitSymmetricEncryptionKey()
{
var key = GetEncodedRandomString(KeyLength); // 256 bits.
return key;
}
public static string InitSymmetricEncryptionIV(String key)
{
Aes cipher = CreateCipher(key);
var IVBase64 = Convert.ToBase64String(cipher.IV);
return IVBase64;
}
public static (string Key, string IVBase64) InitSymmetricEncryptionKeyIV()
{
var key = InitSymmetricEncryptionKey();
var IVBase64 = InitSymmetricEncryptionIV(key);
return (key, IVBase64);
}
//-------------------------------------------------------------------
public static string GetEncodedRandomString(int length)
{
var base64 = Convert.ToBase64String(GenerateRandomBytes(length));
return base64;
}
private static Aes CreateCipher(string keyBase64)
{
// Default values: Keysize 256 bits, Padding PKC27.
Aes cipher = Aes.Create();
// Ensure the integrity of the ciphertext if using CBC
cipher.Mode = CipherMode.CBC;
cipher.Padding = PaddingMode.ISO10126;
byte[] rawKey = Convert.FromBase64String(keyBase64);
String rawKeyValue = System.Text.Encoding.Default.GetString(rawKey);
cipher.Key = rawKey;
return cipher;
}
private static byte[] GenerateRandomBytes(int length)
{
var byteArray = new byte[length];
SacsRandomHelper.Fill(byteArray);
return byteArray;
}
//-------------------------------------------------------------------
public static string Encrypt(string text, string IV, string key)
{
Aes cipher = CreateCipher(key);
cipher.IV = Convert.FromBase64String(IV);
ICryptoTransform cryptTransform = cipher.CreateEncryptor();
byte[] plaintext = Encoding.UTF8.GetBytes(text);
byte[] cipherText = cryptTransform.TransformFinalBlock(plaintext, 0, plaintext.Length);
return Convert.ToBase64String(cipherText);
}
//-------------------------------------------------------------------
public static string Decrypt(string encryptedText, string IV, string key)
{
Aes cipher = CreateCipher(key);
cipher.IV = Convert.FromBase64String(IV);
ICryptoTransform cryptTransform = cipher.CreateDecryptor();
byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
byte[] plainBytes = cryptTransform.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(plainBytes);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,253 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Tasks;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Sarand.Net.Standard.Base.Helpers
{
//=======================================================================
public static class SacsHttpClientHelper
{
//-------------------------------------------------------------------
/// <summary>Request configuration</summary>
public class RequestData : SacsTaskData
{
// Construction.
public RequestData(CancellationToken? cancellationToken) : base(cancellationToken) { }
/// <summary>URL to send request to.</summary>
public UriBuilder UriBuilder { get; } = new UriBuilder();
/// <summary>
/// Request timeout. Default: 5 secs.
/// <para>NB Not currently supported as can only be changed when static HTTP Client not in use.</para>
/// </summary>
public int TimeoutSecs { get; set; } = RequestTimeoutSecs_Default;
/// <summary>
/// Headers to send with request.
/// <para>Accept, Accept-Charset, Accept-Encoding, Accept-Language, User-Agent, Transfer-Encoding, Pragma, Expect etc.</para>
/// </summary>
public Dictionary<String, List<String>> RequestHeaders { get; } = new Dictionary<String, List<String>>();
/// <summary>
/// Content Headers to send with request.
/// <para>Content-Length (bytes), Content-Type (media type), Content-Encoding (compression algorithm), Content-Language etc.</para>
/// <para>Content-Type header is defaulted for POST request if not specified.</para>
/// </summary>
public Dictionary<String, List<String>> ContentHeaders { get; } = new Dictionary<String, List<String>>();
/// <summary>
/// Form values to post as 'URL Encoded'.
/// <para>Content-Type defaults to 'application/x-www-form-urlencoded; charset=utf-8'.</para>
/// </summary>
public List<KeyValuePair<string, string>> FormData { get; } = new List<KeyValuePair<string, string>>();
/// <summary>
/// Data to POST. Ignored if FormData populated.
/// <para>Content-Type defaults to 'text/plain; charset=utf-8'.</para>
/// </summary>
public String PostData { get; set; }
/// <summary>Use POST request rather than GET even if no data to post.</summary>
public bool ForcePost { get; set; }
}
//-------------------------------------------------------------------
/// <summary>Response data</summary>
public class ResponseData
{
public DateTime RequestStarted { get; set; }
public DateTime RequestCompleted { get; set; }
/// <summary>Response headers.</summary>
public Dictionary<String, IEnumerable<String>> ResponseHeaders { get; } = new Dictionary<String, IEnumerable<String>>();
/// <summary>Response content headers.</summary>
public Dictionary<String, IEnumerable<String>> ContentHeaders { get; } = new Dictionary<String, IEnumerable<String>>();
/// <summary>Indicates whether Status Code represents success.</summary>
public bool Success { get; set; }
/// <summary>HTTP Status Code.</summary>
public HttpStatusCode StatusCode { get; set; }
/// <summary>HTTP message version. Default: 1.1</summary>
public Version Version { get; set; }
/// <summary>HTTP Reason Code.</summary>
public String ReasonPhrase { get; set; } = "";
/// <summary>Response data.</summary>
public String Data { get; set; } = "";
/// <summary>Elapsed time for request.</summary>
public TimeSpan Elapsed { get; set; }
/// <summary>Exception thrown during handling of request.</summary>
public Exception Exception { get; set; }
/// <summary>Error state message - generally exception type and message.</summary>
public String ErrorStateMessage { get; set; }
}
//-------------------------------------------------------------------
// Data members.
private static readonly HttpClient httpClient;
//-------------------------------------------------------------------
// Static initialisation.
static SacsHttpClientHelper ()
{
// Configure client.
httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(0, 0, RequestTimeoutSecs_Default);
}
//-------------------------------------------------------------------
// Properties.
public static HttpClient HttpClient { get { return httpClient; } }
public static int RequestTimeoutSecs_Default { get; } = 5;
public static String HeaderName_ContentType { get; } = "Content-Type";
//-------------------------------------------------------------------
public static async Task<ResponseData> DoRequest (RequestData requestData)
{
String fn = "SacsHttpClientHelper.DoRequest";
requestData.ThrowIfCancellationRequested();
ResponseData responseData = new ResponseData();
// Construct content to post.
HttpContent postContent = null;
if (requestData.FormData.Count > 0)
{
postContent = new FormUrlEncodedContent(requestData.FormData);
if (!requestData.ContentHeaders.ContainsKey(HeaderName_ContentType))
requestData.ContentHeaders.Add(HeaderName_ContentType, "application/x-www-form-urlencoded; charset=utf-8");
}
else if (!StringUtil.IsEmpty(requestData.PostData) || requestData.ForcePost)
{
postContent = new StringContent(StringUtil.EmptyOnNull(requestData.PostData), Encoding.UTF8);
if (!requestData.ContentHeaders.ContainsKey(HeaderName_ContentType))
requestData.ContentHeaders.Add(HeaderName_ContentType, "text/plain; charset=utf-8");
}
requestData.ThrowIfCancellationRequested();
// Make request.
DateTime startedAt = DateTime.Now;
try
{
// Request.
using (HttpRequestMessage request = new HttpRequestMessage())
{
request.RequestUri = requestData.UriBuilder.Uri;
// Request headers.
foreach (String headerName in requestData.RequestHeaders.Keys)
{
if (request.Headers.Contains(headerName))
request.Headers.Remove(headerName);
request.Headers.Add(headerName, requestData.RequestHeaders[headerName]);
}
// Default request headers.
if (HttpClient.DefaultRequestHeaders.Accept.Count == 0 && request.Headers.Accept.Count == 0)
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/*"));
// Configure request.
HttpResponseMessage response = null;
// Send request.
if (postContent != null)
{
// POST.
request.Method = HttpMethod.Post;
request.Content = postContent;
// Content headers.
foreach (String headerName in requestData.ContentHeaders.Keys)
{
if (request.Content.Headers.Contains(headerName))
request.Content.Headers.Remove(headerName);
request.Content.Headers.Add(headerName, requestData.ContentHeaders[headerName]);
}
// Send request.
responseData.RequestStarted = DateTime.Now;
response = await HttpClient.SendAsync(request, requestData.CancellationToken);
responseData.RequestCompleted = DateTime.Now;
}
else
{
// GET.
request.Method = HttpMethod.Get;
responseData.RequestStarted = DateTime.Now;
response = await HttpClient.SendAsync(request, requestData.CancellationToken);
responseData.RequestCompleted = DateTime.Now;
}
// Extract response data.
responseData.Version = response.Version;
responseData.Success = response.IsSuccessStatusCode;
responseData.StatusCode = response.StatusCode;
responseData.ReasonPhrase = response.ReasonPhrase;
if (response.Headers != null)
{
foreach (var header in response.Headers)
responseData.ResponseHeaders[header.Key] = new List<String>(header.Value);
}
if (response.Content != null && response.Content.Headers != null)
{
foreach (var header in response.Content.Headers)
responseData.ContentHeaders[header.Key] = new List<String>(header.Value);
}
responseData.Data = await response.Content.ReadAsStringAsync();
if (response != null) response.Dispose();
}
}
catch (Exception exc)
{
// Ignore if task has been cancelled.
if (requestData.IsCancellationRequested) throw exc;
// Record exception.
responseData.Exception = exc;
if (exc.InnerException != null)
{
exc = exc.InnerException;
}
String msg = exc.GetType().Name + ": " + exc.Message;
SaLogger.Warn(fn + " " + msg + ExceptionUtil.GetStackEntries(exc, 6).Concat("", "\n\t"));
responseData.ErrorStateMessage = msg;
}
requestData.ThrowIfCancellationRequested();
// Complete response data.
responseData.Elapsed = DateTime.Now - startedAt;
return responseData;
}
//-------------------------------------------------------------------
// R e s p o n s e S t a t u s D e s c r i p t i o n
//-------------------------------------------------------------------
public static String GetResponseStatusDescription (HttpStatusCode httpStatus)
{
// Ref. https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
switch (httpStatus)
{
// 1xx: Informational - Request received, continuing process.
case HttpStatusCode.Continue: return "Continue";
// 2xx: Success - The action was successfully received, understood, and accepted.
case HttpStatusCode.OK: return "OK";
case HttpStatusCode.Created: return "Created";
case HttpStatusCode.Accepted: return "Accepted";
// 3xx: Redirection - Further action must be taken in order to complete the request.
case HttpStatusCode.MultipleChoices: return "Multiple choices";
case HttpStatusCode.MovedPermanently: return "Moved permanently";
case HttpStatusCode.Found: return "Found";
// 4xx: Client Error -The request contains bad syntax or cannot be fulfilled.
case HttpStatusCode.BadRequest: return "Bad request";
case HttpStatusCode.Unauthorized: return "Unauthorized";
case HttpStatusCode.PaymentRequired: return "Payment required";
case HttpStatusCode.Forbidden: return "Forbidden";
case HttpStatusCode.NotFound: return "Not found";
case HttpStatusCode.MethodNotAllowed: return "Method not allowed";
case HttpStatusCode.NotAcceptable: return "Not acceptable";
// 5xx: Server Error -The server failed to fulfill an apparently valid request.
case HttpStatusCode.InternalServerError: return "Internal server error";
}
return httpStatus.ToString();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,20 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace Sarand.Net.Standard.Base.Helpers
{
//=======================================================================
public static class SacsJsonHelper
{
//-------------------------------------------------------------------
public static dynamic DeserializeJsonObject(String data)
{
return JsonConvert.DeserializeObject<dynamic>(data);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace Sarand.Net.Standard.Base.Helpers
{
//=======================================================================
public static class SacsRandomHelper
{
//-------------------------------------------------------------------
// Properties.
public static RandomNumberGenerator RandomNumberGenerator { get; } = RandomNumberGenerator.Create();
private static Random random;
public static Random Random { get { if (random == null) random = new Random(GetInt32(Int32.MaxValue)); return random; } }
public static void Fill(byte[] byteArray)
{
// ToDo RandomNumberGenerator.Fill(byteArray);
RandomNumberGenerator.GetBytes(byteArray);
}
//-------------------------------------------------------------------
/// <summary>
/// Generates a random integer between 0 (inclusive) and a specified exclusive upper
/// bound using a cryptographically strong random number generator.
/// </summary>
/// <param name="toExclusive">The exclusive upper bound of the random range.</param>
/// <returns>A random integer between 0 (inclusive) and toExclusive (exclusive).</returns>
/// <exception cref="ArgumentOutOfRangeException">The toExclusive parameter is less than or equal to 0.</exception>
public static int GetInt32(int toExclusive)
{
return RandomNumberGenerator.GetInt32(toExclusive);
//return Random.Next(toExclusive);
}
//-------------------------------------------------------------------
/// <summary>
/// Generates a random integer between a specified inclusive lower bound and a specified
/// exclusive upper bound using a cryptographically strong random number generator.
/// </summary>
/// <param name="fromInclusive">The inclusive lower bound of the random range.</param>
/// <param name="toExclusive">The exclusive upper bound of the random range.</param>
/// <returns>A random integer between fromInclusive (inclusive) and toExclusive (exclusive).</returns>
/// <exception cref="ArgumentOutOfRangeException">The toExclusive parameter is less than or equal to the fromInclusive parameter.</exception>
public static int GetInt32(int fromInclusive, int toExclusive)
{
return RandomNumberGenerator.GetInt32(fromInclusive, toExclusive);
//return Random.Next(fromInclusive, toExclusive);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,243 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
namespace Sarand.Net.Standard.Base.Helpers
{
//=======================================================================
public static class SacsResourceHelper
{
//-------------------------------------------------------------------
// Definitions.
public enum TextResource
{
SaBaseCss,
SaBaseJs,
JQueryJs,
JQueryUiCss,
JQueryUiJs,
}
public enum ImageResource
{
// Burgers.
Icon_Burger_Black_48_png,
Icon_Burger_Black_64_png,
// Arrows.
Arrow_Left_Black_16_png,
Arrow_Left_Double_Black_16_png,
Arrow_Right_Black_16_png,
Arrow_Right_Double_Black_16_png,
Arrow_Left_Black_24_png,
Arrow_Left_Double_Black_24_png,
Arrow_Right_Black_24_png,
Arrow_Right_Double_Black_24_png,
// IconShock.
IconShock_Arrow_Down_Purple_72_png,
IconShock_Arrow_Right_Purple_72_png,
IconShock_Add_Green_72_png,
IconShock_Pencil_Orange_72_png,
IconShock_Close_Red_72_png,
IconShock_TrashCan_Grey_72_png,
}
//-------------------------------------------------------------------
// NB 'Properties' not available in Core .Net project.
// Resources must be loaded via csproj so that they are available in the Manifest Resources:
// <ItemGroup>
// <EmbeddedResource Include="Properties\Resources.resx">
// <Generator>ResXFileCodeGenerator</Generator>
// <LastGenOutput>Resources.Designer.cs</LastGenOutput>
// </EmbeddedResource>
// <EmbeddedResource Include="Resources\html\*.css" />
// <EmbeddedResource Include="Resources\html\*.js" />
// </ItemGroup>
// REf. https://stackoverflow.com/questions/38762368/embedded-resource-in-net-core-libraries
//-------------------------------------------------------------------
public static String GetTextResource(TextResource textResource)
{
String partialPath = "";
String resourceFilename = "";
switch (textResource)
{
case TextResource.SaBaseCss:
//return Properties.Resources.sa_base_css;
resourceFilename = "sa-base.css";
break;
case TextResource.SaBaseJs:
//return Properties.Resources.sa_base_js;
resourceFilename = "sa-base.js";
break;
case TextResource.JQueryJs:
//return Properties.Resources.jquery_1_12_1_min_js;
resourceFilename = "jquery-1.12.1.min.js";
break;
case TextResource.JQueryUiCss:
//return Properties.Resources.jquery_ui_1_12_1_min_css;
resourceFilename = "jquery-ui-1.12.1.min.css";
break;
case TextResource.JQueryUiJs:
//return Properties.Resources.jquery_ui_1_12_1_min_js;
resourceFilename = "jquery-ui-1.12.1.min.js";
break;
}
if (!StringUtil.IsEmpty(resourceFilename))
{
var assembly = typeof(SacsResourceHelper).GetTypeInfo().Assembly;
String resourceText = GetManifestResourceAsText(assembly, partialPath, resourceFilename);
if (!StringUtil.IsEmpty(resourceText))
return resourceText;
}
return "";
}
//-------------------------------------------------------------------
public static byte[] GetImageResource(ImageResource imageResource)
{
String partialPath = "";
String resourceFilename = "";
switch (imageResource)
{
//-----------------------------------------------------------
// Burgers.
case ImageResource.Icon_Burger_Black_48_png:
resourceFilename = "burger_black_48.png";
break;
case ImageResource.Icon_Burger_Black_64_png:
resourceFilename = "burger_black_64.png";
break;
//-----------------------------------------------------------
// Arrows.
case ImageResource.Arrow_Left_Black_16_png:
resourceFilename = "arrow_left_black_16.png";
break;
case ImageResource.Arrow_Left_Double_Black_16_png:
resourceFilename = "arrow_left_double_black_16.png";
break;
case ImageResource.Arrow_Right_Black_16_png:
resourceFilename = "arrow_right_black_16.png";
break;
case ImageResource.Arrow_Right_Double_Black_16_png:
resourceFilename = "arrow_right_double_black_16.png";
break;
case ImageResource.Arrow_Left_Black_24_png:
resourceFilename = "arrow_left_black_24.png";
break;
case ImageResource.Arrow_Left_Double_Black_24_png:
resourceFilename = "arrow_left_double_black_24.png";
break;
case ImageResource.Arrow_Right_Black_24_png:
resourceFilename = "arrow_right_black_24.png";
break;
case ImageResource.Arrow_Right_Double_Black_24_png:
resourceFilename = "arrow_right_double_black_24.png";
break;
//-----------------------------------------------------------
// IconShock.
case ImageResource.IconShock_Arrow_Down_Purple_72_png:
partialPath = "IconShock";
resourceFilename = "arrow_down_purple_72.png";
break;
case ImageResource.IconShock_Arrow_Right_Purple_72_png:
partialPath = "IconShock";
resourceFilename = "arrow_right_purple_72.png";
break;
case ImageResource.IconShock_Add_Green_72_png:
partialPath = "IconShock";
resourceFilename = "add_green_72.png";
break;
case ImageResource.IconShock_Pencil_Orange_72_png:
partialPath = "IconShock";
resourceFilename = "pencil_orange_72.png";
break;
case ImageResource.IconShock_Close_Red_72_png:
partialPath = "IconShock";
resourceFilename = "close_red_72.png";
break;
case ImageResource.IconShock_TrashCan_Grey_72_png:
partialPath = "IconShock";
resourceFilename = "trashcan_grey_72.png";
break;
//-----------------------------------------------------------
}
if (!StringUtil.IsEmpty(resourceFilename))
{
var assembly = typeof(SacsResourceHelper).GetTypeInfo().Assembly;
byte[] resourceData = GetManifestResourceAsBinary(assembly, partialPath, resourceFilename);
if (resourceData != null)
return resourceData;
}
return new byte[0];
}
//-------------------------------------------------------------------
/// <summary>Retrieve resource as String based on assembly and partial resource name.</summary>
public static String GetManifestResourceAsText(Assembly assembly, String partialPath, String resourceNameEndsWith)
{
String fn = typeof(SacsResourceHelper).Name + ".GetManifestResourceAsText";
if (StringUtil.IsEmpty(resourceNameEndsWith)) return "";
using (Stream resourceStream = GetManifestResourceStream(assembly, partialPath, resourceNameEndsWith))
{
if (resourceStream != null)
{
using (StreamReader resourceReader = new StreamReader(resourceStream, Encoding.UTF8))
{
return resourceReader.ReadToEnd();
}
}
}
return "";
}
//-------------------------------------------------------------------
/// <summary>Retrieve resource as byte array based on assembly and partial resource name.</summary>
public static byte[] GetManifestResourceAsBinary(Assembly assembly, String partialPath, String resourceNameEndsWith)
{
String fn = typeof(SacsResourceHelper).Name + ".GetManifestResourceAsBinary";
if (
StringUtil.IsEmpty(resourceNameEndsWith)) return null;
using (Stream resourceStream = GetManifestResourceStream(assembly, partialPath, resourceNameEndsWith))
{
if (resourceStream != null)
{
using (BinaryReader resourceReader = new BinaryReader(resourceStream, Encoding.UTF8))
{
return resourceReader.ReadBytes((int)resourceStream.Length);
}
}
}
SaLogger.Warn(fn + " Failed to locate text resource: " + resourceNameEndsWith);
return null;
}
//-------------------------------------------------------------------
/// <summary>Retrieve resource as stream based on assembly and partial resource name.</summary>
public static Stream GetManifestResourceStream(Assembly assembly, String partialPath, String resourceNameEndsWith)
{
String fn = typeof(SacsResourceHelper).Name + ".GetManifestResourceStream";
//Logger.Debug(fn + " Manifest resource names: " + new List<String>(assembly.GetManifestResourceNames()).Concat("","\n\t"));
foreach (String resourceName in assembly.GetManifestResourceNames())
{
//SaLogger.Debug(fn + " Resource: " + resourceName);
// Match the partial path.
if (!StringUtil.IsEmpty(partialPath) && !resourceName.ContainsCI(partialPath)) continue;
// Match the resource filename to the end of the resource name - resource names start with default namespace (eg. 'Sarand').
if (!resourceName.EndsWithCI(resourceNameEndsWith)) continue;
//SaLogger.Debug(fn + " Resource filename: " + resourceNameEndsWith + ". Matched to resource: " + resourceName);
return assembly.GetManifestResourceStream(resourceName);
}
SaLogger.Warn(fn + " Resource filename not found: " + resourceNameEndsWith);
return null;
}
//-------------------------------------------------------------------
}
//=======================================================================
}