diff --git a/LZW/LZW.sln b/LZW/LZW.sln
new file mode 100644
index 0000000..bee34d3
--- /dev/null
+++ b/LZW/LZW.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.4.33403.182
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LZW", "LZW\LZW.csproj", "{B99BFF18-B071-406A-989E-994845F53D3B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestsBor", "TestsBor\TestsBor.csproj", "{019B956A-4284-4708-9B93-8D6FC218A62E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLZW", "TestLZW\TestLZW.csproj", "{C3A8A289-5E8E-4D79-8263-3E4726F4A4CD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B99BFF18-B071-406A-989E-994845F53D3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B99BFF18-B071-406A-989E-994845F53D3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B99BFF18-B071-406A-989E-994845F53D3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B99BFF18-B071-406A-989E-994845F53D3B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {019B956A-4284-4708-9B93-8D6FC218A62E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {019B956A-4284-4708-9B93-8D6FC218A62E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {019B956A-4284-4708-9B93-8D6FC218A62E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {019B956A-4284-4708-9B93-8D6FC218A62E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C3A8A289-5E8E-4D79-8263-3E4726F4A4CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C3A8A289-5E8E-4D79-8263-3E4726F4A4CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C3A8A289-5E8E-4D79-8263-3E4726F4A4CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C3A8A289-5E8E-4D79-8263-3E4726F4A4CD}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {40032E74-4213-49E7-9C40-632CA5D1FA92}
+ EndGlobalSection
+EndGlobal
diff --git a/LZW/LZW/Bor.cs b/LZW/LZW/Bor.cs
new file mode 100644
index 0000000..c4c1338
--- /dev/null
+++ b/LZW/LZW/Bor.cs
@@ -0,0 +1,143 @@
+namespace Bor;
+
+///
+/// String Parsing Tree
+///
+public class Bor
+{
+ private BorElement root = new();
+
+ ///
+ /// Adding an element to a Trie
+ ///
+ public (bool, int) Add(char[] buffer, int from = 0, int to = 0)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException(nameof(buffer));
+ }
+
+ if (root == null)
+ {
+ throw new InvalidOperationException();
+ }
+ var walker = root;
+ int i = 0;
+ int pointer = from;
+ int toSymbolCode = -1;
+ bool isStringInBor = Contains(buffer, from, to);
+ while (i < to - from + 1)
+ {
+ int number = (int)buffer[pointer];
+ if (!walker.Next.ContainsKey(number))
+ {
+ walker.Next.Add(number, new BorElement());
+ ++walker.SizeDictionary;
+ }
+ if (!isStringInBor)
+ {
+ ++walker.Next[number].HowManyStringInDictionary;
+ }
+ toSymbolCode = walker.SymbolCode;
+ walker = walker.Next[number];
+ pointer++;
+ i++;
+ }
+ if (!walker.IsTerminal)
+ {
+ walker.SymbolCode = root.HowManyStringInDictionary;
+ root.HowManyStringInDictionary++;
+ }
+
+ if (!walker.IsTerminal)
+ {
+ walker.IsTerminal = true;
+ return (true, toSymbolCode);
+ }
+ else
+ {
+ return (true, toSymbolCode);
+ }
+
+ }
+
+ ///
+ /// Returns a stream by letter
+ ///
+ public int ReturnSymbolCodeByCharArray(char[] buffer, int to = 0, int from = 0)
+ {
+ if (buffer.Length == 0)
+ {
+ return -1;
+ }
+ var walker = root;
+ int i = 0;
+ int pointer = from;
+ while(i < to - from + 1)
+ {
+ int number = (int)buffer[pointer];
+ if (!walker.Next.ContainsKey(number))
+ {
+ return -1;
+ }
+ walker = walker.Next[number];
+ ++i;
+ }
+ return walker.SymbolCode;
+ }
+
+ ///
+ /// Returns how many strings in a Trie
+ ///
+ public int HowManyStringsInBor()
+ {
+ if (root == null)
+ {
+ return -1;
+ }
+ return root.HowManyStringInDictionary;
+ }
+
+ ///
+ /// Checks whether the string in the Trie contains
+ ///
+ public bool Contains(char[] buffer, int from = 0 , int to = 0)
+ {
+ if (root == null)
+ {
+ return false;
+ }
+ var walker = root;
+ int i = 0;
+ int pointer = from;
+ while (i < to - from + 1)
+ {
+ if (!walker.Next.ContainsKey(buffer[pointer]))
+ {
+ return false;
+ }
+ walker = walker.Next[buffer[pointer]];
+ pointer++;
+ ++i;
+ }
+ return true;
+ }
+
+ private class BorElement
+ {
+ public Dictionary Next { get; set; }
+ public bool IsTerminal { get; set; }
+
+ public int SizeDictionary { get; set; }
+
+ public int HowManyStringInDictionary { get; set; }
+
+ public int SymbolCode { get; set; }
+
+ public BorElement()
+ {
+ Next = new Dictionary();
+ SymbolCode = -1;
+ }
+ }
+}
diff --git a/LZW/LZW/LZW.cs b/LZW/LZW/LZW.cs
new file mode 100644
index 0000000..a1e4345
--- /dev/null
+++ b/LZW/LZW/LZW.cs
@@ -0,0 +1,189 @@
+namespace LZW;
+
+using Bor;
+
+///
+/// A class for compressing and decompressing data using the LZW algorithm
+///
+public static class LZWAlgorithm
+{
+ private static void AddAlphabetToBor(Bor bor)
+ {
+ var letter = new char[1];
+ for (int i = 0; i < 256; ++i)
+ {
+ letter[0] = (char)i;
+ bor.Add(letter, 0, 0);
+ }
+ }
+
+ private static bool CodeFile(string fileName, ref double compressionRatio)
+ {
+ double sizeForCompressionRatio = 0;
+ try
+ {
+ FileInfo fileFromMain = new(fileName);
+ sizeForCompressionRatio = fileFromMain.Length;
+ }
+ catch (FileNotFoundException)
+ {
+ return false;
+ }
+ string newFile = fileName + ".zipped";
+
+ File.WriteAllText(newFile, string.Empty);
+
+ var bor = new Bor();
+ AddAlphabetToBor(bor);
+
+ byte[] bufferIn = File.ReadAllBytes(fileName);
+ if (bufferIn.Length == 0)
+ {
+ compressionRatio = 1;
+ return true;
+ }
+ int j = 0;
+ var textFromFile = new char[bufferIn.Length];
+ for (int i = 0; i < bufferIn.Length; ++i)
+ {
+ textFromFile[j] = Convert.ToChar(bufferIn[i]);
+ ++j;
+ }
+
+ // Добавление потоков в файл
+ int walker = 0;
+ using var archivedFile = new FileStream(newFile, FileMode.Append);
+ for (int i = 0; i < textFromFile.Length; i++)
+ {
+ if (!bor.Contains(textFromFile, walker, i))
+ {
+ var (_, flow) = bor.Add(textFromFile, walker, i);
+ walker = i;
+ byte[] bytes = BitConverter.GetBytes(flow);
+ archivedFile.WriteAsync(bytes, 0, bytes.Length);
+ }
+ }
+
+ // Добавление последнего потока в файл
+ var flowLast = bor.ReturnSymbolCodeByCharArray(textFromFile, bufferIn.Length - 1, bufferIn.Length - 1);
+ byte[] bytesLast = BitConverter.GetBytes(flowLast);
+ archivedFile.WriteAsync(bytesLast, 0, bytesLast.Length);
+ archivedFile.Close();
+ var file = new FileInfo(newFile.ToString());
+ double newSizeForCompressionRatio = file.Length;
+ compressionRatio = newSizeForCompressionRatio / sizeForCompressionRatio;
+ return true;
+ }
+
+ private static bool DecodeFile(string fileName)
+ {
+ byte[]? bufferIn = null;
+ try
+ {
+ bufferIn = File.ReadAllBytes(fileName);
+ }
+ catch (FileNotFoundException)
+ {
+ return false;
+ }
+ int i = 0;
+ string newFile = fileName.Remove(fileName.Length - 7);
+
+ File.WriteAllText(newFile, string.Empty);
+
+ if (fileName.Length == 0)
+ {
+ return true;
+ }
+
+ var dictionaryForDecode = new Dictionary();
+
+ for (int j = 0; j < 256; ++j)
+ {
+ var stringLetter = new char[1];
+ stringLetter[0] = (char)j;
+ dictionaryForDecode.Add(j, stringLetter);
+ }
+
+ int index = 256;
+ int input = 0;
+ char[]? previousString = null;
+ bool isFirst = true;
+ while (i < bufferIn.Length)
+ {
+ var symbolFromArray = new byte[4];
+ int pointerForSymbolsFromOneArray = 0;
+ int size = i + 4;
+ for (; i < size; ++i)
+ {
+ symbolFromArray[pointerForSymbolsFromOneArray] = bufferIn[i];
+ ++pointerForSymbolsFromOneArray;
+ }
+
+ input = BitConverter.ToInt32(symbolFromArray, 0);
+
+ if (!isFirst)
+ {
+ if (!dictionaryForDecode.ContainsKey(input))
+ {
+ ArgumentNullException.ThrowIfNull(previousString);
+ Array.Resize(ref previousString, previousString.Length + 1);
+ previousString[previousString.Length - 1] = previousString[0];
+ dictionaryForDecode.Add(index, previousString);
+ }
+ var stringByIndex = dictionaryForDecode[input];
+ if (index != input)
+ {
+ ArgumentNullException.ThrowIfNull(previousString);
+ Array.Resize(ref previousString, previousString.Length + 1);
+ previousString[previousString.Length - 1] = stringByIndex[0];
+ dictionaryForDecode.Add(index, previousString);
+ }
+ FileStream file = File.Open(newFile, FileMode.Append);
+ foreach (var symbol in stringByIndex)
+ {
+ file.WriteByte((byte)symbol);
+ }
+ file.Close();
+ previousString = stringByIndex;
+ ++index;
+ }
+ else
+ {
+ var stringByIndex = dictionaryForDecode[input];
+ previousString = stringByIndex;
+ isFirst = false;
+ using FileStream file = File.Open(newFile, FileMode.Append);
+ foreach (var symbol in stringByIndex)
+ {
+ file.WriteByte((byte)symbol);
+ }
+ file.Close();
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// Function for accepting data
+ ///
+ /// Shows decompression or compression
+ /// Returns whether it was executed correctly and what is the compression percentage
+ public static (bool, double) LzwAlgorithm(string fileName, string parameter)
+ {
+ if (parameter.Length == 2 && parameter[0] == '-' && parameter[1] == 'c')
+ {
+ double compressionRatio = 0;
+ var isCorrect = CodeFile(fileName, ref compressionRatio);
+ return (isCorrect, compressionRatio);
+ }
+ else if (parameter.Length == 2 && parameter[0] == '-' && parameter[1] == 'u')
+ {
+ return (DecodeFile(fileName), 0);
+ }
+ else
+ {
+ return (false, 0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/LZW/LZW/LZW.csproj b/LZW/LZW/LZW.csproj
new file mode 100644
index 0000000..f02677b
--- /dev/null
+++ b/LZW/LZW/LZW.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/LZW/LZW/Program.cs b/LZW/LZW/Program.cs
new file mode 100644
index 0000000..c3c8a86
--- /dev/null
+++ b/LZW/LZW/Program.cs
@@ -0,0 +1,10 @@
+using LZW;
+
+
+var (isCorrect, compressionRatio) = LZWAlgorithm.LzwAlgorithm(args[0], args[1]);
+if (!isCorrect)
+{
+ Console.WriteLine("Problems...");
+ return;
+}
+Console.WriteLine(compressionRatio);
\ No newline at end of file
diff --git a/LZW/TestLZW/TestLZW.cs b/LZW/TestLZW/TestLZW.cs
new file mode 100644
index 0000000..242673f
--- /dev/null
+++ b/LZW/TestLZW/TestLZW.cs
@@ -0,0 +1,51 @@
+namespace TestLZW;
+
+using LZW;
+
+public class Tests
+{
+ [Test]
+ public void TheLZWShouldWorkCorrectlyToReturnTheCorrectValueOnASimpleExample()
+ {
+ var (isCorrect, _) = LZWAlgorithm.LzwAlgorithm(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestsForLZW", "testAnElementaryExample.txt"), "-c");
+ Assert.That(!isCorrect, Is.EqualTo(false));
+ (isCorrect, var _) = LZWAlgorithm.LzwAlgorithm(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestsForLZW", "testAnElementaryExample.txt.zipped"), "-u");
+ Assert.That(!isCorrect, Is.EqualTo(false));
+ string correctText = File.ReadAllText(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestsForLZW", "correctTestAnElementaryExample.txt"));
+ string fromLZWText = File.ReadAllText(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestsForLZW", "testAnElementaryExample.txt"));
+ Assert.That(correctText, Is.EqualTo(fromLZWText));
+ }
+
+ [Test]
+ public void LZWCodeingShouldReturnFalseWhenReceivingAFileWithAnIncorrectName()
+ {
+ var (isCorrect, _) = LZWAlgorithm.LzwAlgorithm("ds", "-c");
+ Assert.False(isCorrect);
+ }
+
+ [Test]
+ public void LZWDecodeingShouldReturnFalseWhenReceivingAFileWithAnIncorrectName()
+ {
+ var (isCorrect, _) = LZWAlgorithm.LzwAlgorithm("ds", "-u");
+ Assert.False(isCorrect);
+ }
+
+ [Test]
+ public void LZWShouldReturnFalseWhenReceivingAFileWithAnIncorrectParametr()
+ {
+ var (isCorrect, _) = LZWAlgorithm.LzwAlgorithm("ds", "-e");
+ Assert.False(isCorrect);
+ }
+
+ [Test]
+ public void TheLZWShouldReturnAnEmptyFileEmpty()
+ {
+ var (isCorrect, _) = LZWAlgorithm.LzwAlgorithm(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestsForLZW", "emptyFile.txt"), "-c");
+ Assert.That(!isCorrect, Is.EqualTo(false));
+ (isCorrect, var _) = LZWAlgorithm.LzwAlgorithm(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestsForLZW", "emptyFile.txt.zipped"), "-u");
+ Assert.That(!isCorrect, Is.EqualTo(false));
+ string fromLZWText = File.ReadAllText(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestsForLZW", "emptyFile.txt"));
+ string correctText = File.ReadAllText(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestsForLZW", "correctEmptyFile.txt"));
+ Assert.That(correctText, Is.EqualTo(fromLZWText));
+ }
+}
\ No newline at end of file
diff --git a/LZW/TestLZW/TestLZW.csproj b/LZW/TestLZW/TestLZW.csproj
new file mode 100644
index 0000000..cfd3a15
--- /dev/null
+++ b/LZW/TestLZW/TestLZW.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LZW/TestLZW/Usings.cs b/LZW/TestLZW/Usings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/LZW/TestLZW/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file
diff --git a/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/correctEmptyFile.txt b/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/correctEmptyFile.txt
new file mode 100644
index 0000000..e69de29
diff --git a/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/correctTestAnElementaryExample.txt b/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/correctTestAnElementaryExample.txt
new file mode 100644
index 0000000..1acd2c7
--- /dev/null
+++ b/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/correctTestAnElementaryExample.txt
@@ -0,0 +1 @@
+abacabadabae
\ No newline at end of file
diff --git a/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/emptyFile.txt b/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/emptyFile.txt
new file mode 100644
index 0000000..e69de29
diff --git a/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/testAnElementaryExample.txt b/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/testAnElementaryExample.txt
new file mode 100644
index 0000000..1acd2c7
--- /dev/null
+++ b/LZW/TestLZW/bin/Debug/net7.0/TestsForLZW/testAnElementaryExample.txt
@@ -0,0 +1 @@
+abacabadabae
\ No newline at end of file
diff --git a/LZW/TestsBor/TestsBor.cs b/LZW/TestsBor/TestsBor.cs
new file mode 100644
index 0000000..becd865
--- /dev/null
+++ b/LZW/TestsBor/TestsBor.cs
@@ -0,0 +1,54 @@
+namespace TestsForBor;
+
+using Bor;
+
+public class TestsForBor
+{
+ private Bor bor;
+
+ [SetUp]
+ public void Setup()
+ {
+ bor = new Bor();
+ }
+
+ [Test]
+ public void TheAddedElementShouldbeFoundInBor()
+ {
+ Setup();
+ bor.Add("end".ToCharArray(), 0, 2);
+ Assert.True(bor.Contains("end".ToCharArray(), 0, 2), "Problems with the addition test!\n");
+ }
+
+ [Test]
+ public void WhenAddingTwoLinesToBorTheBorShouldIncludeTwoLines()
+ {
+ Setup();
+ bor.Add("endProgram".ToCharArray(), 0, 9);
+ bor.Add("endFunction".ToCharArray(), 0, 10);
+ Assert.True(bor.HowManyStringsInBor() == 2, "Problems with the prefix test!");
+ }
+
+ [Test]
+ public void WhenAddingTheSymbolFlowInTheBorShouldBeCorrect()
+ {
+ Setup();
+ bor.Add("a".ToCharArray(), 0, 0);
+ bor.Add("b".ToCharArray(), 0, 0);
+ Assert.True(bor.ReturnSymbolCodeByCharArray("b".ToCharArray(), 0, 0) == 1, "Problems with the prefix test!");
+ }
+
+ [Test]
+ public void TheInitializedBorShouldBeEmpty()
+ {
+ Setup();
+ Assert.False(bor.Contains("end".ToCharArray(), 0, 2), "Problems with the prefix test!");
+ }
+
+ [Test]
+ public void ThereShouldBeNoThreadsInTheCreatedBor()
+ {
+ Assert.True(bor.ReturnSymbolCodeByCharArray("".ToCharArray(), 0, 0) == -1, "Problems with the prefix test!");
+ }
+
+}
\ No newline at end of file
diff --git a/LZW/TestsBor/TestsBor.csproj b/LZW/TestsBor/TestsBor.csproj
new file mode 100644
index 0000000..cfd3a15
--- /dev/null
+++ b/LZW/TestsBor/TestsBor.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LZW/TestsBor/Usings.cs b/LZW/TestsBor/Usings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/LZW/TestsBor/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file