Created
May 28, 2017 13:03
-
-
Save JPVenson/0115abee42379567f72173305b57e611 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
namespace JPB.PersonalWebpage.Helper | |
{ | |
public class Minify | |
{ | |
private static Encoding DefaultEncoding(Encoding encoding) | |
{ | |
return encoding ?? Encoding.ASCII; | |
} | |
public static Stream MinifyStream(Stream unMinifyed, Encoding encoding = null, bool keepStreamOpen = false) | |
{ | |
try | |
{ | |
var memStream = new MemoryStream(); | |
using (var reader = new BinaryReader(unMinifyed)) | |
{ | |
MinifyFromStream(memStream, reader, DefaultEncoding(encoding)); | |
} | |
return memStream; | |
} | |
finally | |
{ | |
if (!keepStreamOpen) | |
{ | |
unMinifyed.Dispose(); | |
} | |
} | |
} | |
public static Stream MinifyString(string unMinifyed, Encoding encoding = null) | |
{ | |
var memStream = new MemoryStream(); | |
encoding = DefaultEncoding(encoding); | |
using (var stReader = new MemoryStream(encoding.GetBytes(unMinifyed))) | |
{ | |
using (var reader = new BinaryReader(stReader)) | |
{ | |
MinifyFromStream(memStream, reader, DefaultEncoding(encoding)); | |
} | |
} | |
return memStream; | |
} | |
/// <summary> | |
/// Main process | |
/// </summary> | |
private static void MinifyFromStream(Stream targetStream, BinaryReader sourceReader, Encoding encoding) | |
{ | |
var lastChar = 1; // current byte read | |
var nextChar = -1; // byte read in peek() | |
var endProcess = false; // loop control | |
var ignore = false; // if false then add byte to final output | |
var inComment = false; // true when current bytes are part of a comment | |
var isDoubleSlashComment = false; // '//' comment | |
// main processing loop | |
while (!endProcess) | |
{ | |
endProcess = sourceReader.PeekChar() == -1; // check for EOF before reading | |
if (endProcess) | |
{ | |
break; | |
} | |
ignore = false; | |
int thisChar = sourceReader.ReadByte(); // previous byte read | |
if (thisChar == '\t') | |
{ | |
thisChar = ' '; | |
} | |
else if (thisChar == '\t') | |
{ | |
thisChar = '\n'; | |
} | |
else if (thisChar == '\r') | |
{ | |
thisChar = '\n'; | |
} | |
if (thisChar == '\n') | |
{ | |
ignore = true; | |
} | |
if (thisChar == ' ') | |
{ | |
if (lastChar == ' ' || IsDelimiter(lastChar) == 1) | |
{ | |
ignore = true; | |
} | |
else | |
{ | |
endProcess = sourceReader.PeekChar() == -1; // check for EOF | |
if (!endProcess) | |
{ | |
nextChar = sourceReader.PeekChar(); | |
if (IsDelimiter(nextChar) == 1) | |
{ | |
ignore = true; | |
} | |
} | |
} | |
} | |
if (thisChar == '/') | |
{ | |
nextChar = sourceReader.PeekChar(); | |
if (nextChar == '/' || nextChar == '*') | |
{ | |
ignore = true; | |
inComment = true; | |
if (nextChar == '/') | |
{ | |
isDoubleSlashComment = true; | |
} | |
else | |
{ | |
isDoubleSlashComment = false; | |
} | |
} | |
} | |
// ignore all characters till we reach end of comment | |
if (inComment) | |
{ | |
while (true) | |
{ | |
thisChar = sourceReader.ReadByte(); | |
if (thisChar == '*') | |
{ | |
nextChar = sourceReader.PeekChar(); | |
if (nextChar == '/') | |
{ | |
thisChar = sourceReader.ReadByte(); | |
inComment = false; | |
break; | |
} | |
} | |
if (isDoubleSlashComment && thisChar == '\n') | |
{ | |
inComment = false; | |
break; | |
} | |
} // while (true) | |
ignore = true; | |
} // if (inComment) | |
if (!ignore) | |
{ | |
AddToOutput(targetStream, thisChar, encoding); | |
} | |
lastChar = thisChar; | |
} // while (!endProcess) | |
} | |
/// <summary> | |
/// Add character to modified data string | |
/// </summary> | |
/// <param name="target">The stream to write to</param> | |
/// <param name="c">char to add</param> | |
private static void AddToOutput(Stream target, int c, Encoding encoding) | |
{ | |
var encoeded = encoding.GetBytes(((char) c).ToString()); | |
target.Write(encoeded, 0, encoeded.Length); | |
} | |
/// <summary> | |
/// Check if a byte is alphanumeric | |
/// </summary> | |
/// <param name="c">byte to check</param> | |
/// <returns>retval - 1 if yes. else 0</returns> | |
private static int IsAlphanumeric(int c) | |
{ | |
var retval = 0; | |
if (c >= 'a' && c <= 'z' || | |
c >= '0' && c <= '9' || | |
c >= 'A' && c <= 'Z' || | |
c == '_' || c == '$' || c == '\\' || c > 126) | |
{ | |
retval = 1; | |
} | |
return retval; | |
} | |
private static readonly char[] Delimiter = new[] | |
{ | |
'(', ',', '=', ':', | |
'[', '!', '&', '|', | |
'?', '+', '-', '~', | |
'*', '/', '{', '\n', | |
',', | |
}; | |
/// <summary> | |
/// Check if a byte is a delimiter | |
/// </summary> | |
/// <param name="c">byte to check</param> | |
/// <returns>retval - 1 if yes. else 0</returns> | |
private static int IsDelimiter(int c) | |
{ | |
var retval = 0; | |
if (Delimiter.Contains((char)c)) | |
{ | |
retval = 1; | |
} | |
return retval; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment