e39c15fa5975b6103e791cb56b41991016c252b6
[vg.git] / vg_io.h
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
2
3 #ifndef VG_IO_H
4 #define VG_IO_H
5
6 #include "vg.h"
7 #include "vg_stdint.h"
8 #include "vg_platform.h"
9 #include "vg_log.h"
10 #include "vg_mem.h"
11
12
13 typedef struct vg_dir vg_dir;
14 #ifndef _WIN32
15 #include <dirent.h>
16 struct vg_dir{
17 DIR *h;
18 struct dirent *data;
19 u32 index;
20 };
21 #else
22 #include <windows.h>
23 #include <fileapi.h>
24 struct vg_dir{
25 HANDLE h;
26 WIN32_FIND_DATA data;
27 u32 index;
28 };
29 #endif
30
31 enum vg_entry_type{
32 k_vg_entry_type_unknown,
33 k_vg_entry_type_file,
34 k_vg_entry_type_dir
35 };
36
37 static int vg_dir_open( vg_dir *dir, const char *name ){
38 #ifdef _WIN32
39 char q_buf[4096];
40 vg_str q;
41 vg_strnull( &q, q_buf, 4096 );
42 vg_strcat( &q, name );
43 vg_strcat( &q, "/*" );
44 if( !vg_strgood(&q) ) return 0;
45
46 vg_info( "FindFirstFile( '%s' )\n", q.buffer );
47 dir->h = FindFirstFile( q.buffer, &dir->data );
48 if( dir->h == INVALID_HANDLE_VALUE ){
49 if( GetLastError() == ERROR_FILE_NOT_FOUND ){
50 dir->index = 0;
51 return 1;
52 }
53 else return 0;
54 }
55 #else
56 dir->h = opendir( name );
57 if( !dir->h ) return 0;
58 #endif
59 dir->index = 1;
60 return 1;
61 }
62
63 static const char *vg_dir_entry_name( vg_dir *dir ){
64 #ifdef _WIN32
65 return dir->data.cFileName;
66 #else
67 return dir->data->d_name;
68 #endif
69 }
70
71 static int vg_dirskip( vg_dir *dir ){
72 const char *s = vg_dir_entry_name(dir);
73 #ifdef _WIN32
74 if( dir->data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) return 1;
75 #endif
76 if( s[0] == '.' ){
77 if( s[1] == '\0' ) return 1;
78 else if( s[1] == '.' ){
79 if( s[2] == '\0' ) return 1;
80 }
81 }
82 return 0;
83 }
84
85 static int vg_dir_next_entry( vg_dir *dir ){
86 #ifdef _WIN32
87 if( dir->index == 0 ) return 0;
88 if( dir->index > 1 ) {
89 dir->index ++;
90 if( !FindNextFile( dir->h, &dir->data ) ) return 0;
91 }
92 while( vg_dirskip(dir) ){
93 dir->index ++;
94 if( !FindNextFile( dir->h, &dir->data ) ) return 0;
95 }
96 if( dir->index == 1 ) dir->index ++;
97 return 1;
98 #else
99 while( (dir->data = readdir(dir->h)) ){
100 dir->index ++;
101 if( !vg_dirskip(dir) ) break;
102 }
103 if( dir->data ) return 1;
104 else return 0;
105 #endif
106 }
107
108 static enum vg_entry_type vg_dir_entry_type( vg_dir *dir ){
109 #ifdef _WIN32
110 if( dir->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
111 return k_vg_entry_type_dir;
112 return k_vg_entry_type_file; /* sketchy? */
113 #else
114 if( dir->data->d_type == DT_DIR ) return k_vg_entry_type_dir;
115 if( dir->data->d_type == DT_REG ) return k_vg_entry_type_file;
116 #endif
117 return 0;
118 }
119
120 static void vg_dir_close( vg_dir *dir ){
121 #ifdef _WIN32
122 if( dir->index ) FindClose( dir->h );
123 dir->h = INVALID_HANDLE_VALUE;
124 #else
125 closedir( dir->h );
126 dir->h = NULL;
127 dir->data = NULL;
128 #endif
129 dir->index = 0;
130 }
131
132 /*
133 * File I/O
134 */
135
136 #define VG_FILE_IO_CHUNK_SIZE 1024*256
137
138 #ifdef __GNUC__
139 #ifndef __clang__
140 #pragma GCC push_options
141 #pragma GCC optimize ("O3")
142 #pragma GCC diagnostic push
143 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
144 #endif
145 #endif
146
147 static void vg_file_print_invalid( FILE *fp )
148 {
149 if( feof( fp )) {
150 vg_error( "mdl_open: header too short\n" );
151 }
152 else{
153 if( ferror( fp ))
154 vg_error( "mdl_open: %s\n", strerror(errno) );
155 else
156 vg_error( "mdl_open: unkown failure\n" );
157
158 }
159 }
160
161 /* read entire binary file */
162 static void *vg_file_read( void *lin_alloc, const char *path, u32 *size ){
163 FILE *f = fopen( path, "rb" );
164 if( f ){
165 void *buffer = lin_alloc? vg_linear_alloc( lin_alloc, 0 ):
166 NULL;
167 u64 current = 0;
168
169 /* read in chunks */
170 for( u32 i=0; 1; i++ ){
171 if( lin_alloc )
172 buffer = vg_linear_extend( lin_alloc,buffer,VG_FILE_IO_CHUNK_SIZE );
173 else
174 buffer = realloc( buffer, current + VG_FILE_IO_CHUNK_SIZE );
175
176 u64 l = fread( buffer + current, 1, VG_FILE_IO_CHUNK_SIZE, f );
177 current += l;
178
179 if( l != VG_FILE_IO_CHUNK_SIZE ){
180 if( feof( f ) ){
181 break;
182 }
183 else{
184 if( ferror( f ) ){
185 fclose(f);
186 vg_fatal_error( "read error" );
187 }
188 else{
189 fclose(f);
190 vg_fatal_error( "unknown error codition" );
191 }
192 }
193 }
194 }
195
196 if( lin_alloc )
197 buffer = vg_linear_resize( lin_alloc, buffer, vg_align8(current) );
198 else
199 buffer = realloc( buffer, vg_align8(current) );
200
201 fclose( f );
202
203 *size = (u32)current;
204 return buffer;
205 }
206 else{
207 vg_error( "vg_disk_open_read: %s (file: %s)\n", strerror(errno), path );
208 return NULL;
209 }
210 }
211
212 /* read entire file and append a null on the end */
213 static char *vg_file_read_text( void *lin_alloc, const char *path, u32 *sz ){
214 u32 size;
215 char *str = vg_file_read( lin_alloc, path, &size );
216
217 if( !str )
218 return NULL;
219
220 /* include null terminator */
221 if( lin_alloc )
222 str = vg_linear_extend( lin_alloc, str, 1 );
223 else
224 str = realloc( str, size+1 );
225
226 str[ size ] = '\0';
227 *sz = size+1;
228
229 return str;
230 }
231
232
233 static int vg_asset_write( const char *path, void *data, i64 size ){
234 FILE *f = fopen( path, "wb" );
235 if( f ){
236 fwrite( data, size, 1, f );
237 fclose( f );
238 return 1;
239 }
240 else{
241 return 0;
242 }
243 }
244
245 /* TODO: error handling if read fails */
246 static int vg_file_copy( const char *src, const char *dst, void *lin_alloc )
247 {
248 vg_info( "vg_file_copy( %s -> %s )\n", src, dst );
249 u32 size;
250 void *data = vg_file_read( lin_alloc, src, &size );
251 return vg_asset_write( dst, data, size );
252 }
253
254 static const char *vg_path_filename( const char *path )
255 {
256 const char *base = path;
257
258 for( int i=0; i<1024; i++ ){
259 if( path[i] == '\0' ) break;
260 if( path[i] == '/' ){
261 base = path+i+1;
262 }
263 }
264
265 return base;
266 }
267
268 #ifdef __GNUC__
269 #ifndef __clang__
270 #pragma GCC pop_options
271 #pragma GCC diagnostic pop
272 #endif
273 #endif
274
275 #endif /* VG_IO_H */