/*
* Licensed under the MIT License
*
* Copyright (c) 2008 tera
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package org.libspark.utils
{
import flash.errors.IllegalOperationError;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.ProgressEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.IDataInput;
/**
* 一行分がバッファに貯まったら送信されます。
*/
[Event(name="progress", type="ProgressEvent.PROGRESS")]
/**
* LineReader クラスは、 IDataInput インターフェースを実装するクラスに対して、一行ごとにデータを読み込む機能を提供します。
* 一行読み込むたびにProgressEvent.PROGRESSを発生させます。
*
*/
public class LineReader extends EventDispatcher {
/**
* 新しい LineReader クラスのインスタンスを生成します。
*
* 引数で渡される dataInput オブジェクトは、 IEventDispatcher を実装し、
* flash.events.ProgressEvent.SOCKET_DATA または flash.events.ProgressEvent.PROGRESS イベントを発生させるクラス
* ( flash.net.Socket , flash.net.URLStream , flash.filesystem.FileStream )である必要があります。
* ロード完了時なでではProgressEvent.PROGRESSを発生させないので、
* 最後の一行を得るには読み込みが完了した段階でLineReaderオブジェクトのbufferプロパティを直接取得する必要があります。
*
* @param dataInput 処理対象となる IDataInput インターフェースの実装クラス
*/
public function LineReader(dataInput:IDataInput)
{
var dataInputDispatcher:IEventDispatcher = dataInput as IEventDispatcher;
if (!dataInputDispatcher) {
throw new IllegalOperationError("dataInput must implements IEventDispatcher");
}
dataInputDispatcher.addEventListener((dataInput is Socket) ? ProgressEvent.SOCKET_DATA : ProgressEvent.PROGRESS, progressHandler, false, 0, true);
}
// 改行コード:キャリッジリターン
private static const CARRIAGE_RETURN:int = 0x0D;
// 改行コード:ラインフィード
private static const LINE_FEED:int = 0x0A;
// 次バイトで検出したLFをスキップするか
private var _skipNextLineFeed:Boolean = false;
// 読み取りバッファ
private var _buffer:ByteArray = new ByteArray();
// 改行コードをバッファに保存するか
private var _trimLineFeed:Boolean = true;
// 空行をスキップするか
private var _skipBlankLine:Boolean = false;
/**
* 現在のバッファ内容を返します。
*
* @return 現在読み込んでいるバッファ内容
*/
public function get buffer():ByteArray {
return _buffer;
}
/**
* 改行コードをバッファに保存するかを設定します。
*
* @param flag 現在の設定
*/
public function set trimLineFeed(flag:Boolean):void {
_trimLineFeed = flag;
}
/**
* 改行コードをバッファに保存するかを返します。
*
* @return 現在の設定
*/
public function get trimLineFeed():Boolean {
return _trimLineFeed;
}
/**
* 空行をスキップするかを設定します。
*
* @param flag 現在の設定
*/
public function set skipBlankLine(flag:Boolean):void {
_skipBlankLine = flag;
}
/**
* 空行をスキップするかを返します。
*
* @return 現在の設定
*/
public function get skipBlankLine():Boolean {
return _skipBlankLine;
}
/**
* ProgressEvent.PROGRESS または ProgressEvent.SOCKET_DATA イベントを受け取り、一行ごとにバッファに格納します。
*
* @param e ProgressEvent.PROGRESS または ProgressEvent.SOCKET_DATA イベント
* @eventType ProgressEvent.PROGRESS
* @private
*/
private function progressHandler(e:ProgressEvent):void
{
// バッファにリード
var dataInput:IDataInput = e.target as IDataInput;
var byte:int;
while (dataInput.bytesAvailable) {
// 1バイトずつ読み込む
byte = dataInput.readByte();
if (_skipNextLineFeed) {
_skipNextLineFeed = false;
if (byte == LINE_FEED) {
if (!_trimLineFeed) {
_buffer.writeByte(byte);
if (!_skipBlankLine || _buffer.length > 2) {
dispatchEvent(new ProgressEvent( ProgressEvent.PROGRESS, false, false, e.bytesLoaded-dataInput.bytesAvailable, e.bytesTotal));
}
} else {
if (!_skipBlankLine || _buffer.length > 1) {
dispatchEvent(new ProgressEvent( ProgressEvent.PROGRESS, false, false, e.bytesLoaded-dataInput.bytesAvailable, e.bytesTotal));
}
}
_buffer = new ByteArray();
continue;
} else {
if (!_skipBlankLine || _buffer.length > 1) {
dispatchEvent(new ProgressEvent( ProgressEvent.PROGRESS, false, false, e.bytesLoaded-dataInput.bytesAvailable-1, e.bytesTotal));
}
_buffer = new ByteArray();
}
} else if (byte == LINE_FEED) {
if (!_trimLineFeed) {
_buffer.writeByte(byte);
}
if (!_skipBlankLine || _buffer.length > 1) {
dispatchEvent(new ProgressEvent( ProgressEvent.PROGRESS, false, false, e.bytesLoaded-dataInput.bytesAvailable, e.bytesTotal));
}
_buffer = new ByteArray();
continue;
} else if (byte == CARRIAGE_RETURN) {
if (!_trimLineFeed) {
_buffer.writeByte(byte);
}
_skipNextLineFeed = true;
continue;
}
_buffer.writeByte(byte);
}
}
}
}