1 /**
2 Reading files without the D runtime.
3 
4 Copyright: Guillaume Piolat 2015-2016.
5 License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6 */
7 module dplug.core.file;
8 
9 import core.stdc.stdio;
10 
11 import dplug.core.nogc;
12 
13 nothrow:
14 @nogc:
15 
16 /// Replacement for `std.file.read`.
17 /// Returns: File contents, allocated with malloc. `null` on error.
18 /// Note: the result file gets an additional terminal zero after the slice, so that 
19 /// it can be converted to a C string at no cost. 
20 // FUTURE: this should be depreciated in favor of take a char*, this is confusing
21 ubyte[] readFile(const(char)[] fileNameZ)
22 {
23     // assuming that fileNameZ is zero-terminated, since it will in practice be
24     // a static string
25     FILE* file = fopen(assumeZeroTerminated(fileNameZ), "rb".ptr);
26     if (file)
27     {
28         scope(exit) fclose(file);
29 
30         // finds the size of the file
31         fseek(file, 0, SEEK_END);
32         long size = ftell(file);
33         fseek(file, 0, SEEK_SET);
34 
35         // Is this too large to read? 
36         // Refuse to read more than 1gb file (if it happens, it's probably a bug).
37         if (size > 1024*1024*1024)
38             return null;
39 
40         // Read whole file in a mallocated slice
41         ubyte[] fileBytes = mallocSliceNoInit!ubyte(cast(int)size + 1); // room for one additional '\0' byte
42         size_t remaining = cast(size_t)size;
43 
44         ubyte* p = fileBytes.ptr;
45 
46         while (remaining > 0)
47         {
48             size_t bytesRead = fread(p, 1, remaining, file);
49             if (bytesRead == 0)
50             {
51                 freeSlice(fileBytes);
52                 return null;
53             }
54             p += bytesRead;
55             remaining -= bytesRead;
56         }
57 
58         fileBytes[cast(size_t)size] = 0;
59 
60         return fileBytes[0..cast(size_t)size];
61     }
62     else
63         return null;
64 }
65 ubyte[] readFile(const(char)* fileNameZ)
66 {
67     import core.stdc.string: strlen;
68     return readFile(fileNameZ[0..strlen(fileNameZ)]);
69 }
70 
71 
72 /// Replacement for `std.file.write`.
73 /// Returns: `false` on error.
74 bool writeFile(const(char)[] fileNameZ, const(ubyte)[] bytes)
75 {
76     // assuming that fileNameZ is zero-terminated, since it will in practice be
77     // a static string
78     FILE* file = fopen(assumeZeroTerminated(fileNameZ), "wb".ptr);
79     if (file)
80     {
81         scope(exit) fclose(file);
82 
83         size_t n = fwrite(bytes.ptr, 1, bytes.length, file);
84         return n == bytes.length;
85     }
86     else
87         return false;
88 }