/* vim: ts=4 sw=4 sts=4 ff=unix fenc=utf-8 : * ===================================================================== * sc_stream.c * Copyright (c) 2003 - 2011 sys0tem * LICENSE : * LGPL (GNU Lesser General Public License - Version 3,29 June 2007) * http://www.gnu.org/copyleft/lesser.html * or * EPL (Eclipse Public License - v1.0) * http://www.eclipse.org/legal/epl-v10.html * ===================================================================== */ #include <sc_os.h> #include <sc_string.h> #include <sc_error.h> #include <sc_mmgr.h> #include <sc_stream.h> /* --------------------------------------------------------------------- * プロトタイプ宣言 * --------------------------------------------------------------------- */ static bool SC_Stream_fullLoad(SC_Stream* strm); /** * ストリームより1文字読み出します。 * ファイルの末尾に達した場合 0 を返します。 * エラーが発生した場合、負の値を返します。 * * @param strm ストリーム * @param c 読み出すバッファ * @return 読み出したサイズ */ int SC_Stream_readc_(SC_Stream* strm, char* c) { int readSize; if (strm->_data.size <= 0) { /* データがない => 読み込む */ readSize =strm->_readCore( strm, strm->_data.buff, strm->_data.buffSize); if (readSize <= 0) { /* 読み込み失敗 or 末尾到達 */ return readSize; } strm->_data.off = 0; strm->_data.size = readSize; } *c = strm->_data.buff[strm->_data.off]; strm->_data.off++; strm->_data.size--; return 1; } /** * ストリームより読み取ります。 * ファイルの末尾に達した場合 0 を返します。 * エラーが発生した場合、負の値を返します。 * * @param strm ストリーム * @param buff バッファ * @param size サイズ * @return 読み取ったバイト数 */ int SC_Stream_read_(SC_Stream* strm, void* buff, size_t size) { int ret; int readSize = 0; int copySize = (int) size; if (strm->_data.size > 0) { /* バッファがある場合、バッファをコピー */ if (copySize > strm->_data.size) { copySize = strm->_data.size; } memcpy(buff, &(strm->_data.buff[strm->_data.off]), copySize); readSize = copySize; strm->_data.off += readSize; strm->_data.size -= readSize; } copySize = size - readSize; if (copySize > 0) { /* 残りを _readCore により取得 */ ret = strm->_readCore(strm, &((char*)buff)[readSize], copySize); if (ret <= 0) { return ret; } readSize += ret; } return readSize; } /** * 指定されたバイトを読み取ります。 * 指定されたバイト数分読み取れたか否かは、 * 戻り値にて確認してください。 * ファイルの末尾に達した場合 0 を返します。 * エラーが発生した場合、負の値を返します。 * * @param strm ストリーム * @param buff バッファ * @param size サイズ * @return 実際に読み取ったバイト数 */ int SC_Stream_readExact_(SC_Stream* strm, void* buff, size_t size) { char* readPtr = (char*) buff; int restSize = size; int readSize; for (;;) { if (restSize == 0) { /* サイズ分読み込んだ */ break; } readSize = strm->read(strm, readPtr, restSize); if (readSize == 0) { /* 終わりまで読み込んだ */ break; } if (readSize < 0) { /* エラー発生 */ return -1; } readPtr += readSize; restSize -= readSize; } return (size - restSize); } /** * ストリームより、1行を読み込みます。 * ストリームの終わりの場合、0 を返します。 * バッファの最後には、'\0' が付与されます。 * 読み取ったサイズに '\0' は含まれません。 * * @param strm ストリーム * @param buff バッファ * @param size バッファサイズ * @return 読み取ったサイズ */ int SC_Stream_readLine_(SC_Stream* strm, char* buff, size_t size) { int i; int ret; char c; char* ptr = buff; for (i = 0; i < ((int) size - 1); i++) { ret = strm->readc(strm, &c); if (ret <= 0) { break; } *ptr = c; ptr++; if (c == '\n') { /* LF */ i++; break; } if (c == '\r') { /* CR */ i++; ret = strm->readc(strm, &c); if (ret <= 0) { break; } if (c == '\n') { /* CRLF */ *ptr = c; ptr++; i++; } else { /* push back */ strm->_data.off--; strm->_data.size++; } break; } } if (ret < 0) { return ret; } *ptr = '\0'; return i; } /** * ストリームより、指定されたデータの直前までのデータを読み込みます。 * ストリームの終わり、指定されたデータの直前に達した場合、0 を返します。 * 指定されたデータのサイズが、バッファサイズより大きい場合失敗します。 * * @param strm ストリーム * @param buff バッファ * @param size サイズ * @param limitData ここで指定されたデータまで読み込む * @param limitSize limitData のサイズ * @return 実際に読み取ったバイト数 */ int SC_Stream_limitedRead_(SC_Stream* strm, char* buff , size_t size, char* limitData, size_t limitSize ) { bool ret; const char* limitDataPtr; int readSize = size; int tmpSize; if (((int) limitSize * 2) > strm->_data.buffSize) { return -1; } /* とりあえず、バッファいっぱいにロードする。 */ ret = SC_Stream_fullLoad(strm); if (!ret) { return -1; } /* limitData を検索 */ limitDataPtr = SC_memindex( strm->_data.buff, strm->_data.size, limitData, limitSize); if (limitDataPtr == NULL) { /* 見つからない => 読み込みサイズを制限する 中途半端な位置で切れてる可能性があるため 読み込み終了位置を制限する */ tmpSize = strm->_data.size - limitSize; if (readSize > tmpSize) { readSize = tmpSize; } } else { /* 見つかった => 最大でも見つかった位置の直前までを返す */ tmpSize = limitDataPtr - strm->_data.buff; if (readSize > tmpSize) { readSize = tmpSize; } } if (readSize > 0) { readSize = strm->read(strm, buff, readSize); } return readSize; } /** * ストリームに1文字書き出します。 * ファイルの末尾に達した場合 0 を返します。 * エラーが発生した場合、負の値を返します。 * * @param strm ストリーム * @param c 書き出す値 * @return true/false (成功/失敗) */ int SC_Stream_writec_(SC_Stream* strm, char c) { int ret; ret = strm->_writeCore(strm, &c, 1); return ret; } /** * ストリームに書き出します。 * ファイルの末尾に達した場合 0 を返します。 * エラーが発生した場合、負の値を返します。 * * @param strm ストリーム * @param buff バッファ * @param size サイズ * @return 書き出したバイト数 */ int SC_Stream_write_(SC_Stream* strm, const void* buff, size_t size) { int ret; ret = strm->_writeCore(strm, buff, size); return ret; } /** * 指定されたバイトを書き込みます。 * ファイルの末尾に達した場合 0 を返します。 * エラーが発生した場合、負の値を返します。 * * @param stram ストリーム * @param buff バッファ * @param size サイズ * @return 書き込んだバイト数 */ int SC_Stream_writeExact_(SC_Stream* strm, const void* buff, size_t size) { const char* writePtr = (const char*) buff; int restSize = (int) size; int writeSize; for (;;) { if (restSize == 0) { /* サイズ分書き込んだ */ break; } writeSize = strm->write(strm, writePtr, restSize); if (writeSize == 0) { /* 0 byte 書き込んだ */ break; } if (writeSize < 0) { /* エラーが発生した */ return -1; } writePtr += writeSize; restSize -= writeSize; } return (size - restSize); } /** * 指定されたストリームを削除します。 * * @param stram ストリーム */ void SC_Stream_delete(SC_Stream* strm) { strm->close(strm); free(strm); } /** * 指定されたストリームのバッファにロードします。 */ static bool SC_Stream_fullLoad(SC_Stream* strm) { int size; /* データを前詰めする */ if (strm->_data.size > 0) { memmove(strm->_data.buff, &(strm->_data.buff[strm->_data.off]), strm->_data.size); strm->_data.off = 0; } /* バッファにロードする */ size = strm->_readCore(strm, &(strm->_data.buff[strm->_data.size]), strm->_data.buffSize - strm->_data.size); if (size < 0) { return false; } strm->_data.size += size; return true; }