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