1 /** 2 Copyright (c) 2018 Clipsey (clipseypone@gmail.com) 3 4 Permission is hereby granted, free of charge, to any person or organization 5 obtaining a copy of the software and accompanying documentation covered by 6 this license (the "Software") to use, reproduce, display, distribute, 7 execute, and transmit the Software, and to prepare derivative works of the 8 Software, and to permit third-parties to whom the Software is furnished to 9 do so, all subject to the following: 10 11 The copyright notices in the Software and this entire statement, including 12 the above license grant, this restriction and the following disclaimer, 13 must be included in all copies of the Software, in whole or in part, and 14 all derivative works of the Software, unless such copies or derivative 15 works are solely in the form of machine-executable object code generated by 16 a source language processor. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 21 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 22 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 23 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 DEALINGS IN THE SOFTWARE. 25 */ 26 module ppc.backend.cfile; 27 import ppc.backend; 28 import ppc.exceptions; 29 30 import core.stdc.stdlib; 31 import core.stdc..string; 32 import core.stdc.stdio; 33 34 // Handling for bit arch 35 // Windows acts like it's 32 bit even if it's 64 bit, ugly hack to make windows work. 36 version(Windows) version = BIT_32; 37 else version(D_X32) version = BIT_32; 38 else version(D_LP64) version = BIT_64; 39 40 /// Seek based of the start of the MemFile 41 /// Alias of SEEK_SET 42 enum SeekStart = SEEK_SET; 43 44 /// Seek based of the current position of the readhead of the MemFile 45 /// Alias of SEEK_CUR 46 enum SeekCurrent = SEEK_CUR; 47 48 /// Seek based of the end of the MemFile backwards. 49 /// Alias of SEEK_END 50 enum SeekEnd = SEEK_END; 51 52 /// Loads a raw file as a MemFile usable by the loaders. 53 MemFile loadFile(string filePath) { 54 import std.file : read; 55 auto data = cast(ubyte[])read(filePath); 56 MemFile file; 57 file.arrayptr = data.ptr; 58 file.readhead = file.arrayptr; 59 file.length = data.length; 60 return file; 61 } 62 63 /// Loads a raw file as a MemFile usable by the loaders. 64 RefMemFile loadFileRef(string filePath) { 65 import std.file : read; 66 auto data = cast(ubyte[])read(filePath); 67 return RefMemFile(data); 68 } 69 70 /// A memfile wrapper to make sure that the garbage collector 100% doesn't remove it. 71 struct RefMemFile { 72 private: 73 ubyte[] data; 74 75 public: 76 /// The MemFile object that the references the internally stored data of this struct. 77 MemFile file; 78 79 /// Creates a new RefMemFile 80 this(ubyte[] data) { 81 this.data = data; 82 file.arrayptr = cast(ubyte*)&this.data; 83 file.readhead = file.arrayptr; 84 file.length = data.length; 85 } 86 } 87 88 /// A C File struct which reads from memory instead of disk. 89 struct MemFile { 90 public: 91 /// Pointer to data 92 ubyte* arrayptr; 93 94 /// Pointer to read head. 95 ubyte* readhead; 96 97 /// Length of data. 98 size_t length; 99 100 this(ubyte* array, size_t length) { 101 this.arrayptr = array; 102 this.readhead = this.arrayptr; 103 this.length = length; 104 } 105 106 /// MemFile implementation of C fseek. 107 static extern (C) int seek(void* fileStream, int64_t offset, int whence) nothrow { 108 MemFile* mf = cast(MemFile*)fileStream; 109 switch (whence) { 110 case SEEK_CUR: 111 mf.readhead += offset; 112 break; 113 case SEEK_SET: 114 mf.readhead = mf.arrayptr + offset; 115 break; 116 case SEEK_END: 117 mf.readhead = mf.arrayptr + mf.length-offset; 118 break; 119 default: 120 return -1; 121 } 122 123 if (mf.readhead < mf.arrayptr) { 124 mf.readhead = mf.arrayptr; 125 return -1; 126 } 127 128 if (mf.readhead > mf.arrayptr + mf.length) { 129 mf.readhead = mf.arrayptr + mf.length; 130 } 131 132 return 0; 133 } 134 135 /// MemFile implementation of C fread. 136 static extern (C) size_t read(void* data, size_t bytes, size_t to_read, void* fileStream) nothrow { 137 MemFile* mf = cast(MemFile*)fileStream; 138 139 size_t len = bytes*to_read; 140 if (mf.readhead + len > mf.arrayptr+mf.length) { 141 len = mf.arrayptr+mf.length-mf.readhead; 142 } 143 memcpy(data, mf.readhead, len); 144 mf.readhead += len; 145 return len; 146 } 147 148 // TODO: Improve the implementation of this. 149 /// MemFile implementation of C fwrite 150 /// Returns 0 if index is out of range 151 static extern (C) size_t write(void* data, size_t bytes, size_t to_write, void* fileStream) { 152 MemFile* mf = cast(MemFile*)fileStream; 153 154 // Create buffer if doesn't exist. 155 if (mf.arrayptr is null) { 156 mf.arrayptr = (new ubyte[1]).ptr; 157 mf.readhead = mf.arrayptr; 158 } 159 160 ubyte[] newArr; 161 size_t len = bytes*to_write; 162 if (mf.readhead + len > mf.arrayptr+mf.length) { 163 164 // Offset from last iteration 165 size_t offset = (cast(size_t)mf.readhead-cast(size_t)mf.arrayptr); 166 167 // Allocation 168 newArr = new ubyte[mf.length+(len)]; 169 170 // Resize/copy operation 171 memoryCopy(mf.arrayptr, newArr.ptr, mf.length); 172 mf.arrayptr = newArr.ptr; 173 mf.readhead = mf.arrayptr+offset; 174 mf.length = newArr.length; 175 176 } 177 memoryCopy(data, mf.readhead, len); 178 mf.readhead += len; 179 return len; 180 } 181 182 /// MemFile implementation of C fclose. 183 static extern (C) int close(void* fileStream) nothrow { 184 return 0; 185 } 186 187 /// MemFile implementation of C ftell. 188 static extern (C) clong tell(void* fileStream) nothrow { 189 MemFile* mf = cast(MemFile*)fileStream; 190 191 // Screw C file handling, make sure that the right type of long is used on each platform... 192 version(BIT_32) { 193 194 // Pray that stuff doesn't break with this cast. 195 return cast(clong)mf.readhead-cast(clong)mf.arrayptr; 196 197 } else version(BIT_64) { 198 199 // How it is intended to work, geez. 200 return mf.readhead-mf.arrayptr; 201 202 } 203 } 204 205 ubyte[] toArray() nothrow { 206 return cast(ubyte[])arrayptr[0..length]; 207 } 208 209 } 210 211 /// C-style memory copy. 212 void memoryCopy(void* input, void* output, size_t length) nothrow { 213 memcpy(output, input, length); 214 }