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