/* maxlen 0 = read one text line */ I32 Perl_filter_read(pTHX_ int idx, SV *buf_sv, int maxlen) { filter_t funcp; SV *datasv = NULL; if (!PL_rsfp_filters) return -1; if (idx > AvFILLp(PL_rsfp_filters)) { /* Any more filters? */ /* Provide a default input filter to make life easy. */ /* Note that we append to the line. This is handy. */ DEBUG_P(PerlIO_printf(Perl_debug_log, "filter_read %d: from rsfp\n", idx)); if (maxlen) { /* Want a block */ int len ; const int old_len = SvCUR(buf_sv); /* ensure buf_sv is large enough */ SvGROW(buf_sv, (STRLEN)(old_len + maxlen)) ; if ((len = PerlIO_read(PL_rsfp, SvPVX(buf_sv) + old_len, maxlen)) <= 0){ if (PerlIO_error(PL_rsfp)) return -1; /* error */ else return 0 ; /* end of file */ } SvCUR_set(buf_sv, old_len + len) ; } else { /* Want a line */ if (sv_gets(buf_sv, PL_rsfp, SvCUR(buf_sv)) == NULL) { if (PerlIO_error(PL_rsfp)) return -1; /* error */ else return 0 ; /* end of file */ } } return SvCUR(buf_sv); } /* Skip this filter slot if filter has been deleted */ if ( (datasv = FILTER_DATA(idx)) == &PL_sv_undef) { DEBUG_P(PerlIO_printf(Perl_debug_log, "filter_read %d: skipped (filter deleted)\n", idx)); return FILTER_READ(idx+1, buf_sv, maxlen); /* recurse */ } /* Get function pointer hidden within datasv */ funcp = DPTR2FPTR(filter_t, IoANY(datasv)); DEBUG_P(PerlIO_printf(Perl_debug_log, "filter_read %d: via function %p (%s)\n", idx, datasv, SvPV_nolen_const(datasv))); /* Call function. The function is expected to */ /* call "FILTER_READ(idx+1, buf_sv)" first. */ /* Return: <0:error, =0:eof, >0:not eof */ return (*funcp)(aTHX_ idx, buf_sv, maxlen); }
static int fmm_fhmagic(PerlFMM *state, PerlIO *fhandle, char **mime_type) { SV *err; unsigned char *data; int ret = -1; Newz(1234, data, HOWMANY + 1, unsigned char); if (! PerlIO_read(fhandle, data, HOWMANY)) { err = newSVpvf( "Failed to read from handle: %s", strerror(errno) ); FMM_SET_ERROR(state, err); Safefree(data); return -1; } ret = fmm_bufmagic(state, &data, mime_type); Safefree(data); return ret; }
SV * parse_in_chunks(char * filepath, size_t filesize) { char *buf; size_t bytes_read = 0; int max_buf = 1000; char *err_msg; int block = BLOCK_HEADER; int cur_event_type = 0; int event_type = 0; char event_block = 0; char *brnl, *breq; AV * data; AV * datawrapper; AV * events; char *line; char * nl = "\n"; char * eq = "="; int rewind_pos = 0; size_t cur_fpos = 0; SV * pbuf; SV * pmax_buf; AV * HANDLERS = get_av("Opsview::Utils::NDOLogsImporter::HANDLERS", 0); AV * INPUT_DATA_TYPE = get_av("Opsview::Utils::NDOLogsImporter::INPUT_DATA_TYPE", 0); int init_last_pos; int init_block; if ( first_read ) { if ( ! ( fh = PerlIO_open( filepath, "rb" ) ) ) { croak("Could not open file: %s\n", strerror(errno)); } bytes_left = filesize; init_last_pos = prev_pos = first_read = 0; init_block = block = BLOCK_HEADER; } else { init_block = block = BLOCK_EVENTS; init_last_pos = prev_pos; } read_begin: brnl = NULL; breq = NULL; pbuf = get_sv("Opsview::Utils::NDOLogsImporter::PARSE_BUF", 0); pmax_buf = get_sv("Opsview::Utils::NDOLogsImporter::MAX_BUF_SIZE", 0); buf = SvPVX(pbuf); max_buf = SvIVX(pmax_buf); if ( max_buf < 1024 * 1024 && ! automated_tests ) { max_buf = 1024*1024; SvIV_set( pmax_buf, max_buf ); SvGROW( pbuf, max_buf + 1); SvCUR_set( pbuf, max_buf); } if ( bytes_left > 0 ) { bytes_read = PerlIO_read(fh, buf + prev_pos, max_buf-prev_pos); cur_fpos = PerlIO_tell(fh); if ( bytes_read < 0 ) { err_msg = strerror(errno); PerlIO_close( fh ); croak("Could not read file: %s\n", err_msg); } bytes_left -= bytes_read; events = (AV *)sv_2mortal((SV *)newAV()); rewind_pos = last_999(buf+prev_pos, bytes_read); prev_pos = bytes_read + prev_pos - rewind_pos; buf[prev_pos] = '\0'; // avg ratio events:file_size = 0.21% if ( prev_pos > 1000 ) { av_extend( events, (int)(prev_pos * 0.0021) ); } for ( line = strtok_r(buf, nl, &brnl); line != NULL; line = strtok_r(NULL, nl, &brnl) ) { switch(block) { case BLOCK_HEADER: { if ( strEQ(line, "STARTDATADUMP") ) { block = BLOCK_EVENTS; } } break; case BLOCK_EVENTS: { if ( strEQ(line, "1000") ) { /* NDO_API_ENDDATADUMP */ block = BLOCK_FOOTER; continue; } cur_event_type = atoi(line); /* ignore events we are not handling */ if ( ! av_exists(HANDLERS, cur_event_type) ) { block = BLOCK_IGNORE_EVENT; continue; } event_block = BLOCK_EVENT_STARTED; if ( cur_event_type != event_type ) { datawrapper = (AV *)sv_2mortal((SV *)newAV()); data = (AV *)sv_2mortal((SV *)newAV()); av_push( events, newSViv( cur_event_type ) ); av_push( datawrapper, newRV( (SV *)data ) ); av_push( events, newRV( (SV *)datawrapper ) ); event_type = cur_event_type; } else { data = (AV *)sv_2mortal((SV *)newAV()); av_push( datawrapper, newRV( (SV *)data ) ); } block = BLOCK_EVENT; } break; case BLOCK_EVENT: { if ( strEQ(line, "999") ) { /* NDO_API_ENDDATA */ block = BLOCK_EVENTS; event_block = BLOCK_EVENT_ENDED; } else { char *k; char *v; int key; int key_type = 0; int v_len = 0; k = strtok_r(line, eq, &breq); v = strtok_r(NULL, "\0", &breq); key = atoi(k); /* invalid key, skip parsing */ if ( key == 0 ) { goto remove_invalid; } SV ** const k_type = av_fetch(INPUT_DATA_TYPE, key, 0 ); if ( k_type ) { key_type = SvIVx( *k_type ); } if ( v ) { if ( key_type & 1 ) { v_len = ndo_unescape_buffer( v ); } else { v_len = strlen(v); } } if ( key_type & 2 ) { AV * datanstptr; SV ** const datanst = av_fetch(data, key, 0 ); if ( datanst ) { datanstptr = (AV *)SvRV( *datanst ); } else { datanstptr = (AV *)sv_2mortal((SV *)newAV()); av_store( data, key, newRV( (SV *)datanstptr ) ); } if ( v ) { av_push( datanstptr, newSVpvn(v, v_len) ); } else { av_push( datanstptr, newSVpvn("", 0) ); } } else { if ( v ) { av_store( data, key, newSVpvn(v, v_len) ); } else { av_store( data, key, newSVpvn("", 0) ); } } } } break; case BLOCK_FOOTER: { if ( strEQ(line, "GOODBYE") ) { block = BLOCK_HEADER; } } break; case BLOCK_IGNORE_EVENT: { if ( strEQ(line, "999") ) { /* NDO_API_ENDDATA */ block = BLOCK_EVENTS; // go back to EVENTS continue; } } break; } }; /* there were some events */ if ( event_block != BLOCK_HEADER ) { if ( event_block != BLOCK_EVENT_ENDED ) { remove_invalid: av_pop( datawrapper ); } /* remove whole block if the last block has no events */ if ( av_len( datawrapper ) == -1 ) { av_pop( events ); av_pop( events ); } } if ( av_len(events) > 0 ) { if ( rewind_pos > 0 && cur_fpos < filesize ) { memmove(buf, buf+prev_pos+1, rewind_pos-1); } prev_pos = rewind_pos - 1; return newRV_inc((SV *) events); } else { if ( cur_fpos < filesize && event_block != BLOCK_HEADER && event_block != BLOCK_EVENT_ENDED ) { int new_max_buf = max_buf * 2; SvIV_set( pmax_buf, new_max_buf ); SvGROW( pbuf, new_max_buf + 1); SvCUR_set( pbuf, new_max_buf); //start again as previous buffer would be tokenized already prev_pos = 0; block = init_block; event_type = 0; PerlIO_close( fh ); if ( ! ( fh = PerlIO_open( filepath, "rb" ) ) ) { croak("Could not re-open file: %s\n", strerror(errno)); } PerlIO_seek(fh, cur_fpos-bytes_read-init_last_pos, SEEK_SET); bytes_left += bytes_read + init_last_pos; goto read_begin; } } } parser_reset_iterator(); return &PL_sv_undef; }
int _check_buf(PerlIO *infile, Buffer *buf, int min_wanted, int max_wanted) { int ret = 1; // Do we have enough data? if ( buffer_len(buf) < min_wanted ) { // Read more data uint32_t read; uint32_t actual_wanted; unsigned char *tmp; #ifdef _MSC_VER uint32_t pos_check = PerlIO_tell(infile); #endif if (min_wanted > max_wanted) { max_wanted = min_wanted; } // Adjust actual amount to read by the amount we already have in the buffer actual_wanted = max_wanted - buffer_len(buf); New(0, tmp, actual_wanted, unsigned char); DEBUG_TRACE("Buffering from file @ %d (min_wanted %d, max_wanted %d, adjusted to %d)\n", (int)PerlIO_tell(infile), min_wanted, max_wanted, actual_wanted ); if ( (read = PerlIO_read(infile, tmp, actual_wanted)) <= 0 ) { if ( PerlIO_error(infile) ) { #ifdef _MSC_VER // Show windows specific error message as Win32 PerlIO_read does not set errno DWORD last_error = GetLastError(); LPWSTR *errmsg = NULL; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, last_error, 0, (LPWSTR)&errmsg, 0, NULL); warn("Error reading: %d %s (read %d wanted %d)\n", last_error, errmsg, read, actual_wanted); LocalFree(errmsg); #else warn("Error reading: %s (wanted %d)\n", strerror(errno), actual_wanted); #endif } else { warn("Error: Unable to read at least %d bytes from file.\n", min_wanted); } ret = 0; goto out; } buffer_append(buf, tmp, read); // Make sure we got enough if ( buffer_len(buf) < min_wanted ) { warn("Error: Unable to read at least %d bytes from file (only read %d).\n", min_wanted, read); ret = 0; goto out; } #ifdef _MSC_VER // Bug 16095, weird off-by-one bug seen only on Win32 and only when reading a filehandle if (PerlIO_tell(infile) != pos_check + read) { //PerlIO_printf(PerlIO_stderr(), "Win32 bug, pos should be %d, but was %d\n", pos_check + read, PerlIO_tell(infile)); PerlIO_seek(infile, pos_check + read, SEEK_SET); } #endif DEBUG_TRACE("Buffered %d bytes, new pos %d\n", read, (int)PerlIO_tell(infile)); out: Safefree(tmp); }