filename | src/util.c |
changeset | 1092:7c4ffe27e7b5 |
prev | 1091:186558374345 |
next | 1148:8e75fab17be8 |
author | nkeynes |
date | Mon Feb 15 17:27:14 2010 +1000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Hook up the fake bios boot Use fakebios if invoked with -b, or if there's no boot rom loaded |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Miscellaneous utility functions.
5 *
6 * Copyright (c) 2005 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #define HAVE_EXECINFO_H 1
21 #include <assert.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <signal.h>
27 #include <time.h>
28 #include <zlib.h>
29 #include <glib.h>
30 #include <png.h>
31 #include "dream.h"
32 #include "display.h"
33 #include "dreamcast.h"
34 #include "gui.h"
35 #include "sh4/sh4.h"
37 char *msg_levels[] = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
38 int global_msg_level = EMIT_WARN;
40 static void report_crash( int signo, siginfo_t *info, void *ptr )
41 {
42 char buf[128];
44 fprintf( stderr, "--- Aborting with signal %d ---\n", signo );
45 sh4_crashdump();
46 // Get gdb to print a nice backtrace for us
47 snprintf( buf, 128, "gdb -batch -f --quiet --pid=%d -ex bt", getpid() );
48 system(buf);
50 abort();
51 }
53 void install_crash_handler(void)
54 {
55 struct sigaction sa;
57 sa.sa_sigaction = report_crash;
58 sigemptyset(&sa.sa_mask);
59 sa.sa_flags = SA_RESETHAND|SA_SIGINFO;
60 sigaction( SIGSEGV, &sa, NULL );
61 sigaction( SIGILL, &sa, NULL );
62 sigaction( SIGBUS, &sa, NULL );
63 }
66 void fwrite_string( const char *s, FILE *f )
67 {
68 uint32_t len = 0;
69 if( s == NULL ) {
70 fwrite( &len, sizeof(len), 1, f );
71 } else {
72 len = strlen(s)+1;
73 fwrite( &len, sizeof(len), 1, f );
74 fwrite( s, len, 1, f );
75 }
76 }
78 int fread_string( char *s, int maxlen, FILE *f )
79 {
80 uint32_t len;
81 fread( &len, sizeof(len), 1, f );
82 if( len != 0 ) {
83 fread( s, len > maxlen ? maxlen : len, 1, f );
84 }
85 return len;
86 }
88 int fwrite_gzip( void *p, size_t sz, size_t count, FILE *f )
89 {
90 uLongf size = sz*count;
91 uLongf csize = ((int)(size*1.001))+13;
92 unsigned char *tmp = g_malloc0( csize );
93 int status = compress( tmp, &csize, p, size );
94 assert( status == Z_OK );
95 uint32_t wsize = (uint32_t)csize;
96 fwrite( &wsize, sizeof(wsize), 1, f );
97 int written = fwrite( tmp, csize, 1, f );
98 g_free(tmp);
100 /* Could be finer-grained, but this is enough to know it succeeded/failed */
101 if( written == 1 ) {
102 return count;
103 } else {
104 return 0;
105 }
106 }
108 int fread_gzip( void *p, size_t sz, size_t count, FILE *f )
109 {
110 uLongf size = sz*count;
111 uint32_t csize;
112 unsigned char *tmp;
114 fread( &csize, sizeof(csize), 1, f );
115 assert( csize <= (size*2) );
116 tmp = g_malloc0( csize );
117 fread( tmp, csize, 1, f );
118 int status = uncompress( p, &size, tmp, csize );
119 g_free(tmp);
120 if( status == Z_OK ) {
121 return count;
122 } else {
123 fprintf( stderr, "Error reading compressed data\n" );
124 return 0;
125 }
126 }
128 void fwrite_dump( unsigned char *data, unsigned int length, FILE *f )
129 {
130 unsigned int i, j;
131 for( i =0; i<length; i+=16 ) {
132 fprintf( f, "%08X:", i);
133 for( j=i; j<i+16; j++ ) {
134 if( (j % 4) == 0 )
135 fprintf( f, " " );
136 if( j < length )
137 fprintf( f, " %02X", (unsigned int)(data[j]) );
138 else
139 fprintf( f, " " );
140 }
141 fprintf( f, " " );
142 for( j=i; j<i+16 && j<length; j++ ) {
143 fprintf( f, "%c", isprint(data[j]) ? data[j] : '.' );
144 }
145 fprintf( f, "\n" );
146 }
147 }
149 void fwrite_dump32( unsigned int *data, unsigned int length, FILE *f )
150 {
151 fwrite_dump32v( data, length, 8, f );
152 }
154 void fwrite_dump32v( unsigned int *data, unsigned int length, int wordsPerLine, FILE *f )
155 {
156 unsigned int i, j;
157 for( i =0; i<length>>2; i+=wordsPerLine ) {
158 fprintf( f, "%08X:", i);
159 for( j=i; j<i+wordsPerLine; j++ ) {
160 if( j < length )
161 fprintf( f, " %08X", (unsigned int)(data[j]) );
162 else
163 fprintf( f, " " );
164 }
165 fprintf( f, "\n" );
166 }
167 }
169 gboolean write_png_to_stream( FILE *f, frame_buffer_t buffer )
170 {
171 int coltype, i;
172 png_bytep p;
173 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
174 if (!png_ptr) {
175 return FALSE;
176 }
178 png_infop info_ptr = png_create_info_struct(png_ptr);
179 if (!info_ptr) {
180 png_destroy_write_struct(&png_ptr, NULL);
181 return FALSE;
182 }
184 if( setjmp(png_jmpbuf(png_ptr)) ) {
185 png_destroy_write_struct(&png_ptr, &info_ptr);
186 return FALSE;
187 }
188 png_init_io( png_ptr, f );
189 switch( buffer->colour_format ) {
190 case COLFMT_BGR888:
191 coltype = PNG_COLOR_TYPE_RGB;
192 break;
193 case COLFMT_BGRA8888:
194 coltype = PNG_COLOR_TYPE_RGB_ALPHA;
195 break;
196 case COLFMT_BGR0888:
197 coltype = PNG_COLOR_TYPE_RGB;
198 break;
199 default:
200 coltype = PNG_COLOR_TYPE_RGB;
201 }
202 png_set_IHDR(png_ptr, info_ptr, buffer->width, buffer->height,
203 8, coltype, PNG_INTERLACE_NONE,
204 PNG_COMPRESSION_TYPE_DEFAULT,
205 PNG_FILTER_TYPE_DEFAULT );
206 png_write_info(png_ptr, info_ptr);
207 if( buffer->colour_format == COLFMT_BGR0888 ) {
208 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
209 }
210 png_set_bgr(png_ptr);
211 if( buffer->inverted ) {
212 p = (png_bytep)(buffer->data + (buffer->height*buffer->rowstride) - buffer->rowstride);
213 for(i=0; i<buffer->height; i++ ) {
214 png_write_row(png_ptr, p);
215 p-=buffer->rowstride;
216 }
217 } else {
218 p = (png_bytep)buffer->data;
219 for(i=0; i<buffer->height; i++ ) {
220 png_write_row(png_ptr, p);
221 p+=buffer->rowstride;
222 }
223 }
224 png_write_end(png_ptr, info_ptr);
225 png_destroy_write_struct(&png_ptr, &info_ptr);
226 return TRUE;
227 }
229 frame_buffer_t read_png_from_stream( FILE *f )
230 {
231 png_bytep p;
232 int i;
233 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
234 NULL, NULL, NULL);
235 if (!png_ptr) {
236 return NULL;
237 }
239 png_infop info_ptr = png_create_info_struct(png_ptr);
240 if (!info_ptr) {
241 png_destroy_read_struct(&png_ptr, NULL, NULL);
242 return NULL;
243 }
245 png_infop end_info = png_create_info_struct(png_ptr);
246 if (!end_info) {
247 png_destroy_read_struct(&png_ptr, &info_ptr, NULL );
248 return NULL;
249 }
251 if( setjmp(png_jmpbuf(png_ptr)) ) {
252 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
253 return NULL;
254 }
256 png_init_io(png_ptr, f);
257 png_read_info(png_ptr, info_ptr);
259 png_uint_32 width, height;
260 int bit_depth, color_type, interlace_type,
261 compression_type, filter_method;
262 png_get_IHDR(png_ptr, info_ptr, &width, &height,
263 &bit_depth, &color_type, &interlace_type,
264 &compression_type, &filter_method);
265 assert( interlace_type == PNG_INTERLACE_NONE );
266 int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
267 int channels = png_get_channels(png_ptr, info_ptr);
268 frame_buffer_t buffer = g_malloc( sizeof(struct frame_buffer) + rowbytes*height );
269 buffer->data = (unsigned char *)(buffer+1);
270 buffer->width = width;
271 buffer->height = height;
272 buffer->rowstride = rowbytes;
273 buffer->address = -1;
274 buffer->size = rowbytes*height;
275 buffer->inverted = FALSE;
276 if( channels == 4 ) {
277 buffer->colour_format = COLFMT_BGRA8888;
278 } else if( channels == 3 ) {
279 buffer->colour_format = COLFMT_RGB888;
280 }
282 p = (png_bytep)buffer->data;
283 for( i=0; i<height; i++ ) {
284 png_read_row(png_ptr, p, NULL );
285 p += rowbytes;
286 }
288 png_read_end(png_ptr, end_info);
289 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
290 return buffer;
291 }
293 int get_log_level_from_string( const gchar *str )
294 {
295 switch( tolower(str[0]) ) {
296 case 'd': return EMIT_DEBUG;
297 case 'e': return EMIT_ERR;
298 case 'f': return EMIT_FATAL;
299 case 'i': return EMIT_INFO;
300 case 't': return EMIT_TRACE;
301 case 'w': return EMIT_WARN;
302 default: return -1;
303 }
304 }
306 gboolean set_global_log_level( const gchar *str )
307 {
308 int l = get_log_level_from_string(str);
309 if( l == -1 ) {
310 return FALSE;
311 } else {
312 global_msg_level = l;
313 return TRUE;
314 }
315 }
317 void log_message( void *ptr, int level, const gchar *source, const char *msg, ... )
318 {
319 char buf[20];
320 time_t tm = time(NULL);
321 va_list ap;
323 if( level > global_msg_level ) {
324 return; // ignored
325 }
327 va_start(ap, msg);
328 gchar *text = g_strdup_vprintf( msg, ap );
329 va_end(ap);
331 if( level <= EMIT_ERR ) {
332 if( gui_error_dialog( text ) ) {
333 g_free(text);
334 // If we're running, halt on error to avoid potentially flooding
335 // the user with error messages.
336 if( dreamcast_is_running() ) {
337 dreamcast_stop();
338 }
339 return;
340 }
341 }
344 strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
345 fprintf( stderr, "%s %08X %-5s %s\n", buf, sh4r.pc, msg_levels[level], text );
346 g_free(text);
347 }
.