replace VG_STATIC -> static
[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 {
164 FILE *f = fopen( path, "rb" );
165 if( f ){
166 void *buffer = vg_linear_alloc( lin_alloc, 0 );
167 u64 current = 0;
168
169 /* read in chunks */
170 for( u32 i=0; 1; i++ ){
171 buffer = vg_linear_extend( lin_alloc, buffer, VG_FILE_IO_CHUNK_SIZE );
172
173 u64 l = fread( buffer + current, 1, VG_FILE_IO_CHUNK_SIZE, f );
174 current += l;
175
176 if( l != VG_FILE_IO_CHUNK_SIZE ){
177 if( feof( f ) ){
178 break;
179 }
180 else{
181 if( ferror( f ) ){
182 fclose(f);
183 vg_fatal_error( "read error" );
184 }
185 else{
186 fclose(f);
187 vg_fatal_error( "unknown error codition" );
188 }
189 }
190 }
191 }
192
193 buffer = vg_linear_resize( lin_alloc, buffer, vg_align8(current) );
194 fclose( f );
195
196 *size = (u32)current;
197 return buffer;
198 }
199 else{
200 vg_error( "vg_disk_open_read: %s\n", strerror(errno) );
201 return NULL;
202 }
203 }
204
205 /* read entire file and append a null on the end */
206 static char *vg_file_read_text( void *lin_alloc, const char *path, u32 *sz )
207 {
208 u32 size;
209 char *str = vg_file_read( lin_alloc, path, &size );
210
211 if( !str )
212 return NULL;
213
214 /* include null terminator */
215 str = vg_linear_extend( lin_alloc, str, 1 );
216 str[ size ] = '\0';
217 *sz = size+1;
218
219 return str;
220 }
221
222
223 static int vg_asset_write( const char *path, void *data, i64 size ){
224 FILE *f = fopen( path, "wb" );
225 if( f ){
226 fwrite( data, size, 1, f );
227 fclose( f );
228 return 1;
229 }
230 else{
231 return 0;
232 }
233 }
234
235 /* TODO: error handling if read fails */
236 static int vg_file_copy( const char *src, const char *dst, void *lin_alloc )
237 {
238 vg_info( "vg_file_copy( %s -> %s )\n", src, dst );
239 u32 size;
240 void *data = vg_file_read( lin_alloc, src, &size );
241 return vg_asset_write( dst, data, size );
242 }
243
244 static const char *vg_path_filename( const char *path )
245 {
246 const char *base = path;
247
248 for( int i=0; i<1024; i++ ){
249 if( path[i] == '\0' ) break;
250 if( path[i] == '/' ){
251 base = path+i+1;
252 }
253 }
254
255 return base;
256 }
257
258 #ifdef __GNUC__
259 #ifndef __clang__
260 #pragma GCC pop_options
261 #pragma GCC diagnostic pop
262 #endif
263 #endif
264
265 #endif /* VG_IO_H */