getting stuff working on windows again
[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 VG_STATIC void vg_file_print_invalid( FILE *fp )
139 {
140 if( feof( fp )) {
141 vg_error( "mdl_open: header too short\n" );
142 }
143 else{
144 if( ferror( fp ))
145 vg_error( "mdl_open: %s\n", strerror(errno) );
146 else
147 vg_error( "mdl_open: unkown failure\n" );
148
149 }
150 }
151
152 /* read entire binary file */
153 VG_STATIC void *vg_file_read( void *lin_alloc, const char *path, u32 *size )
154 {
155 FILE *f = fopen( path, "rb" );
156 if( f ){
157 void *buffer = vg_linear_alloc( lin_alloc, 0 );
158 u64 current = 0;
159
160 /* read in chunks */
161 for( u32 i=0; 1; i++ ){
162 buffer = vg_linear_extend( lin_alloc, buffer, VG_FILE_IO_CHUNK_SIZE );
163
164 u64 l = fread( buffer + current, 1, VG_FILE_IO_CHUNK_SIZE, f );
165 current += l;
166
167 if( l != VG_FILE_IO_CHUNK_SIZE ){
168 if( feof( f ) ){
169 break;
170 }
171 else{
172 if( ferror( f ) ){
173 fclose(f);
174 vg_fatal_error( "read error" );
175 }
176 else{
177 fclose(f);
178 vg_fatal_error( "unknown error codition" );
179 }
180 }
181 }
182 }
183
184 buffer = vg_linear_resize( lin_alloc, buffer, vg_align8(current) );
185 fclose( f );
186
187 *size = (u32)current;
188 return buffer;
189 }
190 else{
191 vg_error( "vg_disk_open_read: %s\n", strerror(errno) );
192 return NULL;
193 }
194 }
195
196 /* read entire file and append a null on the end */
197 VG_STATIC char *vg_file_read_text( void *lin_alloc, const char *path, u32 *sz )
198 {
199 u32 size;
200 char *str = vg_file_read( lin_alloc, path, &size );
201
202 if( !str )
203 return NULL;
204
205 /* include null terminator */
206 str = vg_linear_extend( lin_alloc, str, 1 );
207 str[ size ] = '\0';
208 *sz = size+1;
209
210 return str;
211 }
212
213
214 VG_STATIC int vg_asset_write( const char *path, void *data, i64 size ){
215 FILE *f = fopen( path, "wb" );
216 if( f ){
217 fwrite( data, size, 1, f );
218 fclose( f );
219 return 1;
220 }
221 else{
222 return 0;
223 }
224 }
225
226 /* TODO: error handling if read fails */
227 VG_STATIC int vg_file_copy( const char *src, const char *dst, void *lin_alloc )
228 {
229 vg_info( "vg_file_copy( %s -> %s )\n", src, dst );
230 u32 size;
231 void *data = vg_file_read( lin_alloc, src, &size );
232 return vg_asset_write( dst, data, size );
233 }
234
235 VG_STATIC const char *vg_path_filename( const char *path )
236 {
237 const char *base = path;
238
239 for( int i=0; i<1024; i++ ){
240 if( path[i] == '\0' ) break;
241 if( path[i] == '/' ){
242 base = path+i+1;
243 }
244 }
245
246 return base;
247 }
248
249 #endif /* VG_IO_H */