function ChunkStreamer(config)
	{
		this._handle = null;
		this._finished = false;
		this._completed = false;
		this._halted = false;
		this._input = null;
		this._baseIndex = 0;
		this._partialLine = '';
		this._rowCount = 0;
		this._start = 0;
		this._nextChunk = null;
		this.isFirstChunk = true;
		this._completeResults = {
			data: [],
			errors: [],
			meta: {}
		};
		replaceConfig.call(this, config);

		this.parseChunk = function(chunk, isFakeChunk)
		{
			// First chunk pre-processing
			if (this.isFirstChunk && isFunction(this._config.beforeFirstChunk))
			{
				var modifiedChunk = this._config.beforeFirstChunk(chunk);
				if (modifiedChunk !== undefined)
					chunk = modifiedChunk;
			}
			this.isFirstChunk = false;
			this._halted = false;

			// Rejoin the line we likely just split in two by chunking the file
			var aggregate = this._partialLine + chunk;
			this._partialLine = '';

			var results = this._handle.parse(aggregate, this._baseIndex, !this._finished);

			if (this._handle.paused() || this._handle.aborted()) {
				this._halted = true;
				return;
			}

			var lastIndex = results.meta.cursor;

			if (!this._finished)
			{
				this._partialLine = aggregate.substring(lastIndex - this._baseIndex);
				this._baseIndex = lastIndex;
			}

			if (results && results.data)
				this._rowCount += results.data.length;

			var finishedIncludingPreview = this._finished || (this._config.preview && this._rowCount >= this._config.preview);

			if (IS_PAPA_WORKER)
			{
				global.postMessage({
					results: results,
					workerId: WORKER_ID,
					finished: finishedIncludingPreview
				});
			}
			else if (isFunction(this._config.chunk) && !isFakeChunk)
			{
				this._config.chunk(results, this._handle);
				if (this._handle.paused() || this._handle.aborted()) {
					this._halted = true;
					return;
				}
				results = undefined;
				this._completeResults = undefined;
			}

			if (!this._config.step && !this._config.chunk) {
				this._completeResults.data = this._completeResults.data.concat(results.data);
				this._completeResults.errors = this._completeResults.errors.concat(results.errors);
				this._completeResults.meta = results.meta;
			}

			if (!this._completed && finishedIncludingPreview && isFunction(this._config.complete) && (!results || !results.meta.aborted)) {
				this._config.complete(this._completeResults, this._input);
				this._completed = true;
			}

			if (!finishedIncludingPreview && (!results || !results.meta.paused))
				this._nextChunk();

			return results;
		};

		this._sendError = function(error)
		{
			if (isFunction(this._config.error))
				this._config.error(error);
			else if (IS_PAPA_WORKER && this._config.error)
			{
				global.postMessage({
					workerId: WORKER_ID,
					error: error,
					finished: false
				});
			}
		};

		function replaceConfig(config)
		{
			// Deep-copy the config so we can edit it
			var configCopy = copy(config);
			configCopy.chunkSize = parseInt(configCopy.chunkSize);	// parseInt VERY important so we don't concatenate strings!
			if (!config.step && !config.chunk)
				configCopy.chunkSize = null;  // disable Range header if not streaming; bad values break IIS - see issue #196
			this._handle = new _ParserHandle(configCopy);
			this._handle.streamer = this;
			this._config = configCopy;	// persist the copy to the caller
		}
	}
/** ChunkStreamer is the base prototype for various streamer implementations. */
ChunkStreamer is the base prototype for various streamer implementations.
ChunkStreamer is the base prototype for various streamer implementations .
function ChunkStreamer(config)
	{
		this._handle = null;
		this._finished = false;
		this._completed = false;
		this._halted = false;
		this._input = null;
		this._baseIndex = 0;
		this._partialLine = '';
		this._rowCount = 0;
		this._start = 0;
		this._nextChunk = null;
		this.isFirstChunk = true;
		this._completeResults = {
			data: [],
			errors: [],
			meta: {}
		};
		replaceConfig.call(this, config);
		this.parseChunk = function(chunk, isFakeChunk)
		{
			if (this.isFirstChunk && isFunction(this._config.beforeFirstChunk))
			{
				var modifiedChunk = this._config.beforeFirstChunk(chunk);
				if (modifiedChunk !== undefined)
					chunk = modifiedChunk;
			}
			this.isFirstChunk = false;
			this._halted = false;
			var aggregate = this._partialLine + chunk;
			this._partialLine = '';
			var results = this._handle.parse(aggregate, this._baseIndex, !this._finished);
			if (this._handle.paused() || this._handle.aborted()) {
				this._halted = true;
				return;
			}
			var lastIndex = results.meta.cursor;
			if (!this._finished)
			{
				this._partialLine = aggregate.substring(lastIndex - this._baseIndex);
				this._baseIndex = lastIndex;
			}
			if (results && results.data)
				this._rowCount += results.data.length;
			var finishedIncludingPreview = this._finished || (this._config.preview && this._rowCount >= this._config.preview);
			if (IS_PAPA_WORKER)
			{
				global.postMessage({
					results: results,
					workerId: WORKER_ID,
					finished: finishedIncludingPreview
				});
			}
			else if (isFunction(this._config.chunk) && !isFakeChunk)
			{
				this._config.chunk(results, this._handle);
				if (this._handle.paused() || this._handle.aborted()) {
					this._halted = true;
					return;
				}
				results = undefined;
				this._completeResults = undefined;
			}
			if (!this._config.step && !this._config.chunk) {
				this._completeResults.data = this._completeResults.data.concat(results.data);
				this._completeResults.errors = this._completeResults.errors.concat(results.errors);
				this._completeResults.meta = results.meta;
			}
			if (!this._completed && finishedIncludingPreview && isFunction(this._config.complete) && (!results || !results.meta.aborted)) {
				this._config.complete(this._completeResults, this._input);
				this._completed = true;
			}
			if (!finishedIncludingPreview && (!results || !results.meta.paused))
				this._nextChunk();
			return results;
		};
		this._sendError = function(error)
		{
			if (isFunction(this._config.error))
				this._config.error(error);
			else if (IS_PAPA_WORKER && this._config.error)
			{
				global.postMessage({
					workerId: WORKER_ID,
					error: error,
					finished: false
				});
			}
		};
		function replaceConfig(config)
		{
			var configCopy = copy(config);
			configCopy.chunkSize = parseInt(configCopy.chunkSize);	
			if (!config.step && !config.chunk)
				configCopy.chunkSize = null;  
			this._handle = new _ParserHandle(configCopy);
			this._handle.streamer = this;
			this._config = configCopy;	
		}
	}
function ChunkStreamer ( config ) { this . _handle = null ; this . _finished = false ; this . _completed = false ; this . _halted = false ; this . _input = null ; this . _baseIndex = 0 ; this . _partialLine = '' ; this . _rowCount = 0 ; this . _start = 0 ; this . _nextChunk = null ; this . isFirstChunk = true ; this . _completeResults = { data : [ ] , errors : [ ] , meta : { } } ; replaceConfig . call ( this , config ) ; this . parseChunk = function ( chunk , isFakeChunk ) { if ( this . isFirstChunk && isFunction ( this . _config . beforeFirstChunk ) ) { var modifiedChunk = this . _config . beforeFirstChunk ( chunk ) ; if ( modifiedChunk !== undefined ) chunk = modifiedChunk ; } this . isFirstChunk = false ; this . _halted = false ; var aggregate = this . _partialLine + chunk ; this . _partialLine = '' ; var results = this . _handle . parse ( aggregate , this . _baseIndex , ! this . _finished ) ; if ( this . _handle . paused ( ) || this . _handle . aborted ( ) ) { this . _halted = true ; return ; } var lastIndex = results . meta . cursor ; if ( ! this . _finished ) { this . _partialLine = aggregate . substring ( lastIndex - this . _baseIndex ) ; this . _baseIndex = lastIndex ; } if ( results && results . data ) this . _rowCount += results . data . length ; var finishedIncludingPreview = this . _finished || ( this . _config . preview && this . _rowCount >= this . _config . preview ) ; if ( IS_PAPA_WORKER ) { global . postMessage ( { results : results , workerId : WORKER_ID , finished : finishedIncludingPreview } ) ; } else if ( isFunction ( this . _config . chunk ) && ! isFakeChunk ) { this . _config . chunk ( results , this . _handle ) ; if ( this . _handle . paused ( ) || this . _handle . aborted ( ) ) { this . _halted = true ; return ; } results = undefined ; this . _completeResults = undefined ; } if ( ! this . _config . step && ! this . _config . chunk ) { this . _completeResults . data = this . _completeResults . data . concat ( results . data ) ; this . _completeResults . errors = this . _completeResults . errors . concat ( results . errors ) ; this . _completeResults . meta = results . meta ; } if ( ! this . _completed && finishedIncludingPreview && isFunction ( this . _config . complete ) && ( ! results || ! results . meta . aborted ) ) { this . _config . complete ( this . _completeResults , this . _input ) ; this . _completed = true ; } if ( ! finishedIncludingPreview && ( ! results || ! results . meta . paused ) ) this . _nextChunk ( ) ; return results ; } ; this . _sendError = function ( error ) { if ( isFunction ( this . _config . error ) ) this . _config . error ( error ) ; else if ( IS_PAPA_WORKER && this . _config . error ) { global . postMessage ( { workerId : WORKER_ID , error : error , finished : false } ) ; } } ; function replaceConfig ( config ) { var configCopy = copy ( config ) ; configCopy . chunkSize = parseInt ( configCopy . chunkSize ) ; if ( ! config . step && ! config . chunk ) configCopy . chunkSize = null ; this . _handle = new _ParserHandle ( configCopy ) ; this . _handle . streamer = this ; this . _config = configCopy ; } }
ChunkStreamer is the base prototype for various streamer implementations.
ChunkStreamer is the base prototype for various streamer implementations .
// First chunk pre-processing // Rejoin the line we likely just split in two by chunking the file // Deep-copy the config so we can edit it // parseInt VERY important so we don't concatenate strings! // disable Range header if not streaming; bad values break IIS - see issue #196 // persist the copy to the caller