Saturday, September 19, 2020

What is current version of Microsoft Edge - live-ish

 

Pulled from wikipedia at

 

 

for mobile switch to desktop view

Friday, September 18, 2020

C# .NET How to get image dimensions from header of webP for all formats; lossy, lossless, extended - partially load image

Get image dimensions from header of WebP  for all formats; lossy, lossless and extended and is fast. 

Code for reading the header of WebP formats is not commonly available in C# .NET, so I had to go to the WebP Container Specification to build out the code. The code reads the 1st 30 bytes of a webp file only. This is fast, but could be faster, stay tuned.


Geneva Drive
Geneva Drive.webp


Handles animated webp formats as specified by "VP8X" type.

Source Code

using System;
using System.Net; 
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using System.Linq;
using System.Diagnostics; 

public class Program
{
	//Org 	https://www.codeproject.com/Articles/35978/Reading-Image-Headers-to-Get-Width-and-Height
	//Mod 	https://stackoverflow.com/questions/111345/getting-image-dimensions-without-reading-the-entire-file/60667939#60667939
    //		DecodeWebP reads only lossless :( 
	
	//My version improved DecodeWebP method to read all webp formats; lossy, lossless and extended. 
                
	internal static class ImageHelper
    {
        const string errorMessage = "Could not recognise image format.";

        private static Dictionary<byte[], Func<BinaryReader, Size>> imageFormatDecoders = new Dictionary<byte[], Func<BinaryReader, Size>>()
        {
            { new byte[] { 0x42, 0x4D }, DecodeBitmap },
            { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
            { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
            { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
            { new byte[] { 0xff, 0xd8 }, DecodeJfif },
            { new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
        };

        /// <summary>        
        /// Gets the dimensions of an image.        
        /// </summary>        
        /// <param name="path">The path of the image to get the dimensions of.</param>        
        /// <returns>The dimensions of the specified image.</returns>        
        /// <exception cref="ArgumentException">The image was of an unrecognised format.</exception>            
        public static Size GetDimensions(BinaryReader binaryReader)
        {
            int maxMagicBytesLength = imageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;
            byte[] magicBytes = new byte[maxMagicBytesLength];
            for (int i = 0; i < maxMagicBytesLength; i += 1)
            {
                magicBytes[i] = binaryReader.ReadByte();
                foreach (var kvPair in imageFormatDecoders)
                {
                    if (StartsWith(magicBytes, kvPair.Key))
                    {
                        return kvPair.Value(binaryReader);
                    }
                }
            }

            throw new ArgumentException(errorMessage, "binaryReader");
        }
        
        /// <summary>
        /// Gets the dimensions of an image.
        /// </summary>
        /// <param name="path">The path of the image to get the dimensions of.</param>
        /// <returns>The dimensions of the specified image.</returns>
        /// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
        public static Size GetDimensions(string path)
        {
            using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(path)))
            {
                try
                {
                    return GetDimensions(binaryReader);
                }
                catch (ArgumentException e)
                {
                    if (e.Message.StartsWith(errorMessage))
                    {
                        throw new ArgumentException(errorMessage, "path", e);
                    }
                    else
                    {
                        throw e;
                    }
                }
            }
        }
		
		 /// <summary>
        /// Gets the dimensions of an image.
        /// </summary>
        /// <param name="path">The path of the image to get the dimensions of.</param>
        /// <returns>The dimensions of the specified image.</returns>
        /// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
        public static Size GetDimensions(MemoryStream ms)
        {
            using (BinaryReader binaryReader = new BinaryReader(ms))
            {
                try
                {
                    return GetDimensions(binaryReader);
                }
                catch (ArgumentException e)
                {
                    if (e.Message.StartsWith(errorMessage))
                    {
                        throw new ArgumentException(errorMessage, "path", e);
                    }
                    else
                    {
                        throw e;
                    }
                }
            }
        }


        private static bool StartsWith(byte[] thisBytes, byte[] thatBytes)
        {
            for (int i = 0; i < thatBytes.Length; i += 1)
            {
                if (thisBytes[i] != thatBytes[i])
                {
                    return false;
                }
            }

            return true;
        }

        private static short ReadLittleEndianInt16(BinaryReader binaryReader)
        {
            byte[] bytes = new byte[sizeof(short)];

            for (int i = 0; i < sizeof(short); i += 1)
            {
                bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
            }
            return BitConverter.ToInt16(bytes, 0);
        }

        private static int ReadLittleEndianInt32(BinaryReader binaryReader)
        {
            byte[] bytes = new byte[sizeof(int)];
            for (int i = 0; i < sizeof(int); i += 1)
            {
                bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
            }
            return BitConverter.ToInt32(bytes, 0);
        }

        private static Size DecodeBitmap(BinaryReader binaryReader)
        {
            binaryReader.ReadBytes(16);
            int width = binaryReader.ReadInt32();
            int height = binaryReader.ReadInt32();
            return new Size(width, height);
        }

        private static Size DecodeGif(BinaryReader binaryReader)
        {
            int width = binaryReader.ReadInt16();
            int height = binaryReader.ReadInt16();
            return new Size(width, height);
        }

        private static Size DecodePng(BinaryReader binaryReader)
        {
            binaryReader.ReadBytes(8);
            int width = ReadLittleEndianInt32(binaryReader);
            int height = ReadLittleEndianInt32(binaryReader);
            return new Size(width, height);
        }

        private static Size DecodeJfif(BinaryReader binaryReader)
        {
            while (binaryReader.ReadByte() == 0xff)
            {
                byte marker = binaryReader.ReadByte();
                short chunkLength = ReadLittleEndianInt16(binaryReader);
                if (marker == 0xc0 || marker == 0xc2) // c2: progressive
                {
                    binaryReader.ReadByte();
                    int height = ReadLittleEndianInt16(binaryReader);
                    int width = ReadLittleEndianInt16(binaryReader);
                    return new Size(width, height);
                }

                if (chunkLength < 0)
                {
                    ushort uchunkLength = (ushort)chunkLength;
                    binaryReader.ReadBytes(uchunkLength - 2);
                }
                else
                {
                    binaryReader.ReadBytes(chunkLength - 2);
                }
            }

            throw new ArgumentException(errorMessage);
        }
        
        //Other libs did not do it 
        //https://github.com/JosePineiro/WebP-wrapper/blob/master/WebPTest/WebPWrapper.cs
        //https://github.com/JimBobSquarePants/ImageProcessor/blob/6092da59e9aa4975e564002ef3c782a8f6bf3384/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/WebPFormat.cs
      
		//fast
        private static Size DecodeWebP(BinaryReader binaryReader)
        {
            //https://developers.google.com/speed/webp/docs/riff_container
			//var riff = binaryReader.ReadBytes(4); //already offset 4 bytes to read R I F F 
            
			uint size = binaryReader.ReadUInt32() + 8; // Size - start at offset 4,  length+8! https://en.wikipedia.org/wiki/WebP - actual not on disk size
			
            var webp = binaryReader.ReadBytes(4); // start 8 offset - https://en.wikipedia.org/wiki/WebP
            if (webp[0] != 87 && webp[1] != 69 && webp[2] != 66 && webp[3] != 80) //must match W E B P
                return new Size(0, 0);

			//or use binaryReader.ReadBytes(8); to avoid skip above
			
            var type = binaryReader.ReadBytes(4); // start 12 offset - VP8[ ] determination

            string VP8Type = System.Text.Encoding.UTF8.GetString(type);
			
			Console.WriteLine("VP8Type=\""+VP8Type+"\" of size "+ size.ToString("#,##0")+" bytes."); 

            int x = 0; 
            int y = 0;

            if (VP8Type == "VP8X") //Extra format - https://developers.google.com/speed/webp/docs/riff_container#extended_file_format
            { 
                //skip 32 bits or 8 bytes for Alpha, Exif, XMP flags... in VP8X header
                binaryReader.ReadBytes(8);

                byte[] w = binaryReader.ReadBytes(3); //24bits for width

                x = 1 + (w[2] << 16 | w[1] << 8 | w[0]); //little endian

                byte[] h = binaryReader.ReadBytes(3); //24bits for height

                y = 1 + (h[2] << 16 | h[1] << 8 | h[0]); 

				return new Size(x, y);

            }
            else if (VP8Type == "VP8L") //Lossless - https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#2_riff_header 
            {
                
                binaryReader.ReadBytes(4); //size
                byte[] sig = binaryReader.ReadBytes(1); //0x2f->47 1 byte signature
                if (sig[0] != 47) return new Size(0, 0); 

                byte[] wh = binaryReader.ReadBytes(4); //width and height in 1 read
                x = 1 + (((wh[1] & 0x3F) << 8) | wh[0]); //{1 + ((($b1 & 0x3F) << 8) | $b0)} - https://blog.tcl.tk/38137  
                y = 1 + (((wh[3] & 0xF) << 10) | (wh[2] << 2) | ((wh[1] & 0xC0) >> 6)); //{1 + ((($b3 & 0xF) << 10) | ($b2 << 2) | (($b1 & 0xC0) >> 6))}]

				return new Size(x, y);

            }
            else if (VP8Type == "VP8 ") //Lossy - https://tools.ietf.org/html/rfc6386#section-9.1
            {

                //Lossy - https://tools.ietf.org/html/rfc6386#section-9.1  - hard to decipher this 
                //pc->Width      = swap2(*(unsigned short*)(c+3))&0x3fff;  0x3fff -> 16383 decimal  swap2 - big or little indian depending on machine 
                //pc->Height     = swap2(*(unsigned short*)(c+5))&0x3fff;
              
				//https://blog.tcl.tk/38137 - much better
                  
                binaryReader.ReadBytes(7); //move to offset 23 or 0x17, 23-12+4=7 - open webp lossy file https://developers.google.com/speed/webp/gallery1

                byte[] frameTag = binaryReader.ReadBytes(3); 
				
				//    $b0 != 0x9d->157  || $b1 != 0x01>1 || $b2 != 0x2a->	42 
                if (frameTag[0] != 157 || frameTag[1] != 1 || frameTag[2] != 42) 
					return new Size(0, 0); //invalid webp file

				//reads 2 bytes which is 16-bits, but we want only 14 bits, shrink
                x = binaryReader.ReadUInt16() & 0x3fff;    //$width & 0x3fff -> & 0b00_11111111111111 c#7.0 above only
                y = binaryReader.ReadUInt16() & 0x3fff;    //$height & 0x3fff
            
				return new Size(x, y);
            }
            
            return new Size(0, 0);
            			
        }

    }
	
	public static string GetFileNameFromURL(string hrefLink) //hack
	{
		string[] parts = hrefLink.Split('/');
		string fileName = string.Empty;

		if (parts.Length > 0)
			fileName = parts[parts.Length - 1];
		else
			fileName = hrefLink;

		return fileName;
	}

	public static void Main()
	{
	    Stopwatch sw = new Stopwatch(); 
		//string webpURL = "https://www.gstatic.com/webp/gallery/1.sm.webp";//Lossy
		//string webpURL = "https://www.gstatic.com/webp/gallery3/2_webp_ll.webp";//Lossless
		//string webpURL = "https://www.gstatic.com/webp/gallery3/1_webp_a.webp";//Extended with alpha channel
		//string webpURL = "https://mathiasbynens.be/demo/animated-webp-supported.webp"; //animated
		//string webpURL = "http://blog.mindworkshop.com/image/webp003.webp"; //animal
		string webpURL = "https://file-examples-com.github.io/uploads/2020/03/file_example_WEBP_1500kB.webp"; //1.5 Mb
		
	    string webpfile = GetFileNameFromURL(webpURL); 
		
		Size webpSize = new Size(); 
		
	    WebClient wc = new WebClient();
		using (MemoryStream stream = new MemoryStream(wc.DownloadData(webpURL))) //this would normally be a path, but can't do that here
		{
         sw.Start(); 
		 webpSize = ImageHelper.GetDimensions(stream); 
	     sw.Stop(); 
			
		}
		Console.WriteLine("WebP file \"{0}\" has dimensions [{1}w X {2}h] in {3}ms.", webpfile, webpSize.Width, webpSize.Height, sw.ElapsedMilliseconds);
	}
}




Blade Runner.webp

Wednesday, September 9, 2020

C# .NET - How to get a string between two strings, minimal spanning, fast

Here's an implementation to get a string between two strings fast, which meets most  expectations what this function should return. It finds the sub-string found "after" the 1st string "before" the next 2nd string. The sticky question is where does before 2nd string exactly start?

Technically, this minimal spanning meaning the string returned is the minimal length found string between the 1st string end and the beginning of the 2nd string. 

Below we compare the 2nd string starting immediately after leaving no space after 1st, versus, 2nd string starting immediately after 1st but starting +1 character or next character after. We want at least one character to return, not empty string. Right.

Immediate after is how most examples are commonly implemented, but it may not be what you want, see comparison image below. Quick note, r stands for rule, see code.








With index immediately after "Exact in charts", getting string between strings "a" to "a" for input "aaaa" is empty! Technically correct. 

With index immediately after "+1 in charts", getting string between strings "a" to "a" for input "aaaa" is "a". Intuitively you would want this. 

Whilst the "+1" seems good, there are repercussions, in some cases might not be want you expect. Best to see it for you own eyes, in 
comparison chart image below.





















To see full effects, run code below for "Exact" or Edit in .NET Fiddle
to try "+1" version. 



using System;using System.Diagnostics; 

public static class Extensions 
{
	/// <summary>
	/// Get a substring between two anchor strings, minimal span
	/// </summary>
	/// <param name="s">source string</param>
	/// <param name="from">search from end of this string</param>
	/// <param name="to">to beginning of this string, searching backwards, from end to start of s</param>
	/// <returns>a substring between from and to, maximal span</returns>
	public static string GetFirstStringBetweenStringsMinSpanCleanup(this string s, string from, string to)
	{
		if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to)) return string.Empty;

		int idxFrom = s.IndexOf(from);
		int idxStart = idxFrom + from.Length; //we filter "not found" -1, never race condtn

		if (idxFrom == -1 || idxStart >= s.Length - 1)
			return string.Empty;

		int idxEnd = s.IndexOf(to, idxStart); //Exact definition, but intuitively next line meets likely expectations -> YOU CHOOSE
        //int idxEnd = s.IndexOf(to, idxStart + 1); //Start next position after, leaving a space for 1 character to be returned

           
		if (idxEnd == -1 || idxEnd <= idxStart)
			return string.Empty;

		return s.Substring(idxStart, idxEnd - idxStart);

	}
	/// <summary>
	/// Get a substring between two anchor strings, MINIMAL SPAN
	/// </summary>
	/// <param name="s">source string</param>
	/// <param name="from">search from end of this string</param>
	/// <param name="to">to beginning of this string, searching backwards, from end to start of s</param>
	/// <returns>a substring between from and to, maximal span</returns>
	public static string GetFirstStringBetweenStringsMinSpan(this string s, string from, string to)
	{
		Console.Write("args from {0} to {1} = ", from, to); //debug

		//edge cases
		if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to)) return string.Empty;
		//if (from.Length >= s.Length || to.Length >= s.Length) return string.Empty; //redundant, this Rule take care of below

		int idxFrom = s.IndexOf(from);
		int idxStart = idxFrom + from.Length; //we filter "not found" -1, never race condtn

		if (idxFrom == -1)       
			return string.Empty;
		else if (idxStart >= s.Length - 1) //for testing combine to 1 line, we combining a idx with a length, and w/ lengths we normally subtract 1 
		{
			Console.WriteLine("r1. idxStart={0} >= (s.Length - 1)={1}", idxStart, s.Length - 1);
			return string.Empty; 
		}

		int idxEnd = s.IndexOf(to, idxStart); //Exact definition, but intuitively next line meets likely expectations -> YOU CHOOSE
        //int idxEnd = s.IndexOf(to, idxStart + 1); //Start next position after, leaving a space for 1 character to be returned

		if (idxEnd == -1 )
			return string.Empty;
		else if (idxEnd > s.Length - 1) //Rule 2 never gets used
		{
			Console.WriteLine("r2. idxEnd={0} > (s.Length - 1)={1}", idxEnd, s.Length - 1);
			return string.Empty;
		}
		else if (idxEnd <= idxStart)
		{
			Console.WriteLine("r3. idxEnd={0} <= idxStart={1}", idxEnd, idxStart);
			return string.Empty;
		}

		return s.Substring(idxStart, idxEnd - idxStart);

	}
 }

public class Program
{
	public static void Main()
	{
		  string test = "abcd";
            Console.WriteLine(test);
            Console.WriteLine("=================");

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(null, null));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("", ""));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, test));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("", test));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test,""));
            
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "d"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "e"));
            
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("e", "e"));
            
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "d"));
            
            

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a","abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("b", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("c", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("d", "abc"));

            Console.WriteLine(); 
            test = "abcdabcd";
            Console.WriteLine(test);
            Console.WriteLine("=================");

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(null, null));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("", ""));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, test));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("", test));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, ""));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "d"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "e"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("e", "e"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("b", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("c", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("d", "abc"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "d")); //pass


            Console.WriteLine();
            test = "aaaa";
            Console.WriteLine(test);
            Console.WriteLine("=================");

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("aa", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("aaa", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("aaaa", "a"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "aa"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "aaa"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "aaaa"));

            Console.WriteLine();
            test = "aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb";
            Console.WriteLine(test);
            Console.WriteLine("=================");
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("bbbb", "aaaa"));

            string result = string.Empty; 
            Stopwatch sw = new Stopwatch();
            sw.Start();
            result = test.GetFirstStringBetweenStringsMinSpan("aaaaaaa", "bb");
            sw.Stop();
            Console.WriteLine(result);
            Console.WriteLine(" in " + sw.ElapsedTicks + " ticks."); 
	}
}

Saturday, September 5, 2020

C# .NET - How to get a string between two strings fast

Here's an indulgent look into getting a string between 2 strings. I could not find any satisfactory* solutions out there so I did my own. 

*Satisfactory because all the solution out there generally were not taking care of edge cases and did not state if there were maximal spanning (greedy in regex terms) or minimal spanning. 

So having a little extra time I decided to really look at this. I learnt that some edge cases I did not need to optimize this and make it fast, but bullet proof.

Note: This solution gets the maximal span between two strings. So 1st is search from beginning, and 2nd string is search from end.  Minimal span would be 2nd string would be search from a position after 1st. 

Code below implement a debug version of the method which shows which rules get triggered, in an extensive test cases.

  
Source Code
 
using System;using System.Diagnostics;

namespace GetBetweenStrings_Blog
{
    public static class Extensions 
    {
        /// <summary>
        /// Get a substring between two anchor strings, maximal span
        /// </summary>
        /// <param name="s">source string</param>
        /// <param name="from">search from end of this string</param>
        /// <param name="to">to beginning of this string, searching backwards, from end to start of s</param>
        /// <returns>a substring between from and to, maximal span</returns>
        public static string GetFirstStringBetweenStringsCleanup(this string s, string from, string to)
        {
            if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to)) return string.Empty;
        
            int idxFrom = s.IndexOf(from);
            int idxStart = idxFrom + from.Length; //we filter "not found" -1, never get neg number here

            if (idxFrom == -1 || idxStart >= s.Length - 1)
			    return string.Empty;
            
            int idxEnd = s.LastIndexOf(to);
            
            if (idxEnd == -1 || idxEnd <= idxStart) 
                return string.Empty;
            
            return s.Substring(idxStart, idxEnd - idxStart);

        }

		//4:00AM coding journey, testing conditions you may or may not need, buiding from scatch
        /// <summary>
        /// Get a substring between two anchor strings, maximal span
        /// </summary>
        /// <param name="s">source string</param>
        /// <param name="from">search from end of this string</param>
        /// <param name="to">to beginning of this string, searching backwards, from end to start of s</param>
        /// <returns>a substring between from and to, maximal span</returns>
        public static string GetFirstStringBetweenStrings(this string s, string from, string to)
        {
            Console.Write("args from {0} to {1} = ", from, to); //debug

            //edge case
            if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to)) return string.Empty;
            //if (from.Length >= s.Length || to.Length >= s.Length) return string.Empty; //redundant rule take care of below
            
            int idxFrom = s.IndexOf(from);
            int idxStart = idxFrom + from.Length; //we filter "not found" -1, never race condtn

            if (idxFrom == -1)       
                return string.Empty;
            else if (idxStart >= s.Length - 1) //for testing combine to 1 line, we combining a idx with a length, and w/ lengths we normally subtract 1 
            //else if (idxStart >= s.Length) //for testing combine to 1 line, we combining a idx with a length, and w/ lengths we normally subtract 1 
            {
                Console.WriteLine("r1. idxStart={0} >= (s.Length - 1)={1}", idxStart, s.Length - 1);
                //Console.WriteLine("r1. idxStart={0} >= s.Length={1}",  idxStart, s.Length);
                return string.Empty; 
            }

         

            int idxEnd = s.LastIndexOf(to); 
            //int idxEnd = s.LastIndexOf(to, idxStart); //produces unexpected results 1 when to="a" and idxStart=1 when from="a", we expect last last index of string "aaaa" which is 4-1=3

            //if (idxEnd == -1 || idxEnd > s.Length - 1 || idxStart >= idxEnd) //intially in-correction
            if (idxEnd == -1 )
                return string.Empty;
            //else if (idxEnd > s.Length - 1) //we can rule this out because if not found -1
            ////else if (idxEnd > s.Length)
            //{
            //    Console.WriteLine("r2. idxEnd={0} > (s.Length - 1)={1}", idxEnd, s.Length - 1);
            //    //Console.WriteLine("r2. idxEnd={0} > s.Length={1}", idxEnd, s.Length);
            //    return string.Empty;
            //}
            else if (idxEnd <= idxStart)
            {
                Console.WriteLine("r3. idxEnd={0} <= idxStart={1}", idxEnd, idxStart);
                return string.Empty;
            }
            
            return s.Substring(idxStart, idxEnd - idxStart);
            
        }


    }
    public class Program
    {
        public static void Main(string[] args)
        {
            string test = "abcd";
            Console.WriteLine(test);
            Console.WriteLine("=================");

            Console.WriteLine(test.GetFirstStringBetweenStrings(null, null));
            Console.WriteLine(test.GetFirstStringBetweenStrings("", ""));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test, test));
            Console.WriteLine(test.GetFirstStringBetweenStrings("", test));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test,""));
            
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "d"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "e"));
            
            Console.WriteLine(test.GetFirstStringBetweenStrings("e", "e"));
            
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("abc", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("abc", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("abc", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("abc", "d"));
            
            

            Console.WriteLine(test.GetFirstStringBetweenStrings(test, "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test, "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test, "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test, "d"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("a","abc"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("b", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("c", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("d", "abc"));

            Console.WriteLine(); 
            test = "abcdabcd";
            Console.WriteLine(test);
            Console.WriteLine("=================");

            Console.WriteLine(test.GetFirstStringBetweenStrings(null, null));
            Console.WriteLine(test.GetFirstStringBetweenStrings("", ""));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test, test));
            Console.WriteLine(test.GetFirstStringBetweenStrings("", test));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test, ""));

            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "d"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "e"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("e", "e"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("abc", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("abc", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("abc", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("abc", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStrings(test, "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test, "b"));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test, "c"));
            Console.WriteLine(test.GetFirstStringBetweenStrings(test, "d"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("b", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("c", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("d", "abc"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("abc", "d")); //pass


            Console.WriteLine();
            test = "aaaa";
            Console.WriteLine(test);
            Console.WriteLine("=================");

            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("aa", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("aaa", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("aaaa", "a"));

            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "aa"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "aaa"));
            Console.WriteLine(test.GetFirstStringBetweenStrings("a", "aaaa"));

            Console.WriteLine();
            test = "aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb";
            Console.WriteLine(test);
            Console.WriteLine("=================");
            Console.WriteLine(test.GetFirstStringBetweenStrings("bbbb", "aaaa"));
			
			string result = string.Empty; 
            Stopwatch sw = new Stopwatch();
            sw.Start();
            result = test.GetFirstStringBetweenStringsCleanup("aaaaaaa", "bb");
            sw.Stop();
            Console.WriteLine(result);
            Console.WriteLine(" in " + sw.ElapsedTicks + " ticks."); 
           
        }
    }
}

Tuesday, September 1, 2020

Phishing Email - RE: FYI Grant from Ridao Cindy cridao@mhhcc.org

For the record, this is a Ridao Cindy cridao@mhhcc.org phishing email attempt that is recently going around, with subject "RE; FYI Grant" What to do?  Report them, goto bottom of page. 

This is clever attack because the emails seems like its coming from legitimate organization.


From : Ridao, Cindy <cridao@mhhcc.org>

Subject
 : RE: FYI Grant

A humanitarian grant has been made to you, please contact for more information.






CONFIDENTIALITY NOTICE: This e-mail message, including any attachments, is for the sole use of the intended recipient(s) and may contain confidential and privileged information or otherwise protected by law. Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply e-mail and destroy all copies of the original message.


Disclaimer

The information contained in this communication from the sender is confidential. It is intended solely for use by the recipient and others authorized to receive it. If you are not the recipient, you are hereby notified that any disclosure, copying, distribution or taking action in relation of the contents of this information is strictly prohibited and may be unlawful.

This email has been scanned for viruses and malware, and may have been automatically archived by Mimecast Ltd, an innovator in Software as a Service (SaaS) for business. Providing a safer and more useful place for your human generated data. Specializing in; Security, archiving and compliance. To find out more Click Here.




PHISHING LINKs;

1.  None - When you reply - email magically changes to -> ms.lerynnewest51@gmail.com
2.  mhhcc.org belongs to Memorial Hospital and Health Care Center




How to tell this is a Phishing email ?

  1. Check email address in full, if it's not from originating company then it's phishing.
  2. Hover over all links in email, if it's not from the  company's website then forget it.
  3. The best way is to 

How to examine Email Message Source ?

Now lets look at message source
  1. Outlook.com->Actions->View Message Source. 
  2. Gmail.com->More (down arrow to top right)->Show original.
Check for suspicious links, anything that does not originate from apple.com.


Report Phishing Email (not as Spam)

  1. Outlook.com->Junk (at Top)->Phishing Scam
  2. Gmail.com->More (down-arrow to top right)->Report Phishing 

Report Phishing

If you have recievied this email take further 

  1. https://www.google.com/safebrowsing/report_phish/


Report phishing at Microsoft and government agencies

  1. http://www.microsoft.com/security/online-privacy/phishing-faq.aspx