2fd88bcf15f7c4ca72a3e6d4b22ec971054db27e
[sdk] / ecere / src / sys / BufferedFile.ec
1 namespace sys;
2
3 import "System"
4
5 public class BufferedFile : File
6 {
7    class_fixed
8    FileOpenMode mode;
9    File handle;
10    uint bufferSize;
11    uint bufferCount;
12    uint bufferPos;
13    uint pos;
14    byte * buffer;
15    bool eof;
16    uint bufferRead;
17    uint fileSize;
18
19    // bufferSize = 65536;
20    property::bufferSize = 512 * 1024;
21    //property::bufferSize = 10 * 1024 * 1024;
22    property::bufferRead = 1 * 1024;
23
24    ~BufferedFile()
25    {
26       delete handle;
27       delete buffer;
28    }
29
30    void CloseInput()
31    {
32       handle.CloseInput();
33    }
34
35    void CloseOutput()
36    {
37       handle.CloseOutput();
38    }
39
40    int Read(byte * buffer, uint size, uint count)
41    {
42       if(handle)
43       {
44          uint totalBytesRead = 0;
45          uint bufferCount = this.bufferCount;
46          uint bufferPos = this.bufferPos;
47          byte * fileBuffer = this.buffer + bufferPos;
48          uint readCount = count;
49
50          readCount *= size;
51
52          while(true)
53          {
54             uint bytesRead = (bufferCount > bufferPos) ? (bufferCount - bufferPos) : 0;
55             if(bytesRead > readCount) bytesRead = readCount;
56             if(bytesRead)
57             {
58                memcpy(buffer + totalBytesRead, fileBuffer, bytesRead);
59                bufferPos += bytesRead;
60                totalBytesRead += bytesRead;
61                readCount -= bytesRead;
62             }
63             if(readCount)
64             {
65                uint read;
66                if(readCount < bufferSize /*&& bufferPos <= bufferCount*/)
67                {
68                   read = Max(readCount, bufferRead);
69                   if(bufferPos > bufferCount)
70                   {
71                      if(bufferPos + readCount - bufferCount > read && (bufferPos + readCount - bufferCount < bufferCount))
72                         read = bufferPos + readCount - bufferCount;
73                      else
74                      {
75                         bufferPos = 0;
76                         bufferCount = 0;
77                      }
78                   }
79                   if(bufferCount + read > bufferSize)
80                   {
81                      bufferPos = 0;
82                      bufferCount = 0;
83                   }
84                }
85                else
86                {
87                   read = bufferSize;
88                   bufferPos = 0;
89                   bufferCount = 0;
90                }
91                handle.Seek(pos + totalBytesRead - bufferPos + bufferCount, start);
92                read = handle.Read(this.buffer + bufferCount, 1, read);
93                fileBuffer = this.buffer + bufferPos;
94                bufferCount += read;
95                if(!read)
96                {
97                   eof = true;
98                   break;
99                }
100             }
101             else
102                break;
103          }
104          this.bufferCount = bufferCount;
105          this.bufferPos = bufferPos;
106          pos += totalBytesRead;
107          return totalBytesRead / size;
108       }
109       return 0;
110    }
111
112    int Write(const byte * buffer, uint size, uint count)
113    {
114       uint result;
115       uint numBytes;
116       uint bytesToBuffer;
117       uint missing;
118       handle.Seek(pos, start);
119       result = handle.Write(buffer, size, count);
120       numBytes = result * size;
121       bytesToBuffer = (bufferSize > bufferPos) ? (bufferSize - bufferPos) : 0;
122       missing = numBytes - bytesToBuffer;
123       pos += numBytes;
124       fileSize = Max(fileSize, pos);
125
126       //bufferCount = 0;
127       //bufferPos = 0;
128
129       if(bytesToBuffer < numBytes && bufferCount >= bufferPos && numBytes < bufferSize && missing < bufferPos)
130       {
131          memcpy(this.buffer, this.buffer + missing, bufferPos - missing);
132          bufferPos -= missing;
133          bufferCount -= missing;
134          bytesToBuffer += missing;
135       }
136
137       if(bytesToBuffer >= numBytes)
138       {
139          bytesToBuffer = numBytes;
140          memcpy(this.buffer + bufferPos, buffer, bytesToBuffer);
141          bufferPos += bytesToBuffer;
142          bufferCount = Max(bufferCount, bufferPos);
143       }
144       else
145       {
146          bytesToBuffer = Min(numBytes, bufferSize);
147          memcpy(this.buffer, buffer + numBytes - bytesToBuffer, bytesToBuffer);
148          bufferPos = bytesToBuffer;
149          bufferCount = bytesToBuffer;
150       }
151       return result;
152    }
153
154    bool Getc(char * ch)
155    {
156       // return Read(ch, 1,1) ? true : false;
157       if(handle)
158       {
159          while(true)
160          {
161             if(bufferCount > bufferPos)
162             {
163                *ch = *(buffer + bufferPos);
164                bufferPos++;
165                pos++;
166                return true;
167             }
168             else
169             {
170                bufferPos = 0;
171                handle.Seek(pos, start);
172                bufferCount = handle.Read(buffer, 1, bufferSize);
173                if(!bufferCount)
174                {
175                   eof = true;
176                   break;
177                }
178             }
179          }
180       }
181       return false;
182    }
183
184    bool Putc(char ch)
185    {
186       int written = Write(&ch, 1, 1);
187       return written != 0;
188    }
189
190    bool Puts(const char * string)
191    {
192       int len = strlen(string);
193       int written = Write(string, 1, len);
194       return written == len;
195    }
196
197    bool Seek(int pos, FileSeekMode mode)
198    {
199       uint newPosition = this.pos;
200       switch(mode)
201       {
202          case start:
203             newPosition = pos;
204             break;
205          case current:
206             newPosition += pos;
207             break;
208          case end:
209          {
210             // Get size of file
211             newPosition = fileSize + pos;
212             break;
213          }
214       }
215       if(this.pos != newPosition)
216       {
217          if(newPosition >= this.pos - bufferPos && newPosition < this.pos + bufferSize)
218          {
219             if(newPosition < this.pos - bufferPos + bufferCount)
220                bufferPos += newPosition - this.pos;
221             else
222             {
223                uint read = newPosition - this.pos - bufferCount;
224                if(read < bufferCount * 2)
225                {
226                   if(read > bufferSize)
227                   {
228                      bufferCount = 0;
229                      bufferPos = 0;
230                   }
231                   else
232                   {
233                      handle.Seek(this.pos - bufferPos + bufferCount, start);
234                      read = handle.Read(this.buffer + bufferCount, 1, read);
235                      bufferPos += newPosition - this.pos;
236                      bufferCount += read;
237                   }
238                }
239                else
240                {
241                   bufferCount = 0;
242                   bufferPos = 0;
243                }
244             }
245          }
246          else
247          {
248             bufferCount = 0;
249             bufferPos = 0;
250          }
251
252          eof = newPosition > fileSize;
253          this.pos = newPosition;
254       }
255       return true;
256    }
257
258    uint Tell()
259    {
260       return pos;
261    }
262
263    bool Eof()
264    {
265       return eof;
266       //handle.Eof();
267       //return false;
268    }
269
270    uint GetSize()
271    {
272       return fileSize;
273    }
274
275    bool Truncate(FileSize size)
276    {
277       uint bytesAhead = size - (pos - bufferPos);
278       handle.Truncate(size);
279       bufferCount = Min(bufferCount, bytesAhead);
280       fileSize = Min(fileSize, size);
281       return true;
282    }
283
284    bool Lock(FileLock type, uint64 start, uint64 length, bool wait)
285    {
286       return handle.Lock(type, start, length, wait);
287    }
288
289    bool Unlock(uint64 start, uint64 length, bool wait)
290    {
291       return handle.Unlock(start, length, wait);
292    }
293
294 public:
295    property File handle
296    {
297       set
298       {
299          if(handle)
300             delete handle;
301          handle = value;
302          bufferCount = 0;
303          bufferPos = 0;
304          pos = 0;
305          if(handle)
306          {
307             incref handle;
308          }
309       }
310       get
311       {
312          return handle;
313       }
314    }
315    property uint bufferSize
316    {
317       set
318       {
319          bufferSize = value;
320          buffer = renew buffer byte[value];
321          if(bufferCount > bufferSize)
322             bufferCount = bufferSize;
323       }
324       get
325       {
326          return bufferSize;
327       }
328    }
329    property uint bufferRead
330    {
331       set
332       {
333          bufferRead = value;
334       }
335       get
336       {
337          return bufferRead;
338       }
339    }
340 };
341
342 public BufferedFile FileOpenBuffered(const char * fileName, FileOpenMode mode)
343 {
344    BufferedFile result = null;
345    //if(mode == read)
346    {
347       BufferedFile f {};
348       if(f)
349       {
350          f.mode = mode;
351          f.pos = 0;
352          if((f.handle = FileOpen(fileName, mode)))
353          {
354             f.handle.buffered = true;
355             f.fileSize = f.handle.GetSize();
356             result = f;
357          }
358          if(!result)
359             delete f;
360       }
361    }
362    return result;
363 }