StreamReader implemented but found bug in IL2CPU plug resolution :-(

This commit is contained in:
fanoI 2017-11-18 11:12:17 +01:00
parent eb0a469315
commit 81234d1cd9
12 changed files with 560 additions and 148 deletions

View file

@ -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;
}
}
}

View file

@ -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);

View file

@ -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");

View file

@ -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);

View file

@ -1,4 +1,4 @@
#define COSMOSDEBUG
//#define COSMOSDEBUG
using System;
using System.Globalization;
using Cosmos.Common;

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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");
}
}
}
}

View file

@ -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
}
}

View file

@ -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:

View file

@ -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

View file

@ -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()
{
}
}
}