priprava - v2
This commit is contained in:
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace MadMilkman.Ini
|
||||
{
|
||||
internal static class IniCompressor
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
|
||||
Justification = "MemoryStream doesn't have unmanaged resources.")]
|
||||
public static string Compress(string text, Encoding encoding)
|
||||
{
|
||||
byte[] content = encoding.GetBytes(text);
|
||||
var stream = new MemoryStream();
|
||||
|
||||
using (var compressor = new GZipStream(stream, CompressionMode.Compress, true))
|
||||
compressor.Write(content, 0, content.Length);
|
||||
|
||||
byte[] compressedContent = new byte[stream.Length + 4];
|
||||
stream.Position = 0;
|
||||
stream.Read(compressedContent, 4, compressedContent.Length - 4);
|
||||
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(content.Length), 0, compressedContent, 0, 4);
|
||||
return Convert.ToBase64String(compressedContent);
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
|
||||
Justification = "MemoryStream doesn't have unmanaged resources.")]
|
||||
public static string Decompress(string text, Encoding encoding)
|
||||
{
|
||||
byte[] compressedContent = Convert.FromBase64String(text);
|
||||
var stream = new MemoryStream(compressedContent, 4, compressedContent.Length - 4);
|
||||
byte[] content = new byte[BitConverter.ToInt32(compressedContent, 0)];
|
||||
|
||||
stream.Position = 0;
|
||||
using (var decompressor = new GZipStream(stream, CompressionMode.Decompress, false))
|
||||
decompressor.Read(content, 0, content.Length);
|
||||
|
||||
return encoding.GetString(content);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace MadMilkman.Ini
|
||||
{
|
||||
internal static class IniEncryptor
|
||||
{
|
||||
/* REMARKS: RijndaelManaged
|
||||
* - KeySize - BlockSize
|
||||
* DEFAULT = 256 DEFAULT = 128
|
||||
* MIN = 128 MIN = 128
|
||||
* MAX = 256 MAX = 256
|
||||
*
|
||||
* - InitializationVector.Length
|
||||
* MUST = RijndaelManaged.BlockSize / 8
|
||||
*
|
||||
* - key.Length
|
||||
* MUST = RijndaelManaged.KeySize / 8 */
|
||||
|
||||
private static readonly byte[] InitializationVector = { 77, 52, 225, 184, 143, 77, 49, 225, 184, 187, 107, 77, 52, 225, 185, 137 };
|
||||
private static readonly byte[] Salt = { 49, 110, 49, 102, 49, 108, 51, 39, 53, 95, 53, 52, 108, 55, 95, 118, 52, 108, 117, 51 };
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
|
||||
Justification = "MemoryStream doesn't have unmanaged resources.")]
|
||||
public static string Encrypt(string text, string passwordPhrase, Encoding encoding)
|
||||
{
|
||||
byte[] content = encoding.GetBytes(text);
|
||||
byte[] key = new Rfc2898DeriveBytes(passwordPhrase, IniEncryptor.Salt, 1000).GetBytes(32);
|
||||
var stream = new MemoryStream();
|
||||
|
||||
using (var rijndaelAlgorithm = new RijndaelManaged())
|
||||
using (var encryptor = rijndaelAlgorithm.CreateEncryptor(key, IniEncryptor.InitializationVector))
|
||||
using (var cryptoStream = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
|
||||
cryptoStream.Write(content, 0, content.Length);
|
||||
|
||||
return Convert.ToBase64String(stream.ToArray());
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
|
||||
Justification = "MemoryStream doesn't have unmanaged resources.")]
|
||||
public static string Decrypt(string text, string passwordPhrase, Encoding encoding)
|
||||
{
|
||||
byte[] encryptedContent = Convert.FromBase64String(text);
|
||||
byte[] key = new Rfc2898DeriveBytes(passwordPhrase, IniEncryptor.Salt, 1000).GetBytes(32);
|
||||
byte[] content = new byte[encryptedContent.Length];
|
||||
int contentCount;
|
||||
|
||||
using (var rijndaelAlgorithm = new RijndaelManaged())
|
||||
using (var decryptor = rijndaelAlgorithm.CreateDecryptor(key, IniEncryptor.InitializationVector))
|
||||
using (var cryptoStream = new CryptoStream(new MemoryStream(encryptedContent), decryptor, CryptoStreamMode.Read))
|
||||
contentCount = cryptoStream.Read(content, 0, content.Length);
|
||||
|
||||
return encoding.GetString(content, 0, contentCount);
|
||||
}
|
||||
}
|
||||
}
|
197
MadMilkman.Ini-1.0.6/MadMilkman.Ini/IniReaderWriter/IniReader.cs
Normal file
197
MadMilkman.Ini-1.0.6/MadMilkman.Ini/IniReaderWriter/IniReader.cs
Normal file
@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MadMilkman.Ini
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
|
||||
Justification = "StringReader doesn't have unmanaged resources.")]
|
||||
internal sealed class IniReader
|
||||
{
|
||||
private readonly IniOptions options;
|
||||
private TextReader reader;
|
||||
|
||||
private int currentEmptyLinesBefore;
|
||||
private IniComment currentTrailingComment;
|
||||
private IniSection currentSection;
|
||||
|
||||
public IniReader(IniOptions options)
|
||||
{
|
||||
this.options = options;
|
||||
this.currentEmptyLinesBefore = 0;
|
||||
this.currentTrailingComment = null;
|
||||
this.currentSection = null;
|
||||
}
|
||||
|
||||
public void Read(IniFile iniFile, TextReader textReader)
|
||||
{
|
||||
this.reader = new StringReader(this.DecompressAndDecryptText(textReader.ReadToEnd()));
|
||||
|
||||
string line;
|
||||
while ((line = this.reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.Trim().Length == 0)
|
||||
this.currentEmptyLinesBefore++;
|
||||
else
|
||||
this.ReadLine(line, iniFile);
|
||||
}
|
||||
}
|
||||
|
||||
private string DecompressAndDecryptText(string fileContent)
|
||||
{
|
||||
if (this.options.Compression)
|
||||
fileContent = IniCompressor.Decompress(fileContent, this.options.Encoding);
|
||||
|
||||
if (!string.IsNullOrEmpty(this.options.EncryptionPassword))
|
||||
fileContent = IniEncryptor.Decrypt(fileContent, this.options.EncryptionPassword, this.options.Encoding);
|
||||
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
private void ReadLine(string line, IniFile file)
|
||||
{
|
||||
/* REMARKS: All 'whitespace' and 'tab' characters increase the LeftIndention by 1.
|
||||
*
|
||||
* CONSIDER: Implement different processing of 'tab' characters. They are often represented as 4 spaces,
|
||||
* or they can stretch to a next 'tab stop' position which occurs each 8 characters:
|
||||
* 0 8 16
|
||||
* |.......|.......|... */
|
||||
|
||||
// Index of first non 'whitespace' character.
|
||||
int startIndex = Array.FindIndex(line.ToCharArray(), c => !(char.IsWhiteSpace(c) || c == '\t'));
|
||||
char startCharacter = line[startIndex];
|
||||
|
||||
if (startCharacter == (char)this.options.CommentStarter)
|
||||
this.ReadTrailingComment(startIndex, line.Substring(++startIndex));
|
||||
|
||||
else if (startCharacter == this.options.sectionWrapperStart)
|
||||
this.ReadSection(startIndex, line, file);
|
||||
|
||||
else
|
||||
this.ReadKey(startIndex, line, file);
|
||||
|
||||
this.currentEmptyLinesBefore = 0;
|
||||
}
|
||||
|
||||
private void ReadTrailingComment(int leftIndention, string text)
|
||||
{
|
||||
if (this.currentTrailingComment == null)
|
||||
this.currentTrailingComment = new IniComment(IniCommentType.Trailing)
|
||||
{
|
||||
EmptyLinesBefore = this.currentEmptyLinesBefore,
|
||||
LeftIndentation = leftIndention,
|
||||
Text = text
|
||||
};
|
||||
else
|
||||
this.currentTrailingComment.Text += Environment.NewLine + text;
|
||||
}
|
||||
|
||||
/* MZ(2015-08-29): Added support for section names that may contain end wrapper or comment starter characters. */
|
||||
private void ReadSection(int leftIndention, string line, IniFile file)
|
||||
{
|
||||
int sectionEndIndex = -1, potentialCommentIndex, tempIndex = leftIndention;
|
||||
while (tempIndex != -1 && ++tempIndex <= line.Length)
|
||||
{
|
||||
potentialCommentIndex = line.IndexOf((char)this.options.CommentStarter, tempIndex);
|
||||
|
||||
if (potentialCommentIndex != -1)
|
||||
sectionEndIndex = line.LastIndexOf(this.options.sectionWrapperEnd, potentialCommentIndex - 1, potentialCommentIndex - tempIndex);
|
||||
else
|
||||
sectionEndIndex = line.LastIndexOf(this.options.sectionWrapperEnd, line.Length - 1, line.Length - tempIndex);
|
||||
|
||||
if (sectionEndIndex != -1)
|
||||
break;
|
||||
else
|
||||
tempIndex = potentialCommentIndex;
|
||||
}
|
||||
|
||||
if (sectionEndIndex != -1)
|
||||
{
|
||||
this.currentSection = new IniSection(file,
|
||||
line.Substring(leftIndention + 1, sectionEndIndex - leftIndention - 1),
|
||||
this.currentTrailingComment)
|
||||
{
|
||||
LeftIndentation = leftIndention,
|
||||
LeadingComment = { EmptyLinesBefore = this.currentEmptyLinesBefore }
|
||||
};
|
||||
file.Sections.Add(this.currentSection);
|
||||
|
||||
if (++sectionEndIndex < line.Length)
|
||||
this.ReadSectionLeadingComment(line.Substring(sectionEndIndex));
|
||||
}
|
||||
|
||||
this.currentTrailingComment = null;
|
||||
}
|
||||
|
||||
private void ReadSectionLeadingComment(string lineLeftover)
|
||||
{
|
||||
// Index of first non 'whitespace' character.
|
||||
int leftIndention = Array.FindIndex(lineLeftover.ToCharArray(), c => !(char.IsWhiteSpace(c) || c == '\t'));
|
||||
if (leftIndention != -1 && lineLeftover[leftIndention] == (char)this.options.CommentStarter)
|
||||
{
|
||||
var leadingComment = this.currentSection.LeadingComment;
|
||||
leadingComment.Text = lineLeftover.Substring(leftIndention + 1);
|
||||
leadingComment.LeftIndentation = leftIndention;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadKey(int leftIndention, string line, IniFile file)
|
||||
{
|
||||
int keyDelimiterIndex = line.IndexOf((char)this.options.KeyDelimiter, leftIndention);
|
||||
if (keyDelimiterIndex != -1)
|
||||
{
|
||||
if (this.currentSection == null)
|
||||
this.currentSection = file.Sections.Add(IniSection.GlobalSectionName);
|
||||
|
||||
var currentKey = new IniKey(file,
|
||||
line.Substring(leftIndention, keyDelimiterIndex - leftIndention).TrimEnd(),
|
||||
this.currentTrailingComment)
|
||||
{
|
||||
LeftIndentation = leftIndention,
|
||||
LeadingComment = { EmptyLinesBefore = this.currentEmptyLinesBefore }
|
||||
};
|
||||
|
||||
this.currentSection.Keys.Add(currentKey);
|
||||
|
||||
this.ReadValue(line.Substring(++keyDelimiterIndex).TrimStart(), currentKey);
|
||||
}
|
||||
|
||||
this.currentTrailingComment = null;
|
||||
}
|
||||
|
||||
private void ReadValue(string lineLeftover, IniKey key)
|
||||
{
|
||||
int valueEndIndex = lineLeftover.IndexOf((char)this.options.CommentStarter);
|
||||
|
||||
if (valueEndIndex == -1)
|
||||
key.Value = lineLeftover.TrimEnd();
|
||||
else if (valueEndIndex == 0)
|
||||
key.Value = key.LeadingComment.Text = string.Empty;
|
||||
else
|
||||
this.ReadValueLeadingComment(lineLeftover, valueEndIndex, key);
|
||||
}
|
||||
|
||||
/* MZ(2016-02-23): Added support for quoted values which can contain comment's starting characters. */
|
||||
private void ReadValueLeadingComment(string lineLeftover, int potentialCommentIndex, IniKey key)
|
||||
{
|
||||
int quoteEndIndex = lineLeftover.IndexOf('"', 1);
|
||||
if (lineLeftover[0] == '"' && quoteEndIndex != -1)
|
||||
while (quoteEndIndex > potentialCommentIndex && potentialCommentIndex != -1)
|
||||
potentialCommentIndex = lineLeftover.IndexOf((char)this.options.CommentStarter, ++potentialCommentIndex);
|
||||
|
||||
if (potentialCommentIndex == -1)
|
||||
key.Value = lineLeftover.TrimEnd();
|
||||
else
|
||||
{
|
||||
key.LeadingComment.Text = lineLeftover.Substring(potentialCommentIndex + 1);
|
||||
|
||||
// The amount of 'whitespace' characters between key's value and comment's starting character.
|
||||
int leftIndention = 0;
|
||||
while (lineLeftover[--potentialCommentIndex] == ' ' || lineLeftover[potentialCommentIndex] == '\t')
|
||||
leftIndention++;
|
||||
|
||||
key.LeadingComment.LeftIndentation = leftIndention;
|
||||
key.Value = lineLeftover.Substring(0, ++potentialCommentIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
128
MadMilkman.Ini-1.0.6/MadMilkman.Ini/IniReaderWriter/IniWriter.cs
Normal file
128
MadMilkman.Ini-1.0.6/MadMilkman.Ini/IniReaderWriter/IniWriter.cs
Normal file
@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MadMilkman.Ini
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
|
||||
Justification = "StringWriter doesn't have unmanaged resources.")]
|
||||
internal sealed class IniWriter
|
||||
{
|
||||
private static readonly string[] NewLines = { "\r\n", "\n", "\r" };
|
||||
private readonly IniOptions options;
|
||||
private TextWriter writer;
|
||||
|
||||
public IniWriter(IniOptions options) { this.options = options; }
|
||||
|
||||
public void Write(IniFile iniFile, TextWriter textWriter)
|
||||
{
|
||||
this.writer = new StringWriter(System.Globalization.CultureInfo.InvariantCulture);
|
||||
this.WriteSections(iniFile.Sections);
|
||||
|
||||
textWriter.Write(this.EncryptAndCompressText(this.writer.ToString()));
|
||||
textWriter.Flush();
|
||||
}
|
||||
|
||||
private string EncryptAndCompressText(string fileContent)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this.options.EncryptionPassword))
|
||||
fileContent = IniEncryptor.Encrypt(fileContent, this.options.EncryptionPassword, this.options.Encoding);
|
||||
|
||||
if (this.options.Compression)
|
||||
fileContent = IniCompressor.Compress(fileContent, this.options.Encoding);
|
||||
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
private void WriteSections(IniSectionCollection sections)
|
||||
{
|
||||
if (sections.Count == 0)
|
||||
return;
|
||||
|
||||
this.WriteFirstSection(sections[0]);
|
||||
|
||||
for (int i = 1; i < sections.Count; i++)
|
||||
this.WriteSection(sections[i]);
|
||||
}
|
||||
|
||||
private void WriteFirstSection(IniSection section)
|
||||
{
|
||||
if (section.Name.Equals(IniSection.GlobalSectionName))
|
||||
this.WriteKeys(section.Keys);
|
||||
else
|
||||
this.WriteSection(section);
|
||||
}
|
||||
|
||||
private void WriteSection(IniSection section)
|
||||
{
|
||||
this.WriteItem(section,
|
||||
// E.g. " [SectionName]"
|
||||
new String(' ', section.LeftIndentation) +
|
||||
this.options.sectionWrapperStart +
|
||||
section.Name +
|
||||
this.options.sectionWrapperEnd);
|
||||
|
||||
this.WriteKeys(section.Keys);
|
||||
}
|
||||
|
||||
private void WriteKeys(IniKeyCollection keys)
|
||||
{
|
||||
foreach (IniKey key in keys)
|
||||
this.WriteItem(key,
|
||||
// E.g. " KeyName = KeyValue"
|
||||
new String(' ', key.LeftIndentation) +
|
||||
key.Name +
|
||||
((this.options.KeySpaceAroundDelimiter) ? " " : string.Empty) +
|
||||
(char)this.options.KeyDelimiter +
|
||||
((this.options.KeySpaceAroundDelimiter) ? " " : string.Empty) +
|
||||
key.Value);
|
||||
}
|
||||
|
||||
private void WriteItem(IniItem item, string itemContent)
|
||||
{
|
||||
if (item.HasTrailingComment)
|
||||
this.WriteTrailingComment(item.TrailingComment);
|
||||
|
||||
if (item.HasLeadingComment)
|
||||
this.WriteEmptyLines(item.LeadingComment.EmptyLinesBefore);
|
||||
|
||||
this.writer.Write(itemContent);
|
||||
|
||||
if (item.HasLeadingComment)
|
||||
this.WriteLeadingComment(item.LeadingComment);
|
||||
else
|
||||
this.writer.WriteLine();
|
||||
}
|
||||
|
||||
private void WriteTrailingComment(IniComment trailingComment)
|
||||
{
|
||||
this.WriteEmptyLines(trailingComment.EmptyLinesBefore);
|
||||
|
||||
// E.g. " ;CommentText
|
||||
// ;CommentText"
|
||||
if (trailingComment.Text != null)
|
||||
foreach (string commentLine in trailingComment.Text.Split(IniWriter.NewLines, StringSplitOptions.None))
|
||||
this.writer.WriteLine(
|
||||
new String(' ', trailingComment.LeftIndentation) +
|
||||
(char)this.options.CommentStarter +
|
||||
commentLine);
|
||||
}
|
||||
|
||||
private void WriteLeadingComment(IniComment leadingComment)
|
||||
{
|
||||
// E.g. " ;CommentText"
|
||||
if (leadingComment.Text != null)
|
||||
this.writer.WriteLine(
|
||||
new String(' ', leadingComment.LeftIndentation) +
|
||||
(char)this.options.CommentStarter +
|
||||
leadingComment.Text);
|
||||
else
|
||||
this.writer.WriteLine();
|
||||
}
|
||||
|
||||
private void WriteEmptyLines(int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
this.writer.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user