/* vim: ts=4 sw=4 sts=4 ff=unix fenc=utf-8 : * ===================================================================== * sc_stream_memory.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 <string.h> #include <sc_os.h> #include <sc_error.h> #include <sc_mmgr.h> #include <sc_stream_memory.h> /* --------------------------------------------------------------------- * プロトタイプ宣言 * --------------------------------------------------------------------- */ static int SC_Stream_stream_memoryRead(SC_Stream* strm, void* buff, size_t size); static int SC_Stream_stream_memoryWrite(SC_Stream* strm, const void* buff, size_t size); static bool SC_Stream_stream_memoryClose(SC_Stream* strm); /** * メモリストリームを構築します。 * 構築に失敗した場合、NULL を返します。 * * @param size ストリームの最大サイズ * @param buffSize 一時保存用バッファサイズ * @return ストリーム */ SC_Stream* SC_Stream_newMemoryStream(size_t size, size_t buffSize) { SC_Stream* strm; SC_Stream_BufferData* memData; size_t totalSize = sizeof(SC_Stream) + buffSize; totalSize += sizeof(SC_Stream_BufferData) + size; strm = (SC_Stream*) malloc(totalSize); if (strm == NULL) { /* メモリ確保失敗 */ return NULL; } strm->_data.buff = (char*) (strm + 1); strm->_data.buffSize = buffSize; strm->_data.off = 0; strm->_data.size = 0; memData = (SC_Stream_BufferData*) (strm->_data.buff + strm->_data.buffSize); memData->buff = (char*) (memData + 1); memData->buffSize = size; memData->off = 0; memData->size = 0; strm->_strmInfo = memData; strm->readc = SC_Stream_readc_; strm->read = SC_Stream_read_; strm->readExact = SC_Stream_readExact_; strm->readLine = SC_Stream_readLine_; strm->limitedRead = SC_Stream_limitedRead_; strm->writec = SC_Stream_writec_; strm->write = SC_Stream_write_; strm->writeExact = SC_Stream_writeExact_; strm->_readCore = SC_Stream_stream_memoryRead; strm->_writeCore = SC_Stream_stream_memoryWrite; strm->close = SC_Stream_stream_memoryClose; return strm; } /** * メモリから読み込みます。 * 末尾に達した場合 0 を返します。 * * @param strm ストリーム * @param buff バッファ * @param size サイズ * @return 読み取ったバッファサイズ */ static int SC_Stream_stream_memoryRead(SC_Stream* strm, void* buff, size_t size) { size_t readSize; size_t restReadSize; char* outPtr = (char*) buff; SC_Stream_BufferData* data = (SC_Stream_BufferData*) strm->_strmInfo; if (data->size == 0) { /* データなし */ return 0; } /* 読み取るサイズを設定 */ restReadSize = size; if (data->size < size) { restReadSize = data->size; } /* 0 1 2 3 4 5 6 (data->buffSize = 7) * [x][x][ ][ ][x][x][x] * | | * OFF END * OFF~ENDまでの範囲の読み込みで事足りるかチェック */ readSize = data->buffSize - data->off; if (readSize <= restReadSize) { /* とりあえず足りないので、ENDまで読み込む */ memcpy(outPtr, &data->buff[data->off], readSize); /* 読み込んだ分処理する */ data->off = 0; data->size -= readSize; restReadSize -= readSize; outPtr += readSize; } if (restReadSize > 0) { /* まだ読み込む必要があるならすべて読み込む */ memcpy(outPtr, &data->buff[data->off], restReadSize); data->off += restReadSize; data->size -= restReadSize; outPtr += restReadSize; } /* サイズを返す */ return (outPtr - (char*) buff); } /** * メモリに書き込みます。 * * @param strm ストリーム * @param buff バッファ * @param size サイズ * @return 書き出したバッファサイズ */ static int SC_Stream_stream_memoryWrite(SC_Stream* strm, const void* buff, size_t size) { int tmp; size_t writeSize; size_t restWriteSize; const char* inPtr = (const char*) buff; SC_Stream_BufferData* data = (SC_Stream_BufferData*) strm->_strmInfo; /* 書き込むサイズを設定 */ restWriteSize = size; tmp = data->buffSize - data->size; /* 空き容量 */ if (restWriteSize >= tmp) { /* 書き込もうとするサイズの方がデカイ=>可能な範囲書き込む */ restWriteSize = tmp; } /* 0 1 2 3 4 5 6 (data->buffSize = 7) * [ ][ ][x][x][x][ ][ ] * | | | * OFF E END * ENDの位置までの書き込みで事たりるかチェック * Eの次の位置 = data->off + data->size */ writeSize = tmp - data->off; /* E以降の空 = 全空容量 - 先頭からの空き */ if ((writeSize > 0) && (writeSize <= restWriteSize)) { /* とりあえずたりないので、ENDの位置まで書き込む */ memcpy(&data->buff[data->off + data->size], inPtr, writeSize); /* 書き込んだ分処理する */ data->size += writeSize; restWriteSize -= writeSize; inPtr += writeSize; } /* ここにくる時点で(E < OFF) のような形になっている * * 0 1 2 3 4 5 6 (data->buffSize = 7) * [x][ ][ ][x][x][x][x] * | | | * E OFF END * * Eの次の位置 = data->off + data->size - data->buffSize * 3 + 5 - 7 */ if (restWriteSize > 0) { /* まだ書き込む必要なら E の次の位置から書き込む */ tmp = data->off + data->size; if (tmp >= data->buffSize) { tmp -= data->buffSize; } memcpy(&data->buff[tmp], inPtr, restWriteSize); data->size += restWriteSize; inPtr += restWriteSize; } /* 書き込んだサイズを返す */ return (inPtr - (char*) buff); } /** * ストリームを close します。 * メモリストリームの場合、バッファをクリアするのみです。 * * @param strm ストリーム * @return true/false (成功/失敗) */ static bool SC_Stream_stream_memoryClose(SC_Stream* strm) { SC_Stream_BufferData* data = (SC_Stream_BufferData*) strm->_strmInfo; data->off = 0; data->size = 0; return true; }