mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-21 21:38:52 +00:00
StreamReader implemented but found bug in IL2CPU plug resolution :-(
This commit is contained in:
parent
eb0a469315
commit
81234d1cd9
12 changed files with 560 additions and 148 deletions
|
|
@ -16,5 +16,43 @@ namespace Cosmos.Compiler.Tests.Bcl.Helper
|
|||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility method to test Byte[] equality.
|
||||
/// </summary>
|
||||
/// <param name="a1">Byte array.</param>
|
||||
/// <param name="a2">Byte array.</param>
|
||||
/// <returns>True if the elements in the arrays are equal otherwise false.</returns>
|
||||
public static bool ByteArrayAreEquals(byte[] a1, byte[] a2)
|
||||
{
|
||||
if (ReferenceEquals(a1, a2))
|
||||
{
|
||||
//mDebugger.Send("a1 and a2 are the same Object");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a1 == null || a2 == null)
|
||||
{
|
||||
//mDebugger.Send("a1 or a2 is null so are different");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a1.Length != a2.Length)
|
||||
{
|
||||
//mDebugger.Send("a1.Length != a2.Length so are different");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < a1.Length; i++)
|
||||
{
|
||||
if (a1[i] != a2[i])
|
||||
{
|
||||
//mDebugger.Send("In position " + i + " a byte is different");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace Cosmos.Kernel.Tests.Fat
|
|||
PathTest.Execute(mDebugger);
|
||||
DirectoryTest.Execute(mDebugger);
|
||||
#endif
|
||||
//FileTest.Execute(mDebugger);
|
||||
// FileTest.Execute(mDebugger);
|
||||
#if false
|
||||
FileStreamTest.Execute(mDebugger);
|
||||
DirectoryInfoTest.Execute(mDebugger);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using Cosmos.TestRunner;
|
||||
using Cosmos.Debug.Kernel;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Cosmos.Kernel.Tests.Fat.System.IO
|
||||
{
|
||||
|
|
@ -11,32 +12,63 @@ namespace Cosmos.Kernel.Tests.Fat.System.IO
|
|||
/// Tests System.IO.StreamWriter plugs.
|
||||
/// </summary>
|
||||
public static void Execute(Debugger mDebugger)
|
||||
{
|
||||
{
|
||||
string file = @"0:\test.txt";
|
||||
|
||||
mDebugger.Send("START TEST: StreamWriter:");
|
||||
mDebugger.Send("Create StreamWriter");
|
||||
|
||||
using (var xSW = new StreamWriter(@"0:\test.txt"))
|
||||
/*
|
||||
* To Show that UTF-8 is effectively working you write in the file "Cosmos is wonderful!" in Japanase
|
||||
* and read it again
|
||||
*/
|
||||
var text = "Cosmos 素晴らしいです!";
|
||||
|
||||
using (var xSW = new StreamWriter(file))
|
||||
{
|
||||
|
||||
if (xSW != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mDebugger.Send("Start writing");
|
||||
if (xSW == null)
|
||||
Assert.IsTrue(false, $"Failed to create StreamWriter for file {file}");
|
||||
|
||||
xSW.Write("0123");
|
||||
//xSW.Write("A line of text for testing\nSecond line");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Assert.IsTrue(false, $"Couldn't write to file 0:\test.txt using StreamWriter {e.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
try
|
||||
{
|
||||
Assert.IsTrue(false, @"Failed to create StreamWriter for file 0:\test.txt");
|
||||
mDebugger.Send("Start writing");
|
||||
|
||||
xSW.Write(text);
|
||||
}
|
||||
|
||||
catch
|
||||
{
|
||||
Assert.IsTrue(false, $"Couldn't write to file {file} using StreamWriter");
|
||||
}
|
||||
}
|
||||
mDebugger.Send("END TEST");
|
||||
|
||||
#if true
|
||||
/* We use StreamReader() instead of File now it is more "correct" and we test 2 classes in one too! */
|
||||
mDebugger.Send("START TEST: StreamReader:");
|
||||
using (var xSR = new StreamReader(file))
|
||||
{
|
||||
if (xSR == null)
|
||||
Assert.IsTrue(false, $"Failed to create StreamReader for file {file}");
|
||||
|
||||
try
|
||||
{
|
||||
mDebugger.Send("Start reading");
|
||||
var readText = xSR.ReadToEnd();
|
||||
Assert.IsTrue(text == readText, "Failed to write and read file");
|
||||
}
|
||||
catch
|
||||
{
|
||||
Assert.IsTrue(false, $"Couldn't read from file {file} using StreamReader");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
using (StreamReader xSR2 = new StreamReader(file, Encoding.UTF8, true))
|
||||
{
|
||||
mDebugger.Send("Reading using different Ctor!!!");
|
||||
var readText2 = xSR2.ReadToEnd();
|
||||
mDebugger.Send($"Read {readText2}");
|
||||
|
||||
Assert.IsTrue(text == readText2, "Failed to write and read file");
|
||||
}
|
||||
|
||||
mDebugger.Send("END TEST");
|
||||
|
|
|
|||
|
|
@ -17,17 +17,19 @@ namespace Cosmos.TestRunner.Core
|
|||
{
|
||||
|
||||
//yield return typeof(BoxingTests.Kernel);
|
||||
yield return typeof(Cosmos.Compiler.Tests.TypeSystem.Kernel);
|
||||
yield return typeof(Cosmos.Compiler.Tests.Bcl.Kernel);
|
||||
// yield return typeof(Cosmos.Compiler.Tests.TypeSystem.Kernel);
|
||||
// yield return typeof(Cosmos.Compiler.Tests.Bcl.Kernel);
|
||||
//yield return typeof(Cosmos.Compiler.Tests.Encryption.Kernel);
|
||||
#if false
|
||||
yield return typeof(Cosmos.Compiler.Tests.Exceptions.Kernel);
|
||||
yield return typeof(Cosmos.Compiler.Tests.LinqTests.Kernel);
|
||||
yield return typeof(Cosmos.Compiler.Tests.MethodTests.Kernel);
|
||||
yield return typeof(Cosmos.Compiler.Tests.SimpleWriteLine.Kernel);
|
||||
yield return typeof(Cosmos.Compiler.Tests.SingleEchoTest.Kernel);
|
||||
#endif
|
||||
/* Let's test only this for now */
|
||||
yield return typeof(Cosmos.Kernel.Tests.Fat.Kernel);
|
||||
yield return typeof(Cosmos.Kernel.Tests.IO.Kernel);
|
||||
//yield return typeof(Cosmos.Kernel.Tests.IO.Kernel);
|
||||
#if false
|
||||
yield return typeof(SimpleStructsAndArraysTest.Kernel);
|
||||
yield return typeof(VGACompilerCrash.Kernel);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#define COSMOSDEBUG
|
||||
//#define COSMOSDEBUG
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Cosmos.Common;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,45 @@ namespace Cosmos.System2.Encoding
|
|||
{
|
||||
public abstract class CosmosEncoding
|
||||
{
|
||||
public abstract Byte[] GetBytes(String s);
|
||||
public abstract String GetString(Byte[] bytes);
|
||||
public abstract int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex);
|
||||
|
||||
//public abstract String GetString(Byte[] bytes);
|
||||
|
||||
public abstract int GetMaxByteCount(int ByteCount);
|
||||
|
||||
public virtual byte[] GetBytes(string s)
|
||||
{
|
||||
byte[] bytes = new byte[GetMaxByteCount(s.Length)];
|
||||
char[] textToEncode = s.ToCharArray();
|
||||
int nBytes;
|
||||
|
||||
nBytes = GetBytes(textToEncode, 0, textToEncode.Length, bytes, 0);
|
||||
|
||||
/*
|
||||
* This could be not the fastest method (it creates a new array and then does a copy of the old
|
||||
* until 'nBytes') but the alternative way was to call a version of GetBytes() that only counts
|
||||
* the encoded bytes and allocate the array using the correct size and then call GetBytes().
|
||||
* This is the approach used by the real Encoding class I'm unsure it is faster sincerely...
|
||||
* in the end is doing the encoding two times!
|
||||
*
|
||||
* Remeber - in any case - that this is a temporary solution we should plug the real Encoding class...
|
||||
*/
|
||||
Array.Resize(ref bytes, nBytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public abstract int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex);
|
||||
|
||||
public string GetString(byte[] bytes)
|
||||
{
|
||||
int numChar;
|
||||
char[] chars = new char[bytes.Length];
|
||||
|
||||
numChar = GetChars(bytes, 0, bytes.Length, chars, 0);
|
||||
|
||||
Array.Resize(ref chars, numChar);
|
||||
|
||||
return new string(chars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,32 +8,242 @@ namespace Cosmos.System2.Encoding
|
|||
{
|
||||
public class CosmosUTF8Encoding : CosmosEncoding
|
||||
{
|
||||
public override byte[] GetBytes(string s)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"Encoding string {s}");
|
||||
private const uint UNI_REPLACEMENT_CHAR = 0x0000FFFD;
|
||||
private const uint UNI_SUR_HIGH_START = 0xD800;
|
||||
private const uint UNI_SUR_HIGH_END = 0xDBFF;
|
||||
private const uint UNI_SUR_LOW_START = 0xDC00;
|
||||
private const uint UNI_SUR_LOW_END = 0xDFFF;
|
||||
private const uint UNI_MAX_BMP = 0x0000FFFF;
|
||||
private const uint UNI_MAX_UTF16 = 0x0010FFFF;
|
||||
private const int halfShift = 10;
|
||||
private const int halfBase = 0x0010000;
|
||||
private const uint halfMask = 0x3FF;
|
||||
|
||||
//byte[] xResult = new byte[GetMaxByteCount(s.Length)];
|
||||
List <byte> xResult = new List<byte>();
|
||||
/* Only Ascii for now */
|
||||
foreach (var aChar in s)
|
||||
/*
|
||||
* Index into the table below with the first byte of a UTF-8 sequence to
|
||||
* get the number of trailing bytes that are supposed to follow it.
|
||||
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
|
||||
* left as-is for anyone who may want to do such conversion, which was
|
||||
* allowed in earlier algorithms.
|
||||
*/
|
||||
private static int[] trailingBytesForUTF8 = new int[] {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
/*
|
||||
* Magic values subtracted from a buffer value during UTF8 conversion.
|
||||
* This table contains as many values as there might be trailing bytes
|
||||
* in a UTF-8 sequence.
|
||||
*/
|
||||
static uint[] offsetsFromUTF8 = new uint[] { 0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080,
|
||||
0x82082080 };
|
||||
|
||||
private static int GetCharBytes(uint ch, byte[] bytes, int byteIndex, int bytePos)
|
||||
{
|
||||
int bytesToWrite;
|
||||
|
||||
// Filter out byte order marks and invalid character 0xFFFF
|
||||
if ((ch == 0xFEFF) || (ch == 0xFFFE) || (ch == 0xFFFF))
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"Encoding char {aChar}");
|
||||
if (aChar > 0 || aChar < 127)
|
||||
xResult.Add((byte)aChar);
|
||||
else
|
||||
throw new ArgumentOutOfRangeException("Input string contains invalid characters for UTF-8");
|
||||
return bytePos;
|
||||
}
|
||||
|
||||
return xResult.ToArray();
|
||||
//throw new NotImplementedException("GetBytes()");
|
||||
/* Figure out how many bytes the result will require */
|
||||
if (ch < 0x80) /* 0XXX XXXX one byte */
|
||||
bytesToWrite = 1;
|
||||
else if (ch < 0x800) /* 110X XXXX two bytes */
|
||||
bytesToWrite = 2;
|
||||
else if (ch < 0x10000) /* 1110 XXXX three bytes */
|
||||
bytesToWrite = 3;
|
||||
else if (ch < 0x110000) /* 1111 0XXX four bytes */
|
||||
bytesToWrite = 4;
|
||||
else /* Invalid Unicode sequence Encode it as UNI_REPLACEMENT_CHAR */
|
||||
{
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
return GetCharBytes(ch, bytes, byteIndex, bytePos);
|
||||
}
|
||||
|
||||
/* Check if there is sufficient space on bytes before writing on it */
|
||||
if (bytes.Length - (byteIndex + bytePos) < bytesToWrite)
|
||||
throw new ArgumentException("bytes has no sufficient space");
|
||||
|
||||
switch (bytesToWrite)
|
||||
{
|
||||
case 1:
|
||||
bytes[byteIndex + bytePos + 0] = (byte)ch;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
bytes[byteIndex + bytePos + 0] = (byte)(0xC0 | (ch >> 6));
|
||||
bytes[byteIndex + bytePos + 1] = (byte)(0x80 | (ch & 0x3F));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
bytes[byteIndex + bytePos + 0] = (byte)(0xE0 | (ch >> 12));
|
||||
bytes[byteIndex + bytePos + 1] = (byte)(0x80 | ((ch >> 6) & 0x3F));
|
||||
bytes[byteIndex + bytePos + 2] = (byte)(0x80 | (ch & 0x3F));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
bytes[byteIndex + bytePos + 0] = (byte)(0xF0 | (ch >> 18));
|
||||
bytes[byteIndex + bytePos + 1] = (byte)(0x80 | ((ch >> 12) & 0x3F));
|
||||
bytes[byteIndex + bytePos + 2] = (byte)(0x80 | ((ch >> 6) & 0x3F));
|
||||
bytes[byteIndex + bytePos + 3] = (byte)(0x80 | (ch & 0x3F));
|
||||
break;
|
||||
}
|
||||
|
||||
//bytePos += bytesToWrite;
|
||||
return bytesToWrite;
|
||||
}
|
||||
|
||||
/* Some UFT-8 char can occupy 3 bytes */
|
||||
public override int GetMaxByteCount(int ByteCount) => 3 * ByteCount;
|
||||
|
||||
public override string GetString(byte[] bytes)
|
||||
private static uint HandleSurrogatePairs(uint SurrFirst, uint SurrSecond)
|
||||
{
|
||||
throw new NotImplementedException("GetString()");
|
||||
if (SurrSecond >= UNI_SUR_LOW_START && SurrSecond <= UNI_SUR_LOW_END)
|
||||
{
|
||||
return ((SurrFirst - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (SurrSecond - UNI_SUR_LOW_START) + halfBase;
|
||||
}
|
||||
else /* it's an unpaired high surrogate */
|
||||
{
|
||||
throw new ArgumentException("Source contains unpaired surrogate");
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
|
||||
{
|
||||
if (chars == null)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"chars is null returning 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (charIndex == 0 && charCount == 0)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"charIndex and charCount both 0 returning 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bytePos = 0;
|
||||
|
||||
for (int i = charIndex; i < charCount; i++)
|
||||
{
|
||||
uint ch = chars[i];
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
|
||||
{
|
||||
/* There is the next part of the surrogate? */
|
||||
if (chars.Length >= i + 1)
|
||||
{
|
||||
i++;
|
||||
ch = HandleSurrogatePairs(ch, chars[i]);
|
||||
}
|
||||
else
|
||||
throw new ArgumentException("Source contains unpaired surrogate");
|
||||
}
|
||||
|
||||
bytePos += GetCharBytes(ch, bytes, byteIndex, bytePos);
|
||||
}
|
||||
|
||||
return bytePos;
|
||||
}
|
||||
|
||||
/* Some UFT-8 "character" can occupy 4 bytes */
|
||||
public override int GetMaxByteCount(int ByteCount) => 4 * ByteCount;
|
||||
|
||||
private static uint GetCharFromUFT8(byte[] bytes, out int bytesConsumed, int bytePos)
|
||||
{
|
||||
//uint ch = bytes[bytePos];
|
||||
uint ch = 0;
|
||||
|
||||
int UtfTrailingBytes = trailingBytesForUTF8[bytes[bytePos]];
|
||||
int Uft8CharLen = UtfTrailingBytes + 1;
|
||||
bytesConsumed = Uft8CharLen;
|
||||
|
||||
int i = bytePos;
|
||||
/* We "consume" the bytes and do the needed bitmasking to obtain the corrisponding codepoint */
|
||||
do
|
||||
{
|
||||
ch += bytes[i];
|
||||
i++;
|
||||
--Uft8CharLen;
|
||||
if (Uft8CharLen != 0)
|
||||
ch <<= 6;
|
||||
} while (Uft8CharLen > 0);
|
||||
ch -= offsetsFromUTF8[UtfTrailingBytes];
|
||||
|
||||
/* Target is a character <= 0xFFFF */
|
||||
if (ch <= UNI_MAX_BMP)
|
||||
{
|
||||
/* Invalid surrugates */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
|
||||
return UNI_REPLACEMENT_CHAR;
|
||||
/* normal case */
|
||||
else
|
||||
return (char)ch;
|
||||
}
|
||||
else if (ch > UNI_MAX_UTF16)
|
||||
{
|
||||
return UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
/* surrogate pairs */
|
||||
else
|
||||
{
|
||||
ushort lo = 0;
|
||||
ushort hi = 0;
|
||||
ch -= halfBase;
|
||||
hi = (ushort)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
lo = (ushort)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
/*
|
||||
* We pack the two halves of the pair in an uint sadly we need to unpack them later
|
||||
* the alternative was to make this function return an array of character that will be really
|
||||
* used only in this case :-(
|
||||
*/
|
||||
ch = (uint)((uint)hi << 16 | (uint)lo);
|
||||
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
|
||||
{
|
||||
uint ch = 0;
|
||||
int bytesConsumed = 0;
|
||||
//for (i = byteIndex; i < byteCount; i++)
|
||||
int numChar = 0;
|
||||
int bytePos = byteIndex;
|
||||
while (byteCount != 0)
|
||||
{
|
||||
ch = GetCharFromUFT8(bytes, out bytesConsumed, bytePos);
|
||||
/* check that chars has sufficient space */
|
||||
if (chars.Length < (charIndex + numChar))
|
||||
throw new ArgumentException("chars has no sufficient space");
|
||||
|
||||
if (ch < UNI_SUR_HIGH_START)
|
||||
chars[charIndex + numChar] = (char)ch;
|
||||
else
|
||||
{
|
||||
/* Unpach the uint in the two paired surrugates */
|
||||
char chHigh = (char)(ch >> 16);
|
||||
char chLow = (char)(ch & 0xFFFF);
|
||||
chars[charIndex + numChar] = chHigh;
|
||||
chars[charIndex + numChar + 1] = chLow;
|
||||
numChar++;
|
||||
}
|
||||
|
||||
/* skip the part of 'bytes' we have already consumed */
|
||||
byteCount -= bytesConsumed;
|
||||
bytePos += bytesConsumed;
|
||||
numChar++;
|
||||
}
|
||||
|
||||
return numChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,15 +89,15 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
|
||||
public static object /* FileStreamBase */ Open(object aThis, string fullPath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, FileStream parent)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("In FileStream.InitializeStream");
|
||||
Global.mFileSystemDebugger.SendInternal("In CosmosFileSystem.Open");
|
||||
if (fullPath == null)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("In FileStream.Ctor: Path == null is true");
|
||||
Global.mFileSystemDebugger.SendInternal("In CosmosFileSystem.Open: Path == null is true");
|
||||
throw new ArgumentNullException("The file path cannot be null.");
|
||||
}
|
||||
if (fullPath.Length == 0)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("In FileStream.Ctor: Path.Length == 0 is true");
|
||||
Global.mFileSystemDebugger.SendInternal("In CosmosFileSystem.Open: Path.Length == 0 is true");
|
||||
throw new ArgumentException("The file path cannot be empty.");
|
||||
}
|
||||
|
||||
|
|
@ -108,6 +108,17 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
|
||||
Stream aStream = null;
|
||||
|
||||
Global.mFileSystemDebugger.SendInternal($"Create Mode aPath {fullPath}");
|
||||
|
||||
var xEntry = VFSManager.CreateFile(fullPath);
|
||||
if (xEntry == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
aStream = VFSManager.GetFileStream(fullPath);
|
||||
|
||||
#if false
|
||||
switch (mode)
|
||||
{
|
||||
case FileMode.Append:
|
||||
|
|
@ -129,7 +140,8 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
case FileMode.Create:
|
||||
Global.mFileSystemDebugger.SendInternal("Create Mode aPath will be overwritten if existing");
|
||||
// TODO it seems that GetFileStream effectively Creates the file if not exist
|
||||
aStream = File.Create(fullPath);
|
||||
//aStream = File.Create(fullPath);
|
||||
aStream = VFSManager.GetFileStream(fullPath);
|
||||
break;
|
||||
|
||||
case FileMode.CreateNew:
|
||||
|
|
@ -141,7 +153,8 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
|
||||
Global.mFileSystemDebugger.SendInternal("CreateNew Mode with aPath not existing new file created");
|
||||
// TODO it seems that GetFileStream effectively Creates the file if it does not exist
|
||||
aStream = File.Create(fullPath);
|
||||
//aStream = File.Create(fullPath);
|
||||
aStream = VFSManager.GetFileStream(fullPath);
|
||||
break;
|
||||
|
||||
case FileMode.Open:
|
||||
|
|
@ -181,6 +194,7 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
Global.mFileSystemDebugger.SendInternal("The mode " + mode + "is out of range");
|
||||
throw new ArgumentOutOfRangeException("The file mode is invalid");
|
||||
}
|
||||
#endif
|
||||
|
||||
return aStream;
|
||||
}
|
||||
|
|
@ -211,5 +225,37 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeleteFile(object aThis, string fullPath)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"DeleteFile : fullPath = {fullPath}");
|
||||
VFSManager.DeleteFile(fullPath);
|
||||
}
|
||||
|
||||
public static void CopyFile(object aThis, string sourceFullPath, string destFullPath, bool overwrite)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"CopyFile {sourceFullPath} into {destFullPath}");
|
||||
|
||||
// The destination path may just be a directory into which the file should be copied.
|
||||
// If it is, append the filename from the source onto the destination directory
|
||||
if (Directory.Exists(destFullPath))
|
||||
{
|
||||
destFullPath = Path.Combine(destFullPath, Path.GetFileName(sourceFullPath));
|
||||
}
|
||||
|
||||
// Copy the contents of the file from the source to the destination, creating the destination in the process
|
||||
using (var src = new FileStream(sourceFullPath, FileMode.Open))
|
||||
using (var dst = new FileStream(destFullPath, overwrite ? FileMode.Create : FileMode.CreateNew))
|
||||
{
|
||||
int xSize = (int)src.Length;
|
||||
Global.mFileSystemDebugger.SendInternal($"size of {sourceFullPath} is {xSize} bytes");
|
||||
byte[] content = new byte[xSize];
|
||||
Global.mFileSystemDebugger.SendInternal($"content byte buffer allocated");
|
||||
src.Read(content, 0, xSize);
|
||||
Global.mFileSystemDebugger.SendInternal($"content byte buffer read");
|
||||
dst.Write(content, 0, xSize);
|
||||
Global.mFileSystemDebugger.SendInternal($"content byte buffer written");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Cosmos.IL2CPU.API;
|
|||
using Cosmos.IL2CPU.API.Attribs;
|
||||
using Cosmos.System.FileSystem;
|
||||
using Cosmos.System.FileSystem.VFS;
|
||||
using System.Text;
|
||||
|
||||
namespace Cosmos.System_Plugs.System.IO
|
||||
{
|
||||
|
|
@ -16,6 +17,7 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
[Plug(Target = typeof(File))]
|
||||
public static class FileImpl
|
||||
{
|
||||
#if false
|
||||
public static bool Exists(string aFile)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("File.Exists:");
|
||||
|
|
@ -29,7 +31,17 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
|
||||
return VFSManager.FileExists(aFile);
|
||||
}
|
||||
|
||||
#endif
|
||||
public static string ReadAllText(string aFile)
|
||||
{
|
||||
string result;
|
||||
using (StreamReader streamReader = new StreamReader(aFile, Encoding.UTF8, true))
|
||||
{
|
||||
result = streamReader.ReadToEnd();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#if false
|
||||
public static string ReadAllText(string aFile)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("File.ReadAllText:");
|
||||
|
|
@ -55,7 +67,9 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
return xResultStr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if false
|
||||
public static void WriteAllText(string aFile, string aText)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("Creating stream with file " + aFile);
|
||||
|
|
@ -93,6 +107,7 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static void AppendAllText(string aFile, string aText)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("Creating stream in Append Mode with file " + aFile);
|
||||
|
|
@ -106,6 +121,7 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static string[] ReadAllLines(string aFile)
|
||||
{
|
||||
String text = ReadAllText(aFile);
|
||||
|
|
@ -119,15 +135,34 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Plug needed for the usual issue that Array can not be converted in IEnumerable... it is starting
|
||||
* to become annoying :-(
|
||||
*/
|
||||
public static void WriteAllLines(string aFile, string[] contents)
|
||||
{
|
||||
string text = String.Join(Environment.NewLine, contents);
|
||||
|
||||
if (aFile == null)
|
||||
{
|
||||
throw new ArgumentNullException("path");
|
||||
}
|
||||
if (contents == null)
|
||||
{
|
||||
throw new ArgumentNullException("contents");
|
||||
}
|
||||
if (aFile.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Empty", "aFile");
|
||||
}
|
||||
|
||||
Global.mFileSystemDebugger.SendInternal("Writing contents");
|
||||
Global.mFileSystemDebugger.SendInternal(text);
|
||||
|
||||
WriteAllText(aFile, text);
|
||||
|
||||
using (var xSW = new StreamWriter(aFile))
|
||||
{
|
||||
foreach (var current in contents)
|
||||
xSW.WriteLine(current);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ReadAllBytes(string aFile)
|
||||
|
|
@ -155,40 +190,14 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
public static void Copy(string srcFile, string destFile)
|
||||
{
|
||||
try
|
||||
using (var xFS = new FileStream(srcFile, FileMode.Open))
|
||||
{
|
||||
byte[] srcFileBytes = File.ReadAllBytes(srcFile);
|
||||
File.WriteAllBytes(destFile, srcFileBytes);
|
||||
}
|
||||
catch (IOException ioEx)
|
||||
{
|
||||
throw new IOException("File Copy", ioEx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Copy(string srcFile, string destFile, bool overwriting)
|
||||
{
|
||||
if (overwriting)
|
||||
{
|
||||
if (File.Exists(destFile))
|
||||
{
|
||||
File.Delete(destFile);
|
||||
}
|
||||
|
||||
Copy(srcFile, destFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!File.Exists(destFile))
|
||||
{
|
||||
Copy(srcFile, destFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("destFileName exists and overwrite is false.");
|
||||
}
|
||||
var xBuff = new byte[(int)xFS.Length];
|
||||
var yFS = new FileStream(destFile, FileMode.Create);
|
||||
yFS.Write(xBuff, 0, xBuff.Length);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,6 +208,7 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
VFSManager.DeleteFile(xFullPath);
|
||||
}
|
||||
|
||||
|
||||
public static FileStream Create(string aFile)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("File.Create:");
|
||||
|
|
@ -216,5 +226,6 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
|
||||
return new FileStream(aFile, FileMode.Open);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,19 +19,37 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
|
||||
// public static unsafe void Ctor(String aThis, [FieldAccess(Name = "$$Storage$$")]ref Char[] aStorage, Char[] aChars, int aStartIndex, int aLength,
|
||||
|
||||
public static void Ctor(FileStream aThis, string aPathname, FileMode aMode,
|
||||
[FieldAccess(Name = InnerStreamFieldId)] ref Stream innerStream)
|
||||
private static void Init(string aPathname, FileMode aMode, ref Stream innerStream)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("FileStream.Ctor:");
|
||||
|
||||
innerStream = InitializeStream(aPathname, aMode);
|
||||
}
|
||||
|
||||
|
||||
public static void Ctor(FileStream aThis, string aPathname, FileMode aMode,
|
||||
[FieldAccess(Name = InnerStreamFieldId)] ref Stream innerStream)
|
||||
{
|
||||
Init(aPathname, aMode, ref innerStream);
|
||||
#if false
|
||||
Global.mFileSystemDebugger.SendInternal("FileStream.Ctor:");
|
||||
|
||||
innerStream = InitializeStream(aPathname, aMode);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void CCtor()
|
||||
{
|
||||
// plug cctor as it (indirectly) uses Thread.MemoryBarrier()
|
||||
}
|
||||
|
||||
public static void Ctor(FileStream aThis, string aPathname, FileMode aMode, FileAccess access,
|
||||
FileShare share, int bufferSize, FileOptions options,
|
||||
[FieldAccess(Name = InnerStreamFieldId)] ref Stream innerStream)
|
||||
{
|
||||
Init(aPathname, aMode, ref innerStream);
|
||||
}
|
||||
|
||||
public static int Read(FileStream aThis, byte[] aBuffer, int aOffset, int aCount,
|
||||
[FieldAccess(Name = InnerStreamFieldId)] ref Stream innerStream)
|
||||
{
|
||||
|
|
@ -48,7 +66,7 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
public static void Write(FileStream aThis, byte[] aBuffer, int aOffset, int aCount,
|
||||
[FieldAccess(Name = InnerStreamFieldId)] ref Stream innerStream)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("FileStream.Write:");
|
||||
Global.mFileSystemDebugger.SendInternal($"FileStream.Write: aOffset {aOffset} aCount {aCount}");
|
||||
|
||||
innerStream.Write(aBuffer, aOffset, aCount);
|
||||
}
|
||||
|
|
@ -83,6 +101,7 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
public static void Flush(FileStream aThis,
|
||||
[FieldAccess(Name = InnerStreamFieldId)] ref Stream innerStream)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"In FileStream.InitializeStream Flush()");
|
||||
innerStream.Flush();
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +162,13 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
case FileMode.Create:
|
||||
Global.mFileSystemDebugger.SendInternal("Create Mode aPath will be overwritten if existing");
|
||||
// TODO it seems that GetFileStream effectively Creates the file if not exist
|
||||
aStream = File.Create(aPath);
|
||||
var xEntry = VFSManager.CreateFile(aPath);
|
||||
if (xEntry == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
//aStream = File.Create(aPath);
|
||||
aStream = VFSManager.GetFileStream(aPath);
|
||||
break;
|
||||
|
||||
case FileMode.CreateNew:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using Cosmos.IL2CPU.API.Attribs;
|
||||
using Cosmos.System;
|
||||
|
||||
namespace Cosmos.Kernel.Tests.Fat.System.IO
|
||||
namespace Cosmos.System_Plugs.System.IO
|
||||
{
|
||||
[Plug(TargetName = "System.IO.PathInternal, System.IO.FileSystem")]
|
||||
public static class PathInternalImpl
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.IO;
|
|||
using Cosmos.System;
|
||||
using Cosmos.IL2CPU.API.Attribs;
|
||||
using Cosmos.System2.Encoding;
|
||||
using System.Text;
|
||||
|
||||
namespace Cosmos.System_Plugs.System.IO
|
||||
{
|
||||
|
|
@ -11,38 +12,19 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
[Plug(Target = typeof(StreamWriter))]
|
||||
public static class StreamWriterImpl
|
||||
{
|
||||
private const string StreamFieldId = "System.IO.Stream System.IO.StreamWriter._stream";
|
||||
private const string CharPosFieldId = "System.Int32 System.IO.StreamWriter._charPos";
|
||||
private const string CharLenFieldId = "System.Int32 System.IO.StreamWriter._charLen";
|
||||
private const string CharBufferFieldId = "System.Char[] System.IO.StreamWriter._charBuffer";
|
||||
private const string ByteBufferFieldId = "System.Byte[] System.IO.StreamWriter._byteBuffer";
|
||||
|
||||
#if false
|
||||
public static void Ctor(StreamWriter aThis, string path)
|
||||
{
|
||||
throw new NotImplementedException("StreamWriter Ctor(String path)");
|
||||
}
|
||||
#endif
|
||||
private static CosmosEncoding FileEncoding;
|
||||
//private static Stream InnerStream;
|
||||
|
||||
#if false
|
||||
private static void Init(Stream stream, CosmosEncoding encoding)
|
||||
private static void Init(String path, bool append, ref Stream stream, CosmosEncoding encoding,
|
||||
ref char[] charBuffer, int bufferSize, ref byte[] byteBuffer, bool shouldLeaveOpen,
|
||||
ref char[] CoreNewLine)
|
||||
{
|
||||
//InnerStream = stream;
|
||||
FileEncoding = encoding;
|
||||
}
|
||||
#endif
|
||||
private static void Init(CosmosEncoding encoding, ref char[] charBuffer, int bufferSize, ref byte[] byteBuffer, bool shouldLeaveOpen)
|
||||
{
|
||||
FileEncoding = encoding;
|
||||
charBuffer = new char[bufferSize];
|
||||
byteBuffer = new byte[bufferSize * FileEncoding.GetMaxByteCount(bufferSize)];
|
||||
}
|
||||
|
||||
public static void Ctor(StreamWriter aThis, string path,
|
||||
[FieldAccess(Name = "System.IO.Stream System.IO.StreamWriter._stream")] ref Stream _stream,
|
||||
[FieldAccess(Name = "System.Int32 System.IO.StreamWriter._charPos")] ref int _charPos,
|
||||
[FieldAccess(Name = "System.Char[] System.IO.StreamWriter._charBuffer")] ref char[] _charBuffer,
|
||||
[FieldAccess(Name = "System.Byte[] System.IO.StreamWriter._byteBuffer")] ref byte[] _byteBuffer
|
||||
)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"StreamWriter.Ctor() with path {path}");
|
||||
if (path == null)
|
||||
{
|
||||
throw new ArgumentNullException("path");
|
||||
|
|
@ -52,47 +34,76 @@ namespace Cosmos.System_Plugs.System.IO
|
|||
throw new ArgumentException("Empty path");
|
||||
}
|
||||
|
||||
_stream = new FileStream(path, FileMode.Create);
|
||||
Init(new CosmosUTF8Encoding(), ref _charBuffer, 128, ref _byteBuffer, false);
|
||||
Global.mFileSystemDebugger.SendInternal($"StreamWriter.Init() with path {path} append {append} bufferSize {bufferSize}");
|
||||
stream = new FileStream(path, append ? FileMode.Append : FileMode.Create);
|
||||
FileEncoding = encoding;
|
||||
charBuffer = new char[bufferSize];
|
||||
byteBuffer = new byte[FileEncoding.GetMaxByteCount(bufferSize)];
|
||||
CoreNewLine = new char[] { '\n', '\r' };
|
||||
}
|
||||
|
||||
/*
|
||||
* This constructor is really plugged only to enforce our simplified version of UTF8 encoding using other
|
||||
* enconding will be silently ignored (I liked to check for this and throw Exception but == operator
|
||||
* does not work with Encoding neither Equals)
|
||||
*/
|
||||
public static void Ctor(StreamWriter aThis, string path, bool append, Encoding encoding, int bufferSize,
|
||||
[FieldAccess(Name = StreamFieldId)] ref Stream _stream,
|
||||
[FieldAccess(Name = CharPosFieldId)] ref int _charPos,
|
||||
[FieldAccess(Name = CharLenFieldId)] ref int _charLen,
|
||||
[FieldAccess(Name = CharBufferFieldId)] ref char[] _charBuffer,
|
||||
[FieldAccess(Name = ByteBufferFieldId)] ref byte[] _byteBuffer,
|
||||
[FieldAccess(Name = "System.Char[] System.IO.TextWriter.CoreNewLine")] ref char[] CoreNewLine
|
||||
)
|
||||
{
|
||||
#if false
|
||||
//if (!Equals(encoding, Encoding.UTF8))
|
||||
if (!encoding.Equals(Encoding.UTF8))
|
||||
throw new NotImplementedException("Only UFT8 Encoding implemented");
|
||||
#endif
|
||||
|
||||
Global.mFileSystemDebugger.SendInternal($"StreamWriter.Ctor() with path {path} append {append} Encoding and bufferSize {bufferSize}");
|
||||
Init(path, append, ref _stream, new CosmosUTF8Encoding(), ref _charBuffer, _charLen = bufferSize, ref _byteBuffer, false, ref CoreNewLine);
|
||||
}
|
||||
|
||||
public static void Flush(StreamWriter aThis, bool flushStream, bool flushEncoder,
|
||||
[FieldAccess(Name = "System.IO.Stream System.IO.StreamWriter._stream")] ref Stream _stream,
|
||||
[FieldAccess(Name = "System.Int32 System.IO.StreamWriter._charPos")] ref int _charPos,
|
||||
[FieldAccess(Name = "System.Char[] System.IO.StreamWriter._charBuffer")] ref char[] _charBuffer,
|
||||
[FieldAccess(Name = "System.Byte[] System.IO.StreamWriter._byteBuffer")] ref byte[] _byteBuffer
|
||||
[FieldAccess(Name = StreamFieldId)] ref Stream _stream,
|
||||
[FieldAccess(Name = CharPosFieldId)] ref int _charPos,
|
||||
[FieldAccess(Name = CharBufferFieldId)] ref char[] _charBuffer,
|
||||
[FieldAccess(Name = ByteBufferFieldId)] ref byte[] _byteBuffer
|
||||
)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"_charPos is {_charPos}");
|
||||
// Debug code why is not working?
|
||||
if (_charBuffer == null)
|
||||
Global.mFileSystemDebugger.SendInternal("_charBuffer is NULL!");
|
||||
else if (_charBuffer.Length == 0)
|
||||
Global.mFileSystemDebugger.SendInternal("_charBuffer is Empty!");
|
||||
/* First 4 chars should be '0', '1', '2' and '3' */
|
||||
else
|
||||
if (_stream == null)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal("Printing first 4 chars of _charBuffer: ");
|
||||
Global.mFileSystemDebugger.SendInternal(_charBuffer[0]);
|
||||
Global.mFileSystemDebugger.SendInternal(_charBuffer[1]);
|
||||
Global.mFileSystemDebugger.SendInternal(_charBuffer[2]);
|
||||
Global.mFileSystemDebugger.SendInternal(_charBuffer[3]);
|
||||
throw new ObjectDisposedException(null, "Object already disposed");
|
||||
}
|
||||
if (_charPos == 0 && !flushStream && !flushEncoder)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_charBuffer == null)
|
||||
return;
|
||||
if (_charBuffer.Length == 0)
|
||||
return;
|
||||
|
||||
#if false
|
||||
Global.mFileSystemDebugger.SendInternal($"StreamWriter.Flush() with _charPos {_charPos} and _charBuffer{new String(_charBuffer)}");
|
||||
int numBytes = FileEncoding.GetBytes(_charBuffer, 0, _charPos, _byteBuffer, 0);
|
||||
_charPos = 0;
|
||||
|
||||
FileEncoding.GetBytes(new string(_charBuffer));
|
||||
_stream.Write(_byteBuffer, 0, _byteBuffer.Length);
|
||||
_stream.Flush();
|
||||
#endif
|
||||
throw new NotImplementedException("Flush()");
|
||||
if (numBytes > 0)
|
||||
{
|
||||
Global.mFileSystemDebugger.SendInternal($"numBytes is {numBytes} doing Write...");
|
||||
_stream.Write(_byteBuffer, 0, numBytes);
|
||||
Global.mFileSystemDebugger.SendInternal("Write done!");
|
||||
}
|
||||
|
||||
Global.mFileSystemDebugger.SendInternal("Flush() ended");
|
||||
|
||||
//_stream.Flush();
|
||||
}
|
||||
|
||||
public static void Cctor()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue