too much things to enumerate...

This commit is contained in:
Andre Leiradella 2016-06-14 21:37:09 -03:00
parent c2443374e4
commit 3bbe3424cd
13 changed files with 592 additions and 566 deletions

9
.gitignore vendored
View File

@ -2,6 +2,15 @@
*.exe *.exe
*.dll *.dll
*.so *.so
*.png
*.tmx
*.tsx
*~ *~
rl_version.c rl_version.c
boot_lua.h boot_lua.h
bounce.h
sketch008.h
smile.h
GPATH
GRTAGS
GTAGS

View File

@ -4,7 +4,7 @@ DEFINES=-DOUTSIDE_SPEEX -DRANDOM_PREFIX=speex -DEXPORT= -DFIXED_POINT
#CFLAGS=-O3 --std=c99 -Wall $(INCLUDES) $(DEFINES) -fPIC #CFLAGS=-O3 --std=c99 -Wall $(INCLUDES) $(DEFINES) -fPIC
CFLAGS=-O0 -g --std=c99 -Wall $(INCLUDES) $(DEFINES) -fPIC CFLAGS=-O0 -g --std=c99 -Wall $(INCLUDES) $(DEFINES) -fPIC
OBJS=rl_backgrnd.o rl_base64.o rl_config.o rl_image.o rl_imgdata.o rl_pack.o rl_rand.o rl_resample.o rl_sound.o rl_snddata.o rl_sprite.o rl_version.o rl_xml.o external/resample.o OBJS=rl_backgrnd.o rl_base64.o rl_config.o rl_image.o rl_imgdata.o rl_pack.o rl_rand.o rl_resample.o rl_sound.o rl_snddata.o rl_sprite.o rl_tiled.o rl_version.o rl_xml.o external/resample.o
%.o: %.c %.o: %.c
gcc $(CFLAGS) -c $< -o $@ gcc $(CFLAGS) -c $< -o $@

View File

@ -7,7 +7,8 @@
//#define RL_BACKGRND_STRETCH 1 //#define RL_BACKGRND_STRETCH 1
//#define RL_BACKGRND_EXPAND 2 //#define RL_BACKGRND_EXPAND 2
#define RL_COLOR( r, g, b ) ( ( r * 32 / 256 ) << 11 | ( g * 64 / 256 ) << 5 | ( b * 32 / 256 ) ) #define RL_COLOR( r, g, b ) ( ( ( r ) * 32 / 256 ) << 11 | ( ( g ) * 64 / 256 ) << 5 | ( ( b ) * 32 / 256 ) )
#define RL_COLOR_2( rgb ) RL_COLOR( ( rgb >> 16 ) & 255, ( rgb >> 8 ) & 255, rgb & 255 )
int rl_backgrnd_create( int width, int height, int aspect ); int rl_backgrnd_create( int width, int height, int aspect );
void rl_backgrnd_destroy( void ); void rl_backgrnd_destroy( void );

View File

@ -1,27 +1,27 @@
#include <rl_config.h> #include <rl_config.h>
static const rl_config_t config = static const rl_config_t config =
{ {
RL_VERSION_MAJOR, RL_VERSION_MAJOR,
RL_VERSION_MINOR, RL_VERSION_MINOR,
RL_BACKGRND_MARGIN, RL_BACKGRND_MARGIN,
RL_MAX_SPRITES, RL_MAX_SPRITES,
RL_BG_SAVE_SIZE, RL_BG_SAVE_SIZE,
RL_FRAME_RATE, RL_FRAME_RATE,
RL_SAMPLE_RATE, RL_SAMPLE_RATE,
RL_SAMPLES_PER_FRAME, RL_SAMPLES_PER_FRAME,
RL_RESAMPLER_QUALITY, RL_RESAMPLER_QUALITY,
RL_MAX_VOICES, RL_MAX_VOICES,
RL_OGG_INCREMENT, RL_OGG_INCREMENT,
#ifdef RL_OGG_VORBIS #ifdef RL_OGG_VORBIS
1, 1,
#else #else
0, 0,
#endif #endif
RL_USERDATA_COUNT RL_USERDATA_COUNT
}; };
const rl_config_t* rl_get_config( void ) const rl_config_t* rl_get_config( void )
{ {
return &config; return &config;
} }

View File

@ -10,3 +10,16 @@ static inline uint32_t djb2( const char* str )
return hash; return hash;
} }
static inline uint32_t djb2_length( const char* str, size_t length )
{
const unsigned char* aux = (const unsigned char*)str;
uint32_t hash = 5381;
while ( length-- )
{
hash = ( hash << 5 ) + hash + *aux++;
}
return hash;
}

View File

@ -5,6 +5,7 @@
#include <rl_imgdata.h> #include <rl_imgdata.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
/* /*
An image with RLE-encoded pixels and per-pixel alpha of 0, 25, 50, 75 and 100%. An image with RLE-encoded pixels and per-pixel alpha of 0, 25, 50, 75 and 100%.

View File

@ -1,86 +1,86 @@
#include <rl_resample.h> #include <rl_resample.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#include "external/speex_resampler.h" #include "external/speex_resampler.h"
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if RL_RESAMPLER_QUALITY < SPEEX_RESAMPLER_QUALITY_MIN || RL_RESAMPLER_QUALITY > SPEEX_RESAMPLER_QUALITY_MAX #if RL_RESAMPLER_QUALITY < SPEEX_RESAMPLER_QUALITY_MIN || RL_RESAMPLER_QUALITY > SPEEX_RESAMPLER_QUALITY_MAX
#error Invalid quality value in RL_RESAMPLER_QUALITY #error Invalid quality value in RL_RESAMPLER_QUALITY
#endif #endif
static char passthrough = 0; static char passthrough = 0;
rl_resampler_t* rl_resampler_create( unsigned in_freq ) rl_resampler_t* rl_resampler_create( unsigned in_freq )
{ {
if ( in_freq != RL_SAMPLE_RATE ) if ( in_freq != RL_SAMPLE_RATE )
{ {
return (rl_resampler_t*)speex_resampler_init( 2, in_freq, RL_SAMPLE_RATE, RL_RESAMPLER_QUALITY, NULL ); return (rl_resampler_t*)speex_resampler_init( 2, in_freq, RL_SAMPLE_RATE, RL_RESAMPLER_QUALITY, NULL );
} }
return (rl_resampler_t*)&passthrough; return (rl_resampler_t*)&passthrough;
} }
void rl_resampler_destroy( rl_resampler_t* resampler ) void rl_resampler_destroy( rl_resampler_t* resampler )
{ {
if ( resampler != (rl_resampler_t*)&passthrough ) if ( resampler != (rl_resampler_t*)&passthrough )
{ {
speex_resampler_destroy( (SpeexResamplerState*)resampler ); speex_resampler_destroy( (SpeexResamplerState*)resampler );
} }
} }
size_t rl_resampler_out_samples( rl_resampler_t* resampler, size_t in_samples ) size_t rl_resampler_out_samples( rl_resampler_t* resampler, size_t in_samples )
{ {
if ( resampler != (rl_resampler_t*)&passthrough ) if ( resampler != (rl_resampler_t*)&passthrough )
{ {
SpeexResamplerState* st = (SpeexResamplerState*)resampler; SpeexResamplerState* st = (SpeexResamplerState*)resampler;
spx_uint32_t in_rate, out_rate; spx_uint32_t in_rate, out_rate;
speex_resampler_get_rate( st, &in_rate, &out_rate ); speex_resampler_get_rate( st, &in_rate, &out_rate );
return in_samples * out_rate / in_rate; return in_samples * out_rate / in_rate;
} }
else else
{ {
return in_samples; return in_samples;
} }
} }
size_t rl_resampler_in_samples( rl_resampler_t* resampler, size_t out_samples ) size_t rl_resampler_in_samples( rl_resampler_t* resampler, size_t out_samples )
{ {
if ( resampler != (rl_resampler_t*)&passthrough ) if ( resampler != (rl_resampler_t*)&passthrough )
{ {
SpeexResamplerState* st = (SpeexResamplerState*)resampler; SpeexResamplerState* st = (SpeexResamplerState*)resampler;
spx_uint32_t in_rate, out_rate; spx_uint32_t in_rate, out_rate;
speex_resampler_get_rate( st, &in_rate, &out_rate ); speex_resampler_get_rate( st, &in_rate, &out_rate );
return out_samples * in_rate / out_rate; return out_samples * in_rate / out_rate;
} }
else else
{ {
return out_samples; return out_samples;
} }
} }
size_t rl_resampler_resample( rl_resampler_t* resampler, const int16_t* in_buffer, size_t in_samples, int16_t* out_buffer, size_t out_samples ) size_t rl_resampler_resample( rl_resampler_t* resampler, const int16_t* in_buffer, size_t in_samples, int16_t* out_buffer, size_t out_samples )
{ {
if ( resampler != (rl_resampler_t*)&passthrough ) if ( resampler != (rl_resampler_t*)&passthrough )
{ {
spx_uint32_t in_len = in_samples; spx_uint32_t in_len = in_samples;
spx_uint32_t out_len = out_samples; spx_uint32_t out_len = out_samples;
int error = speex_resampler_process_int( (SpeexResamplerState*)resampler, 0, in_buffer, &in_len, out_buffer, &out_len ); int error = speex_resampler_process_int( (SpeexResamplerState*)resampler, 0, in_buffer, &in_len, out_buffer, &out_len );
return error == RESAMPLER_ERR_SUCCESS ? out_len : 0; return error == RESAMPLER_ERR_SUCCESS ? out_len : 0;
} }
else else
{ {
if ( in_samples > out_samples ) if ( in_samples > out_samples )
{ {
in_samples = out_samples; in_samples = out_samples;
} }
memcpy( out_buffer, in_buffer, in_samples * sizeof( int16_t ) ); memcpy( out_buffer, in_buffer, in_samples * sizeof( int16_t ) );
return in_samples; return in_samples;
} }
} }

View File

@ -1,23 +1,23 @@
#ifndef RL_RESAMPLE_H #ifndef RL_RESAMPLE_H
#define RL_RESAMPLE_H #define RL_RESAMPLE_H
#include <rl_userdata.h> #include <rl_userdata.h>
#include <rl_imgdata.h> #include <rl_imgdata.h>
#include <stdint.h> #include <stdint.h>
typedef void rl_resampler_t; typedef void rl_resampler_t;
/* Creates a resampler. */ /* Creates a resampler. */
rl_resampler_t* rl_resampler_create( unsigned in_freq ); rl_resampler_t* rl_resampler_create( unsigned in_freq );
/* Destroys a resampler. */ /* Destroys a resampler. */
void rl_resampler_destroy( rl_resampler_t* resampler ); void rl_resampler_destroy( rl_resampler_t* resampler );
/* Returns how much samples an output buffer must have to resample an input buffer with this number of samples. */ /* Returns how much samples an output buffer must have to resample an input buffer with this number of samples. */
size_t rl_resampler_out_samples( rl_resampler_t* resampler, size_t in_samples ); size_t rl_resampler_out_samples( rl_resampler_t* resampler, size_t in_samples );
/* Returns how much samples an input buffer must have to fill an output buffer with this number of samples. */ /* Returns how much samples an input buffer must have to fill an output buffer with this number of samples. */
size_t rl_resampler_in_samples( rl_resampler_t* resampler, size_t out_samples ); size_t rl_resampler_in_samples( rl_resampler_t* resampler, size_t out_samples );
/* Resamples the input buffer into the output buffer. */ /* Resamples the input buffer into the output buffer. */
size_t rl_resampler_resample( rl_resampler_t* resampler, const int16_t* in_buffer, size_t in_samples, int16_t* out_buffer, size_t out_samples ); size_t rl_resampler_resample( rl_resampler_t* resampler, const int16_t* in_buffer, size_t in_samples, int16_t* out_buffer, size_t out_samples );
#endif /* RL_RESAMPLE_H */ #endif /* RL_RESAMPLE_H */

View File

@ -1,225 +1,225 @@
#include <rl_snddata.h> #include <rl_snddata.h>
#include <rl_resample.h> #include <rl_resample.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <rl_endian.inl> #include <rl_endian.inl>
typedef struct typedef struct
{ {
/* header */ /* header */
char chunkid[ 4 ]; char chunkid[ 4 ];
uint32_t chunksize; uint32_t chunksize;
char format[ 4 ]; char format[ 4 ];
/* fmt */ /* fmt */
char subchunk1id[ 4 ]; char subchunk1id[ 4 ];
uint32_t subchunk1size; uint32_t subchunk1size;
uint16_t audioformat; uint16_t audioformat;
uint16_t numchannels; uint16_t numchannels;
uint32_t samplerate; uint32_t samplerate;
uint32_t byterate; uint32_t byterate;
uint16_t blockalign; uint16_t blockalign;
uint16_t bitspersample; uint16_t bitspersample;
/* data */ /* data */
char subchunk2id[ 4 ]; char subchunk2id[ 4 ];
uint32_t subchunk2size; uint32_t subchunk2size;
uint8_t data[ 0 ]; uint8_t data[ 0 ];
} }
wave_t; wave_t;
int rl_snddata_create( rl_snddata_t* snddata, const void* data, size_t size ) int rl_snddata_create( rl_snddata_t* snddata, const void* data, size_t size )
{ {
const wave_t* wave = (const wave_t*)data; const wave_t* wave = (const wave_t*)data;
if ( wave->chunkid[ 0 ] != 'R' || wave->chunkid[ 1 ] != 'I' || wave->chunkid[ 2 ] != 'F' || wave->chunkid[ 3 ] != 'F' ) if ( wave->chunkid[ 0 ] != 'R' || wave->chunkid[ 1 ] != 'I' || wave->chunkid[ 2 ] != 'F' || wave->chunkid[ 3 ] != 'F' )
{ {
return -1; return -1;
} }
if ( wave->format[ 0 ] != 'W' || wave->format[ 1 ] != 'A' || wave->format[ 2 ] != 'V' || wave->format[ 3 ] != 'E' ) if ( wave->format[ 0 ] != 'W' || wave->format[ 1 ] != 'A' || wave->format[ 2 ] != 'V' || wave->format[ 3 ] != 'E' )
{ {
return -1; return -1;
} }
if ( wave->subchunk1id[ 0 ] != 'f' || wave->subchunk1id[ 1 ] != 'm' || wave->subchunk1id[ 2 ] != 't' || wave->subchunk1id[ 3 ] != ' ' ) if ( wave->subchunk1id[ 0 ] != 'f' || wave->subchunk1id[ 1 ] != 'm' || wave->subchunk1id[ 2 ] != 't' || wave->subchunk1id[ 3 ] != ' ' )
{ {
return -1; return -1;
} }
if ( wave->subchunk2id[ 0 ] != 'd' || wave->subchunk2id[ 1 ] != 'a' || wave->subchunk2id[ 2 ] != 't' || wave->subchunk2id[ 3 ] != 'a' ) if ( wave->subchunk2id[ 0 ] != 'd' || wave->subchunk2id[ 1 ] != 'a' || wave->subchunk2id[ 2 ] != 't' || wave->subchunk2id[ 3 ] != 'a' )
{ {
return -1; return -1;
} }
snddata->bps = le16( wave->bitspersample ); snddata->bps = le16( wave->bitspersample );
snddata->channels = le16( wave->numchannels ); snddata->channels = le16( wave->numchannels );
snddata->freq = le32( wave->samplerate ); snddata->freq = le32( wave->samplerate );
if ( le16( wave->audioformat ) != 1 ) if ( le16( wave->audioformat ) != 1 )
{ {
return -1; return -1;
} }
if ( snddata->channels != 1 && snddata->channels != 2 ) if ( snddata->channels != 1 && snddata->channels != 2 )
{ {
return -1; return -1;
} }
if ( snddata->bps != 8 && snddata->bps != 16 ) if ( snddata->bps != 8 && snddata->bps != 16 )
{ {
return -1; return -1;
} }
snddata->size = le32( wave->subchunk2size ); snddata->size = le32( wave->subchunk2size );
snddata->samples = malloc( snddata->size ); snddata->samples = malloc( snddata->size );
if ( snddata->samples ) if ( snddata->samples )
{ {
memcpy( (void*)snddata->samples, (void*)wave->data, snddata->size ); memcpy( (void*)snddata->samples, (void*)wave->data, snddata->size );
return 0; return 0;
} }
return -1; return -1;
} }
const int16_t* rl_snddata_encode( size_t* out_samples, const rl_snddata_t* snddata ) const int16_t* rl_snddata_encode( size_t* out_samples, const rl_snddata_t* snddata )
{ {
int16_t* out_buffer; int16_t* out_buffer;
size_t in_samples; size_t in_samples;
if ( snddata->bps == 8 ) if ( snddata->bps == 8 )
{ {
if ( snddata->channels == 1 ) if ( snddata->channels == 1 )
{ {
/* 8 bps, mono. */ /* 8 bps, mono. */
in_samples = snddata->size; in_samples = snddata->size;
*out_samples = in_samples * 2; *out_samples = in_samples * 2;
out_buffer = (int16_t*)malloc( *out_samples * sizeof( int16_t ) ); out_buffer = (int16_t*)malloc( *out_samples * sizeof( int16_t ) );
if ( !out_buffer ) if ( !out_buffer )
{ {
return NULL; return NULL;
} }
int16_t* samples = out_buffer; int16_t* samples = out_buffer;
const uint8_t* begin = (const uint8_t*)snddata->samples; const uint8_t* begin = (const uint8_t*)snddata->samples;
const uint8_t* end = begin + in_samples; const uint8_t* end = begin + in_samples;
while ( begin < end ) while ( begin < end )
{ {
int sample = *begin++; int sample = *begin++;
sample = sample * 65792 / 256 - 32768; sample = sample * 65792 / 256 - 32768;
*samples++ = sample; *samples++ = sample;
*samples++ = sample; *samples++ = sample;
} }
} }
else else
{ {
/* 8 bps, stereo. */ /* 8 bps, stereo. */
in_samples = snddata->size; in_samples = snddata->size;
*out_samples = in_samples; *out_samples = in_samples;
out_buffer = (int16_t*)malloc( *out_samples * sizeof( int16_t ) ); out_buffer = (int16_t*)malloc( *out_samples * sizeof( int16_t ) );
if ( !out_buffer ) if ( !out_buffer )
{ {
return NULL; return NULL;
} }
int16_t* samples = out_buffer; int16_t* samples = out_buffer;
const uint8_t* begin = (const uint8_t*)snddata->samples; const uint8_t* begin = (const uint8_t*)snddata->samples;
const uint8_t* end = begin + in_samples; const uint8_t* end = begin + in_samples;
while ( begin < end ) while ( begin < end )
{ {
int sample = *begin++; int sample = *begin++;
sample = sample * 65792 / 256 - 32768; sample = sample * 65792 / 256 - 32768;
*samples++ = sample; *samples++ = sample;
} }
} }
} }
else else
{ {
if ( snddata->channels == 1 ) if ( snddata->channels == 1 )
{ {
/* 16 bps, mono. */ /* 16 bps, mono. */
in_samples = snddata->size / 2; in_samples = snddata->size / 2;
*out_samples = in_samples * 2; *out_samples = in_samples * 2;
out_buffer = (int16_t*)malloc( *out_samples * sizeof( int16_t ) ); out_buffer = (int16_t*)malloc( *out_samples * sizeof( int16_t ) );
if ( !out_buffer ) if ( !out_buffer )
{ {
return NULL; return NULL;
} }
int16_t* samples = out_buffer; int16_t* samples = out_buffer;
const uint16_t* begin = (const uint16_t*)snddata->samples; const uint16_t* begin = (const uint16_t*)snddata->samples;
const uint16_t* end = begin + in_samples; const uint16_t* end = begin + in_samples;
while ( begin < end ) while ( begin < end )
{ {
int16_t sample = le16( *begin++ ); int16_t sample = le16( *begin++ );
*samples++ = sample; *samples++ = sample;
*samples++ = sample; *samples++ = sample;
} }
} }
else else
{ {
/* 16 bps, stereo. */ /* 16 bps, stereo. */
in_samples = snddata->size / 2; in_samples = snddata->size / 2;
*out_samples = in_samples; *out_samples = in_samples;
out_buffer = (int16_t*)malloc( *out_samples * sizeof( int16_t ) ); out_buffer = (int16_t*)malloc( *out_samples * sizeof( int16_t ) );
if ( !out_buffer ) if ( !out_buffer )
{ {
return NULL; return NULL;
} }
int16_t* samples = out_buffer; int16_t* samples = out_buffer;
const uint16_t* begin = (const uint16_t*)snddata->samples; const uint16_t* begin = (const uint16_t*)snddata->samples;
const uint16_t* end = begin + in_samples; const uint16_t* end = begin + in_samples;
while ( begin < end ) while ( begin < end )
{ {
*samples++ = le16( *begin++ ); *samples++ = le16( *begin++ );
} }
} }
} }
if ( snddata->freq != RL_SAMPLE_RATE ) if ( snddata->freq != RL_SAMPLE_RATE )
{ {
rl_resampler_t* resampler = rl_resampler_create( snddata->freq ); rl_resampler_t* resampler = rl_resampler_create( snddata->freq );
if ( !resampler ) if ( !resampler )
{ {
free( out_buffer ); free( out_buffer );
return NULL; return NULL;
} }
size_t new_samples = rl_resampler_out_samples( resampler, *out_samples ); size_t new_samples = rl_resampler_out_samples( resampler, *out_samples );
int16_t* new_buffer = (int16_t*)malloc( new_samples * sizeof( int16_t ) ); int16_t* new_buffer = (int16_t*)malloc( new_samples * sizeof( int16_t ) );
if ( !new_buffer ) if ( !new_buffer )
{ {
rl_resampler_destroy( resampler ); rl_resampler_destroy( resampler );
free( out_buffer ); free( out_buffer );
return NULL; return NULL;
} }
if ( rl_resampler_resample( resampler, out_buffer, *out_samples, new_buffer, new_samples ) != new_samples ) if ( rl_resampler_resample( resampler, out_buffer, *out_samples, new_buffer, new_samples ) != new_samples )
{ {
free( new_buffer ); free( new_buffer );
rl_resampler_destroy( resampler ); rl_resampler_destroy( resampler );
free( out_buffer ); free( out_buffer );
return NULL; return NULL;
} }
free( out_buffer ); free( out_buffer );
out_buffer = new_buffer; out_buffer = new_buffer;
*out_samples = new_samples; *out_samples = new_samples;
} }
return out_buffer; return out_buffer;
} }

View File

@ -1,27 +1,28 @@
#ifndef RL_SNDDATA_H #ifndef RL_SNDDATA_H
#define RL_SNDDATA_H #define RL_SNDDATA_H
#include <rl_userdata.h> #include <rl_userdata.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
typedef struct
{ typedef struct
rl_userdata_t ud; {
rl_userdata_t ud;
int bps; /* bits per sample */
int channels; /* number of channels */ int bps; /* bits per sample */
int freq; /* frequency */ int channels; /* number of channels */
int freq; /* frequency */
size_t size;
const void* samples; size_t size;
} const void* samples;
rl_snddata_t; }
rl_snddata_t;
int rl_snddata_create( rl_snddata_t* snddata, const void* data, size_t size );
#define rl_snddata_destroy( snddata ) do { free( (void*)( snddata )->samples ); } while ( 0 ) int rl_snddata_create( rl_snddata_t* snddata, const void* data, size_t size );
#define rl_snddata_destroy( snddata ) do { free( (void*)( snddata )->samples ); } while ( 0 )
const int16_t* rl_snddata_encode( size_t* out_samples, const rl_snddata_t* snddata );
const int16_t* rl_snddata_encode( size_t* out_samples, const rl_snddata_t* snddata );
#endif /* RL_SNDDATA_H */
#endif /* RL_SNDDATA_H */

View File

@ -6,6 +6,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
/* Reasons passed to the stop callback. */ /* Reasons passed to the stop callback. */
#define RL_SOUND_FINISHED 0 #define RL_SOUND_FINISHED 0

View File

@ -1,152 +1,152 @@
#include <rl_xml.h> #include <rl_xml.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
static inline void skip_to_tag( const char** xml ) static inline void skip_to_tag( const char** xml )
{ {
const char* aux = *xml; const char* aux = *xml;
while ( *aux != '<' && *aux ) while ( *aux != '<' && *aux )
{ {
aux++; aux++;
} }
*xml = aux; *xml = aux;
} }
static inline void skip_name( const char** xml ) static inline void skip_name( const char** xml )
{ {
const char* aux = *xml; const char* aux = *xml;
while ( !isspace( *aux ) && *aux != '>' && *aux != '=' && *aux ) while ( !isspace( *aux ) && *aux != '>' && *aux != '=' && *aux )
{ {
aux++; aux++;
} }
*xml = aux; *xml = aux;
} }
static inline void skip_spaces( const char** xml ) static inline void skip_spaces( const char** xml )
{ {
const char* aux = *xml; const char* aux = *xml;
while ( isspace( *aux ) ) while ( isspace( *aux ) )
{ {
aux++; aux++;
} }
*xml = aux; *xml = aux;
} }
#define CHECK( stmt ) do { int res = stmt; if ( res ) return res; } while ( 0 ) #define CHECK( stmt ) do { int res = stmt; if ( res ) return res; } while ( 0 )
static int parse( const char* xml, const char* end, rl_xmlhandlers_t* handlers ) static int parse( const char* xml, const char* end, rl_xmlhandlers_t* handlers )
{ {
CHECK( handlers->start_document( handlers ) ); CHECK( handlers->start_document( handlers ) );
do do
{ {
const char* text = xml; const char* text = xml;
skip_to_tag( &xml ); skip_to_tag( &xml );
if ( xml != text ) if ( xml != text )
{ {
CHECK( handlers->characters( handlers, text, xml - text ) ); CHECK( handlers->characters( handlers, text, xml - text ) );
} }
if ( *xml != '<' ) if ( *xml != '<' )
{ {
goto out; goto out;
} }
if ( xml[ 1 ] == '/' ) if ( xml[ 1 ] == '/' )
{ {
const char* name = xml += 2; const char* name = xml += 2;
skip_name( &xml ); skip_name( &xml );
CHECK( handlers->end_element( handlers, name, xml - name ) ); CHECK( handlers->end_element( handlers, name, xml - name ) );
skip_spaces( &xml ); skip_spaces( &xml );
if ( *xml != '>' ) if ( *xml != '>' )
{ {
goto out; goto out;
} }
xml++; xml++;
} }
else if ( xml[ 1 ] == '?' ) else if ( xml[ 1 ] == '?' )
{ {
xml = strstr( xml + 2, "?>" ); xml = strstr( xml + 2, "?>" );
if ( !xml ) if ( !xml )
{ {
goto out; goto out;
} }
xml += 2; xml += 2;
} }
else else
{ {
const char* name = ++xml; const char* name = ++xml;
skip_name( &xml ); skip_name( &xml );
size_t name_length = xml - name; size_t name_length = xml - name;
CHECK( handlers->start_element( handlers, name, name_length ) ); CHECK( handlers->start_element( handlers, name, name_length ) );
skip_spaces( &xml ); skip_spaces( &xml );
while ( *xml != '>' && *xml != '/' ) while ( *xml != '>' && *xml != '/' )
{ {
const char* key = xml; const char* key = xml;
skip_name( &xml ); skip_name( &xml );
size_t key_length = xml - key; size_t key_length = xml - key;
skip_spaces( &xml ); skip_spaces( &xml );
if ( *xml != '=' ) if ( *xml != '=' )
{ {
goto out; goto out;
} }
xml++; xml++;
skip_spaces( &xml ); skip_spaces( &xml );
char quote = *xml++; char quote = *xml++;
const char* value = xml; const char* value = xml;
xml = strchr( xml, quote ); xml = strchr( xml, quote );
if ( !xml ) if ( !xml )
{ {
goto out; goto out;
} }
CHECK( handlers->attribute( handlers, key, key_length, value, xml - value ) ); CHECK( handlers->attribute( handlers, key, key_length, value, xml - value ) );
xml++; xml++;
skip_spaces( &xml ); skip_spaces( &xml );
} }
if ( *xml == '/' ) if ( *xml == '/' )
{ {
CHECK( handlers->end_element( handlers, name, name_length ) ); CHECK( handlers->end_element( handlers, name, name_length ) );
xml++; xml++;
skip_spaces( &xml ); skip_spaces( &xml );
if ( *xml != '>' ) if ( *xml != '>' )
{ {
goto out; goto out;
} }
} }
xml++; xml++;
} }
} }
while ( *xml ); while ( *xml );
out: out:
return handlers->end_document( handlers ); return handlers->end_document( handlers );
} }
int rl_xml_parse( const char* xml, size_t length, rl_xmlhandlers_t* handlers ) int rl_xml_parse( const char* xml, size_t length, rl_xmlhandlers_t* handlers )
{ {
return parse( xml, xml + length, handlers ); return parse( xml, xml + length, handlers );
} }

View File

@ -1,24 +1,24 @@
#ifndef RL_XML_H #ifndef RL_XML_H
#define RL_XML_H #define RL_XML_H
#include <rl_userdata.h> #include <rl_userdata.h>
#include <stddef.h> #include <stddef.h>
typedef struct rl_xmlhandlers_t rl_xmlhandlers_t; typedef struct rl_xmlhandlers_t rl_xmlhandlers_t;
struct rl_xmlhandlers_t struct rl_xmlhandlers_t
{ {
rl_userdata_t ud; rl_userdata_t ud;
int ( *start_document )( rl_xmlhandlers_t* handlers ); int ( *start_document )( rl_xmlhandlers_t* handlers );
int ( *end_document )( rl_xmlhandlers_t* handlers ); int ( *end_document )( rl_xmlhandlers_t* handlers );
int ( *start_element )( rl_xmlhandlers_t* handlers, const char* name, size_t length ); int ( *start_element )( rl_xmlhandlers_t* handlers, const char* name, size_t length );
int ( *end_element )( rl_xmlhandlers_t* handlers, const char* name, size_t length ); int ( *end_element )( rl_xmlhandlers_t* handlers, const char* name, size_t length );
int ( *attribute )( rl_xmlhandlers_t* handlers, const char* key, size_t key_length, const char* value, size_t value_length ); int ( *attribute )( rl_xmlhandlers_t* handlers, const char* key, size_t key_length, const char* value, size_t value_length );
int ( *characters )( rl_xmlhandlers_t* handlers, const char* text, size_t length ); int ( *characters )( rl_xmlhandlers_t* handlers, const char* text, size_t length );
}; };
int rl_xml_parse( const char* xml, size_t length, rl_xmlhandlers_t* handlers ); int rl_xml_parse( const char* xml, size_t length, rl_xmlhandlers_t* handlers );
#endif /* RL_XML_H */ #endif /* RL_XML_H */