1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 
  9 namespace System.IO
 10 {
 11     public class StreamReader : IOBase
 12     {
 13         public StreamReader() : base()stream(null)buffer(-1)buffered(false)eos(false)
 14         {
 15         }
 16         public explicit StreamReader(Stream* stream_) : base()stream(stream_)buffer(-1)buffered(false)eos(false)
 17         {
 18             if (stream != null && stream->Error())
 19             {
 20                 SetErrorId(stream->GetErrorId());
 21             }
 22         }
 23         suppress StreamReader(const StreamReader&);
 24         suppress void operator=(const StreamReader&);
 25         public StreamReader(StreamReader&& that) : base()stream(that.stream)streams(Rvalue(that.streams))buffer(that.buffer)buffered(that.buffered)eos(that.eos)
 26         {
 27             that.stream = null;
 28         }
 29         public default void operator=(StreamReader&&);
 30         public override ~StreamReader()
 31         {
 32             long n = streams.Count();
 33             for (long i = n - 1; i >= 0; --i;)
 34             {
 35                 streams[i].Reset();
 36             }
 37         }
 38         public inline Stream* GetStream()
 39         {
 40             return stream;
 41         }
 42         public void SetStream(Stream* stream_)
 43         {
 44             stream = stream_;
 45             if (stream != null && stream->Error())
 46             {
 47                 SetErrorId(stream->GetErrorId());
 48             }
 49         }
 50         public void Own(Stream* strm)
 51         {
 52             streams.Add(UniquePtr<Stream>(strm));
 53         }
 54         [nodiscard]
 55         public Result<int> Read()
 56         {
 57             auto x = Get(false);
 58             if (x.Error())
 59             {
 60                 return Result<int>(ErrorId(x.GetErrorId()));
 61             }
 62             eos = x.Value() == -1;
 63             return Result<int>(x.Value());
 64         }
 65         [nodiscard]
 66         public Result<int> Peek()
 67         {
 68             auto x = Get(true);
 69             if (x.Error())
 70             {
 71                 return Result<int>(ErrorId(x.GetErrorId()));
 72             }
 73             eos = x.Value() == -1;
 74             return Result<int>(x.Value());
 75         }
 76         [nodiscard]
 77         public Result<string> ReadLine()
 78         {
 79             string result;
 80             auto x = Read();
 81             if (x.Error())
 82             {
 83                 return Result<string>(ErrorId(x.GetErrorId()));
 84             }
 85             bool prevWasCR = false;
 86             while (x.Value() != -1)
 87             {
 88                 if (cast<char>(x.Value()) == '\r')
 89                 {
 90                     if (prevWasCR)
 91                     {
 92                         result.Append('\r');
 93                     }
 94                     prevWasCR = true;
 95                 }
 96                 else if (cast<char>(x.Value()) == '\n')
 97                 {
 98                     return Result<string>(result);
 99                 }
100                 else
101                 {
102                     if (prevWasCR)
103                     {
104                         result.Append('\r');
105                         prevWasCR = false;
106                     }
107                     result.Append(cast<char>(x.Value()));
108                 }
109                 x = Read();
110                 if (x.Error())
111                 {
112                     return Result<string>(ErrorId(x.GetErrorId()));
113                 }
114             }
115             eos = true;
116             if (prevWasCR)
117             {
118                 result.Append('\r');
119             }
120             return Result<string>(result);
121         }
122         [nodiscard]
123         public Result<string> ReadToEnd()
124         {
125             string result;
126             auto x = Read();
127             if (x.Error())
128             {
129                 return Result<string>(ErrorId(x.GetErrorId()));
130             }
131             while (x.Value() != -1)
132             {
133                 result.Append(cast<char>(x.Value()));
134                 x = Read();
135                 if (x.Error())
136                 {
137                     return Result<string>(ErrorId(x.GetErrorId()));
138                 }
139             }
140             eos = true;
141             return Result<string>(result);
142         }
143         public void PutBack(byte b)
144         {
145             buffered = true;
146             buffer = b;
147         }
148         [nodiscard]
149         private Result<int> Get(bool peek)
150         {
151             if (buffered)
152             {
153                 if (!peek)
154                 {
155                     buffered = false;
156                 }
157                 return Result<int>(buffer);
158             }
159             else
160             {
161                 if (stream == null)
162                 {
163                     int errorId = RtmAllocateError("StreamReader.Get: stream is null");
164                     SetErrorId(errorId);
165                     return Result<int>(ErrorId(errorId));
166                 }
167                 auto x = stream->ReadByte();
168                 if (x.Error())
169                 {
170                     SetErrorId(x.GetErrorId());
171                     return Result<int>(ErrorId(x.GetErrorId()));
172                 }
173                 if (peek)
174                 {
175                     buffer = x.Value();
176                     buffered = true;
177                 }
178                 return Result<int>(x.Value());
179             }
180         }
181         public inline bool Buffered() const
182         {
183             return buffered;
184         }
185         public inline bool EndOfStream() const
186         {
187             return eos;
188         }
189         private Stream* stream;
190         private List<UniquePtr<Stream>> streams;
191         private int buffer;
192         private bool buffered;
193         private bool eos;
194     }