KinoSearch1

 view release on metacpan or  search on metacpan

lib/KinoSearch1/Store/InStream.pm  view on Meta::CPAN


__END__

__XS__

MODULE = KinoSearch1    PACKAGE = KinoSearch1::Store::InStream

=begin comment

    my $instream = KinoSearch1::Store::Instream->new( 
        $filehandle, $offset, $length 
    );

Constructor.  Takes 1-3 arguments, and unlike most classes in the KinoSearch1
suite, the arguments to the constructor are not labeled parameters.

The second argument, an offset, defaults to 0 if not supplied.  Non-zero
offsets get factored in when calling seek and tell.

The last argument, a length, is the length of the "file" in bytes.  Supplying
an explicit value is only essential for InStreams which are assigned to read a
portion of a compound file -- otherwise, the length gets auto-calculated
correctly.

=end comment
=cut

InStream*
new(class, fh_sv, ...)
    char   *class;
    SV     *fh_sv;
PREINIT:
    double  offset = 0;
    double  len    = -1;
CODE:
    if (items > 2) {
        SV* offset_sv;
        offset_sv = ST(2);
        if (SvOK(offset_sv))
            offset = SvNV(offset_sv);
    }
    if (items > 3) {
        SV *len_sv;
        len_sv = ST(3);
        if (SvOK(len_sv))
            len = SvNV(len_sv);
    }
    RETVAL = Kino1_InStream_new(class, fh_sv, offset, len);
OUTPUT: RETVAL


=for comment
Seek to target plus the object's start offset.

=cut

void
seek(instream, target)
    InStream *instream;
    double    target;
PPCODE:
    instream->seek(instream, target);

=for comment
Return the filehandle's position minus the offset.

=cut

double
tell(instream)
    InStream *instream;
CODE:
    RETVAL = instream->tell(instream);
OUTPUT: RETVAL

=for comment
Return the length of the "file" in bytes, factoring in the offset.

=cut

double
length(instream)
    InStream *instream;
CODE:
    RETVAL = instream->len;
OUTPUT: RETVAL

=begin comment

    @items = $instream->lu_read( TEMPLATE );

Read the items specified by TEMPLATE from the InStream.

=end comment
=cut

SV*
_set_or_get(instream, ...)
    InStream *instream;
ALIAS:
    set_len      = 1
    get_len      = 2
    set_offset   = 3
    get_offset   = 4
    set_fh       = 5
    get_fh       = 6
CODE:
{
    KINO_START_SET_OR_GET_SWITCH

    case 1:  instream->len = SvNV( ST(1) );
             /* fall through */
    case 2:  RETVAL = newSVnv(instream->len);
             break;
    
    case 3:  instream->offset = SvNV( ST(1) );
             /* fall through */
    case 4:  RETVAL = newSVnv(instream->offset);
             break;
    
    case 5:  Kino1_confess("Can't set_fh");
             /* fall through */
    case 6:  RETVAL = newSVsv(instream->fh_sv);
             break;

    KINO_END_SET_OR_GET_SWITCH
}
OUTPUT: RETVAL


void
lu_read (instream, template_sv)
    InStream *instream;
    SV       *template_sv
PREINIT:
    STRLEN    tpt_len;      /* bytelength of template */
    char     *template;     /* ptr to a spot in the template */
    char     *tpt_end;      /* ptr to the end of the template */
    int       repeat_count; /* number of times to repeat sym */
    char      sym;          /* the current symbol in the template */
    char      countsym;     /* used when calculating repeat counts */
    IV        aIV;
    SV       *aSV;
    char      aChar;
    char*     string;
    STRLEN    len;
PPCODE:
{
    /* prepare template string pointers */
    template    = SvPV(template_sv, tpt_len);
    tpt_end     = SvEND(template_sv);

    repeat_count = 0;
    while (1) {
        if (repeat_count == 0) {
            /* fast-forward past space characters */
            while (*template == ' ' && template < tpt_end) {
                template++;
            }

            /* break out of the loop if we've exhausted the template */
            if (template == tpt_end) {
                break;
            }
            
            /* derive the current symbol and a possible digit repeat sym */
            sym      = *template++;
            countsym = *template;

            if (template == tpt_end) { 
                /* sym is last char in template, so process once */
                repeat_count = 1;
            }
            else if (countsym >= '0' && countsym <= '9') {
                /* calculate numerical repeat count */
                repeat_count = countsym - KINO_NUM_CHAR_OFFSET;
                countsym = *(++template);
                while (  template <= tpt_end 
                      && countsym >= '0' 
                      && countsym <= '9'
                ) {
                    repeat_count = (repeat_count * 10) 
                        + (countsym - KINO_NUM_CHAR_OFFSET);
                    countsym = *(++template);
                }
            }
            else { /* no numeric repeat count, so process sym only once */
                repeat_count = 1;
            }
        }

        /* thwart potential infinite loop */
        if (repeat_count < 1)
            Kino1_confess( "invalid repeat_count: %d", repeat_count);
        
        switch(sym) {

        case 'a': /* arbitrary binary data */
            len = repeat_count;
            repeat_count = 1;
            aSV = newSV(len + 1);
            SvCUR_set(aSV, len);
            SvPOK_on(aSV);
            string = SvPVX(aSV);
            instream->read_bytes(instream, string, len);
            break;

        case 'b': /* signed byte */
        case 'B': /* unsigned byte */
            aChar = instream->read_byte(instream);
            if (sym == 'b') 
                aIV = (signed char)aChar;
            else
                aIV = (unsigned char)aChar;
            aSV = newSViv(aIV);
            break;

        case 'i': /* signed 32-bit integer */
            aSV = newSViv( (I32)instream->read_int(instream) );
            break;
            
        case 'I': /* unsigned 32-bit integer */
            aSV = newSVuv( instream->read_int(instream) );
            break;

        case 'Q': /* unsigned "64-bit integer" */
            aSV = newSVnv( instream->read_long(instream) );
            break;

        case 'T': /* string */
            len = instream->read_vint(instream);
            aSV = newSV(len + 1);
            SvCUR_set(aSV, len);
            SvPOK_on(aSV);
            string = SvPVX(aSV);
            instream->read_chars(instream, string, 0, len);
            break;

        case 'V': /* VInt */
            aSV = newSVuv( instream->read_vint(instream) );
            break;

        case 'W': /* VLong */
            aSV = newSVnv( instream->read_vlong(instream) );
            break;

        default: 
            aSV = NULL; /* suppress unused var compiler warning */
            Kino1_confess("Invalid type in template: '%c'", sym);
        }

        /* Put a scalar on the stack, use up one symbol or repeater */
        XPUSHs( sv_2mortal(aSV) );
        repeat_count -= 1;
    }
}

void
DESTROY(instream)
    InStream *instream;
PPCODE:
    Kino1_InStream_destroy(instream);

__H__


#ifndef H_KINOSEARCH_STORE_INSTREAM
#define H_KINOSEARCH_STORE_INSTREAM 1

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "KinoSearch1UtilCarp.h"
#include "KinoSearch1UtilMathUtils.h"

/* Detect whether we're on an ASCII or EBCDIC machine. */
#if '0' == 240
#define KINO_NUM_CHAR_OFFSET 240
#else
#define KINO_NUM_CHAR_OFFSET 48
#endif

#define KINO_IO_STREAM_BUF_SIZE 1024

typedef struct instream {
    PerlIO  *fh;
    SV      *fh_sv;
    double   offset;
    double   len;
    char    *buf;          
    Off_t    buf_start;    /* file position of start of buffer */
    int      buf_len;      /* number of valid bytes in the buffer */
    int      buf_pos;      /* next byte to read */
    void   (*seek)(struct instream*, double);
    double (*tell)(struct instream*);
    char   (*read_byte)(struct instream*);
    void   (*read_bytes)(struct instream*, char*, STRLEN);
    void   (*read_chars)(struct instream*, char*, STRLEN, STRLEN);
    U32    (*read_int)(struct instream*);
    double (*read_long)(struct instream*);
    U32    (*read_vint)(struct instream*);
    double (*read_vlong)(struct instream*);
} InStream;

InStream* Kino1_InStream_new     (char*, SV*, double, double);
void   Kino1_InStream_seek       (InStream*, double);
double Kino1_InStream_tell       (InStream*);
void   Kino1_InStream_refill     (InStream*);
char   Kino1_InStream_read_byte  (InStream*);
void   Kino1_InStream_read_bytes (InStream*, char*, STRLEN);
void   Kino1_InStream_read_chars (InStream*, char*, STRLEN, STRLEN);
U32    Kino1_InStream_read_int   (InStream*);
double Kino1_InStream_read_long  (InStream*);
U32    Kino1_InStream_decode_vint(char**);
U32    Kino1_InStream_read_vint  (InStream*);
double Kino1_InStream_read_vlong (InStream*);
void   Kino1_InStream_destroy    (InStream*);

#endif /* include guard */

__C__



( run in 0.462 second using v1.01-cache-2.11-cpan-5511b514fd6 )