llbufferstream.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:9k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llbufferstream.cpp
  3.  * @author Phoenix
  4.  * @date 2005-10-10
  5.  * @brief Implementation of the buffer iostream classes
  6.  *
  7.  * $LicenseInfo:firstyear=2005&license=viewergpl$
  8.  * 
  9.  * Copyright (c) 2005-2010, Linden Research, Inc.
  10.  * 
  11.  * Second Life Viewer Source Code
  12.  * The source code in this file ("Source Code") is provided by Linden Lab
  13.  * to you under the terms of the GNU General Public License, version 2.0
  14.  * ("GPL"), unless you have obtained a separate licensing agreement
  15.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  16.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18.  * 
  19.  * There are special exceptions to the terms and conditions of the GPL as
  20.  * it is applied to this Source Code. View the full text of the exception
  21.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  22.  * online at
  23.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24.  * 
  25.  * By copying, modifying or distributing this software, you acknowledge
  26.  * that you have read and understood your obligations described above,
  27.  * and agree to abide by those obligations.
  28.  * 
  29.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31.  * COMPLETENESS OR PERFORMANCE.
  32.  * $/LicenseInfo$
  33.  */
  34. #include "linden_common.h"
  35. #include "llbufferstream.h"
  36. #include "llbuffer.h"
  37. #include "llmemtype.h"
  38. static const S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4;
  39. /*
  40.  * LLBufferStreamBuf
  41.  */
  42. LLBufferStreamBuf::LLBufferStreamBuf(
  43. const LLChannelDescriptors& channels,
  44. LLBufferArray* buffer) :
  45. mChannels(channels),
  46. mBuffer(buffer)
  47. {
  48. LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
  49. }
  50. LLBufferStreamBuf::~LLBufferStreamBuf()
  51. {
  52. LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
  53. sync();
  54. }
  55. // virtual
  56. int LLBufferStreamBuf::underflow()
  57. {
  58. LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
  59. //lldebugs << "LLBufferStreamBuf::underflow()" << llendl;
  60. if(!mBuffer)
  61. {
  62. return EOF;
  63. }
  64. LLBufferArray::segment_iterator_t iter;
  65. LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
  66. U8* last_pos = (U8*)gptr();
  67. LLSegment segment;
  68. if(last_pos)
  69. {
  70. // Back up into a piece of memory we know that we have
  71. // allocated so that calls for the next segment based on
  72. // 'after' will succeed.
  73. --last_pos;
  74. iter = mBuffer->splitAfter(last_pos);
  75. if(iter != end)
  76. {
  77. // We need to clear the read segment just in case we have
  78. // an early exit in the function and never collect the
  79. // next segment. Calling eraseSegment() with the same
  80. // segment twice is just like double deleting -- nothing
  81. // good comes from it.
  82. mBuffer->eraseSegment(iter++);
  83. if(iter != end) segment = (*iter);
  84. }
  85. else
  86. {
  87. // This should never really happen, but somehow, the
  88. // istream is telling the buf that it just finished
  89. // reading memory that is not in the buf. I think this
  90. // would only happen if there were a bug in the c++ stream
  91. // class. Just bail.
  92. // *TODO: can we set the fail bit on the stream somehow?
  93. return EOF;
  94. }
  95. }
  96. else
  97. {
  98. // Get iterator to full segment containing last_pos
  99. // and construct sub-segment starting at last_pos.
  100. // Note: segment may != *it at this point
  101. iter = mBuffer->constructSegmentAfter(last_pos, segment);
  102. }
  103. if(iter == end)
  104. {
  105. return EOF;
  106. }
  107. // Iterate through segments to find a non-empty segment on input channel.
  108. while((!segment.isOnChannel(mChannels.in()) || (segment.size() == 0)))
  109. {
  110. ++iter;
  111. if(iter == end)
  112. {
  113. return EOF;
  114. }
  115. segment = *(iter);
  116. }
  117. // set up the stream to read from the next segment.
  118. char* start = (char*)segment.data();
  119. setg(start, start, start + segment.size());
  120. return *gptr();
  121. }
  122. // virtual
  123. int LLBufferStreamBuf::overflow(int c)
  124. {
  125. LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
  126. if(!mBuffer)
  127. {
  128. return EOF;
  129. }
  130. if(EOF == c)
  131. {
  132. // if someone puts an EOF, I suppose we should sync and return
  133. // success.
  134. if(0 == sync())
  135. {
  136. return 1;
  137. }
  138. else
  139. {
  140. return EOF;
  141. }
  142. }
  143. // since we got here, we have a buffer, and we have a character to
  144. // put on it.
  145. LLBufferArray::segment_iterator_t it;
  146. it = mBuffer->makeSegment(mChannels.out(), DEFAULT_OUTPUT_SEGMENT_SIZE);
  147. if(it != mBuffer->endSegment())
  148. {
  149. char* start = (char*)(*it).data();
  150. (*start) = (char)(c);
  151. setp(start + 1, start + (*it).size());
  152. return c;
  153. }
  154. else
  155. {
  156. return EOF;
  157. }
  158. }
  159. // virtual
  160. int LLBufferStreamBuf::sync()
  161. {
  162. LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
  163. int return_value = -1;
  164. if(!mBuffer)
  165. {
  166. return return_value;
  167. }
  168. // This chunk of code is not necessary because typically, users of
  169. // the stream will read until EOF. Therefore, underflow was called
  170. // and the segment was discarded before the sync() was called in
  171. // the destructor. Theoretically, we could keep some more data
  172. // around and detect the rare case where an istream was deleted
  173. // before reading to the end, but that will only leave behind some
  174. // unavailable but still referenced memory. Also, if another
  175. // istream is constructed, it will re-read that segment, and then
  176. // discard it.
  177. //U8* last_pos = (U8*)gptr();
  178. //if(last_pos)
  179. //{
  180. // // Looks like we read something. Discard what we have read.
  181. // // gptr() actually returns the currrent position, but we call
  182. // // it last_pos because of how it is used in the split call
  183. // // below.
  184. // --last_pos;
  185. // LLBufferArray::segment_iterator_t iter;
  186. // iter = mBuffer->splitAfter(last_pos);
  187. // if(iter != mBuffer->endSegment())
  188. // {
  189. // // We need to clear the read segment just in case we have
  190. // // an early exit in the function and never collect the
  191. // // next segment. Calling eraseSegment() with the same
  192. // // segment twice is just like double deleting -- nothing
  193. // // good comes from it.
  194. // mBuffer->eraseSegment(iter);
  195. // }
  196. //}
  197. // set the put pointer so that we force an overflow on the next
  198. // write.
  199. U8* address = (U8*)pptr();
  200. setp(NULL, NULL);
  201. // *NOTE: I bet we could just --address if address is not NULL.
  202. // Need to think about that.
  203. address = mBuffer->seek(mChannels.out(), address, -1);
  204. if(address)
  205. {
  206. LLBufferArray::segment_iterator_t it;
  207. it = mBuffer->splitAfter(address);
  208. LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
  209. if(it != end)
  210. {
  211. ++it;
  212. if(it != end)
  213. {
  214. mBuffer->eraseSegment(it);
  215. }
  216. return_value = 0;
  217. }
  218. }
  219. else
  220. {
  221. // nothing was put on the buffer, so the sync() is a no-op.
  222. return_value = 0;
  223. }
  224. return return_value;
  225. }
  226. // virtual
  227. #if( LL_WINDOWS || __GNUC__ > 2)
  228. LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff(
  229. LLBufferStreamBuf::off_type off,
  230. std::ios::seekdir way,
  231. std::ios::openmode which)
  232. #else
  233. streampos LLBufferStreamBuf::seekoff(
  234. streamoff off,
  235. std::ios::seekdir way,
  236. std::ios::openmode which)
  237. #endif
  238. {
  239. LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
  240. if(!mBuffer
  241.    || ((way == std::ios::beg) && (off < 0))
  242.    || ((way == std::ios::end) && (off > 0)))
  243. {
  244. return -1;
  245. }
  246. U8* address = NULL;
  247. if(which & std::ios::in)
  248. {
  249. U8* base_addr = NULL;
  250. switch(way)
  251. {
  252. case std::ios::end:
  253. base_addr = (U8*)LLBufferArray::npos;
  254. break;
  255. case std::ios::cur:
  256. // get the current get pointer and adjust it for buffer
  257. // array semantics.
  258. base_addr = (U8*)gptr();
  259. break;
  260. case std::ios::beg:
  261. default:
  262. // NULL is fine
  263. break;
  264. }
  265. address = mBuffer->seek(mChannels.in(), base_addr, off);
  266. if(address)
  267. {
  268. LLBufferArray::segment_iterator_t iter;
  269. iter = mBuffer->getSegment(address);
  270. char* start = (char*)(*iter).data();
  271. setg(start, (char*)address, start + (*iter).size());
  272. }
  273. else
  274. {
  275. address = (U8*)(-1);
  276. }
  277. }
  278. if(which & std::ios::out)
  279. {
  280. U8* base_addr = NULL;
  281. switch(way)
  282. {
  283. case std::ios::end:
  284. base_addr = (U8*)LLBufferArray::npos;
  285. break;
  286. case std::ios::cur:
  287. // get the current put pointer and adjust it for buffer
  288. // array semantics.
  289. base_addr = (U8*)pptr();
  290. break;
  291. case std::ios::beg:
  292. default:
  293. // NULL is fine
  294. break;
  295. }
  296. address = mBuffer->seek(mChannels.out(), base_addr, off);
  297. if(address)
  298. {
  299. LLBufferArray::segment_iterator_t iter;
  300. iter = mBuffer->getSegment(address);
  301. setp((char*)address, (char*)(*iter).data() + (*iter).size());
  302. }
  303. else
  304. {
  305. address = (U8*)(-1);
  306. }
  307. }
  308. #if( LL_WINDOWS || __GNUC__ > 2 )
  309. S32 rv = (S32)(intptr_t)address;
  310. return (pos_type)rv;
  311. #else
  312. return (streampos)address;
  313. #endif
  314. }
  315. /*
  316.  * LLBufferStream
  317.  */
  318. LLBufferStream::LLBufferStream(
  319. const LLChannelDescriptors& channels,
  320. LLBufferArray* buffer) :
  321. std::iostream(&mStreamBuf),
  322. mStreamBuf(channels, buffer)
  323. {
  324. LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
  325. }
  326. LLBufferStream::~LLBufferStream()
  327. {
  328. LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
  329. }