llbuffer.cpp

Go to the documentation of this file.
00001 
00034 #include "linden_common.h"
00035 #include "llbuffer.h"
00036 
00037 #include "llmath.h"
00038 #include "llmemtype.h"
00039 #include "llstl.h"
00040 
00044 LLSegment::LLSegment() :
00045         mChannel(0),
00046         mData(NULL),
00047         mSize(0)
00048 {
00049         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00050 }
00051 
00052 LLSegment::LLSegment(S32 channel, U8* data, S32 data_len) :
00053         mChannel(channel),
00054         mData(data),
00055         mSize(data_len)
00056 {
00057         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00058 }
00059 
00060 LLSegment::~LLSegment()
00061 {
00062         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00063 }
00064 
00065 bool LLSegment::isOnChannel(S32 channel) const
00066 {
00067         return (mChannel == channel);
00068 }
00069 
00070 S32 LLSegment::getChannel() const
00071 {
00072         return mChannel;
00073 }
00074 
00075 void LLSegment::setChannel(S32 channel)
00076 {
00077         mChannel = channel;
00078 }
00079 
00080 
00081 U8* LLSegment::data() const
00082 {
00083         return mData;
00084 }
00085 
00086 S32 LLSegment::size() const
00087 {
00088         return mSize;
00089 }
00090 
00091 bool LLSegment::operator==(const LLSegment& rhs) const
00092 {
00093         if((mData != rhs.mData)||(mSize != rhs.mSize)||(mChannel != rhs.mChannel))
00094         {
00095                 return false;
00096         }
00097         return true;
00098 }
00099 
00103 LLHeapBuffer::LLHeapBuffer() :
00104         mBuffer(NULL),
00105         mSize(0),
00106         mNextFree(NULL),
00107         mReclaimedBytes(0)
00108 {
00109         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00110         const S32 DEFAULT_HEAP_BUFFER_SIZE = 16384;
00111         allocate(DEFAULT_HEAP_BUFFER_SIZE);
00112 }
00113 
00114 LLHeapBuffer::LLHeapBuffer(S32 size) :
00115         mBuffer(NULL),
00116         mSize(0),
00117         mNextFree(NULL),
00118         mReclaimedBytes(0)
00119 {
00120         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00121         allocate(size);
00122 }
00123 
00124 LLHeapBuffer::LLHeapBuffer(const U8* src, S32 len) :
00125         mBuffer(NULL),
00126         mSize(0),
00127         mNextFree(NULL),
00128         mReclaimedBytes(0)
00129 {
00130         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00131         if((len > 0) && src)
00132         {
00133                 allocate(len);
00134                 if(mBuffer)
00135                 {
00136                         memcpy(mBuffer, src, len);      /*Flawfinder: ignore*/
00137                 }
00138         }
00139 }
00140 
00141 // virtual
00142 LLHeapBuffer::~LLHeapBuffer()
00143 {
00144         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00145         delete[] mBuffer;
00146         mBuffer = NULL;
00147         mSize = 0;
00148         mNextFree = NULL;
00149 }
00150 
00151 S32 LLHeapBuffer::bytesLeft() const
00152 {
00153         return (mSize - (mNextFree - mBuffer));
00154 }
00155 
00156 // virtual
00157 bool LLHeapBuffer::createSegment(
00158         S32 channel,
00159         S32 size,
00160         LLSegment& segment)
00161 {
00162         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00163         // get actual size of the segment.
00164         S32 actual_size = llmin(size, (mSize - S32(mNextFree - mBuffer)));
00165 
00166         // bail if we cannot build a valid segment
00167         if(actual_size <= 0)
00168         {
00169                 return false;
00170         }
00171 
00172         // Yay, we're done.
00173         segment = LLSegment(channel, mNextFree, actual_size);
00174         mNextFree += actual_size;
00175         return true;
00176 }
00177 
00178 // virtual
00179 bool LLHeapBuffer::reclaimSegment(const LLSegment& segment)
00180 {
00181         if(containsSegment(segment))
00182         {
00183                 mReclaimedBytes += segment.size();
00184                 if(mReclaimedBytes == mSize)
00185                 {
00186                         // We have reclaimed all of the memory from this
00187                         // buffer. Therefore, we can reset the mNextFree to the
00188                         // start of the buffer, and reset the reclaimed bytes.
00189                         mReclaimedBytes = 0;
00190                         mNextFree = mBuffer;
00191                 }
00192                 else if(mReclaimedBytes > mSize)
00193                 {
00194                         llwarns << "LLHeapBuffer reclaimed more memory than allocated."
00195                                 << " This is probably programmer error." << llendl;
00196                 }
00197                 return true;
00198         }
00199         return false;
00200 }
00201 
00202 // virtual
00203 bool LLHeapBuffer::containsSegment(const LLSegment& segment) const
00204 {
00205         // *NOTE: this check is fairly simple because heap buffers are
00206         // simple contiguous chunks of heap memory.
00207         if((mBuffer > segment.data())
00208            || ((mBuffer + mSize) < (segment.data() + segment.size())))
00209         {
00210                 return false;
00211         }
00212         return true;
00213 }
00214 
00215 void LLHeapBuffer::allocate(S32 size)
00216 {
00217         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00218         mReclaimedBytes = 0;    
00219         mBuffer = new U8[size];
00220         if(mBuffer)
00221         {
00222                 mSize = size;
00223                 mNextFree = mBuffer;
00224         }
00225 }
00226 
00227 
00231 LLBufferArray::LLBufferArray() :
00232         mNextBaseChannel(0)
00233 {
00234         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00235 }
00236 
00237 LLBufferArray::~LLBufferArray()
00238 {
00239         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00240         std::for_each(mBuffers.begin(), mBuffers.end(), DeletePointer());
00241 }
00242 
00243 // static
00244 LLChannelDescriptors LLBufferArray::makeChannelConsumer(
00245         const LLChannelDescriptors& channels)
00246 {
00247         LLChannelDescriptors rv(channels.out());
00248         return rv;
00249 }
00250 
00251 LLChannelDescriptors LLBufferArray::nextChannel()
00252 {
00253         LLChannelDescriptors rv(mNextBaseChannel++);
00254         return rv;
00255 }
00256 
00257 S32 LLBufferArray::capacity() const
00258 {
00259         S32 total = 0;
00260         const_buffer_iterator_t iter = mBuffers.begin();
00261         const_buffer_iterator_t end = mBuffers.end();
00262         for(; iter != end; ++iter)
00263         {
00264                 total += (*iter)->capacity();
00265         }
00266         return total;
00267 }
00268 
00269 bool LLBufferArray::append(S32 channel, const U8* src, S32 len)
00270 {
00271         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00272         std::vector<LLSegment> segments;
00273         if(copyIntoBuffers(channel, src, len, segments))
00274         {
00275                 mSegments.insert(mSegments.end(), segments.begin(), segments.end());
00276                 return true;
00277         }
00278         return false;
00279 }
00280 
00281 bool LLBufferArray::prepend(S32 channel, const U8* src, S32 len)
00282 {
00283         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00284         std::vector<LLSegment> segments;
00285         if(copyIntoBuffers(channel, src, len, segments))
00286         {
00287                 mSegments.insert(mSegments.begin(), segments.begin(), segments.end());
00288                 return true;
00289         }
00290         return false;
00291 }
00292 
00293 bool LLBufferArray::insertAfter(
00294         segment_iterator_t segment,
00295         S32 channel,
00296         const U8* src,
00297         S32 len)
00298 {
00299         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00300         std::vector<LLSegment> segments;
00301         if(mSegments.end() != segment)
00302         {
00303                 ++segment;
00304         }
00305         if(copyIntoBuffers(channel, src, len, segments))
00306         {
00307                 mSegments.insert(segment, segments.begin(), segments.end());
00308                 return true;
00309         }
00310         return false;
00311 }
00312 
00313 LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address)
00314 {
00315         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00316         segment_iterator_t end = mSegments.end();
00317         segment_iterator_t it = getSegment(address);
00318         if(it == end)
00319         {
00320                 return end;
00321         }
00322 
00323         // We have the location and the segment.
00324         U8* base = (*it).data();
00325         S32 size = (*it).size();
00326         if(address == (base + size))
00327         {
00328                 // No need to split, since this is the last byte of the
00329                 // segment. We do not want to have zero length segments, since
00330                 // that will only incur processing overhead with no advantage.
00331                 return it;
00332         }
00333         S32 channel = (*it).getChannel();
00334         LLSegment segment1(channel, base, (address - base) + 1);
00335         *it = segment1;
00336         segment_iterator_t rv = it;
00337         ++it;
00338         LLSegment segment2(channel, address + 1, size - (address - base) - 1);
00339         mSegments.insert(it, segment2);
00340         return rv;
00341 }
00342                                                            
00343 LLBufferArray::segment_iterator_t LLBufferArray::beginSegment()
00344 {
00345         return mSegments.begin();
00346 }
00347 
00348 LLBufferArray::segment_iterator_t LLBufferArray::endSegment()
00349 {
00350         return mSegments.end();
00351 }
00352 
00353 LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter(
00354         U8* address,
00355         LLSegment& segment)
00356 {
00357         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00358         segment_iterator_t rv = mSegments.begin();
00359         segment_iterator_t end = mSegments.end();
00360         if(!address)
00361         {
00362                 if(rv != end)
00363                 {
00364                         segment = (*rv);
00365                 }
00366         }
00367         else
00368         {
00369                 // we have an address - find the segment it is in.
00370                 for( ; rv != end; ++rv)
00371                 {
00372                         if((address >= (*rv).data())
00373                            && (address < ((*rv).data() + (*rv).size())))
00374                         {
00375                                 if((++address) < ((*rv).data() + (*rv).size()))
00376                                 {
00377                                         // it's in this segment - construct an appropriate
00378                                         // sub-segment.
00379                                         segment = LLSegment(
00380                                                 (*rv).getChannel(),
00381                                                 address,
00382                                                 (*rv).size() - (address - (*rv).data()));
00383                                 }
00384                                 else
00385                                 {
00386                                         ++rv;
00387                                         if(rv != end)
00388                                         {
00389                                                 segment = (*rv);
00390                                         }
00391                                 }
00392                                 break;
00393                         }
00394                 }
00395         }
00396         if(rv == end)
00397         {
00398                 segment = LLSegment();
00399         }
00400         return rv;
00401 }
00402 
00403 LLBufferArray::segment_iterator_t LLBufferArray::getSegment(U8* address)
00404 {
00405         segment_iterator_t end = mSegments.end();
00406         if(!address)
00407         {
00408                 return end;
00409         }
00410         segment_iterator_t it = mSegments.begin();
00411         for( ; it != end; ++it)
00412         {
00413                 if((address >= (*it).data())&&(address < (*it).data() + (*it).size()))
00414                 {
00415                         // found it.
00416                         return it;
00417                 }
00418         }
00419         return end;
00420 }
00421 
00422 LLBufferArray::const_segment_iterator_t LLBufferArray::getSegment(
00423         U8* address) const
00424 {
00425         const_segment_iterator_t end = mSegments.end();
00426         if(!address)
00427         {
00428                 return end;
00429         }
00430         const_segment_iterator_t it = mSegments.begin();
00431         for( ; it != end; ++it)
00432         {
00433                 if((address >= (*it).data())
00434                    && (address < (*it).data() + (*it).size()))
00435                 {
00436                         // found it.
00437                         return it;
00438                 }
00439         }
00440         return end;
00441 }
00442 
00443 /*
00444 U8* LLBufferArray::getAddressAfter(U8* address) 
00445 {
00446         U8* rv = NULL;
00447         segment_iterator_t it = getSegment(address);
00448         segment_iterator_t end = mSegments.end();
00449         if(it != end)
00450         {
00451                 if(++address < ((*it).data() + (*it).size()))
00452                 {
00453                         // it's in the same segment
00454                         rv = address;
00455                 }
00456                 else
00457                 {
00458                         // it's in the next segment
00459                         if(++it != end)
00460                         {
00461                                 rv = (*it).data();
00462                         }
00463                 }
00464         }
00465         return rv;
00466 }
00467 */
00468 
00469 S32 LLBufferArray::countAfter(S32 channel, U8* start) const
00470 {
00471         S32 count = 0;
00472         S32 offset = 0;
00473         const_segment_iterator_t it;
00474         const_segment_iterator_t end = mSegments.end();
00475         if(start)
00476         {
00477                 it = getSegment(start);
00478                 if(it == end)
00479                 {
00480                         return count;
00481                 }
00482                 if(++start < ((*it).data() + (*it).size()))
00483                 {
00484                         // it's in the same segment
00485                         offset = start - (*it).data();
00486                 }
00487                 else if(++it == end)
00488                 {
00489                         // it's in the next segment
00490                         return count;
00491                 }
00492         }
00493         else
00494         {
00495                 it = mSegments.begin();
00496         }
00497         while(it != end)
00498         {
00499                 if((*it).isOnChannel(channel))
00500                 {
00501                         count += (*it).size() - offset;
00502                 }
00503                 offset = 0;
00504                 ++it;
00505         }
00506         return count;
00507 }
00508 
00509 U8* LLBufferArray::readAfter(
00510         S32 channel,
00511         U8* start,
00512         U8* dest,
00513         S32& len) const
00514 {
00515         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00516         U8* rv = start;
00517         if(!dest || len <= 0)
00518         {
00519                 return rv;
00520         }
00521         S32 bytes_left = len;
00522         len = 0;
00523         S32 bytes_to_copy = 0;
00524         const_segment_iterator_t it;
00525         const_segment_iterator_t end = mSegments.end();
00526         if(start)
00527         {
00528                 it = getSegment(start);
00529                 if(it == end)
00530                 {
00531                         return rv;
00532                 }
00533                 if((++start < ((*it).data() + (*it).size()))
00534                    && (*it).isOnChannel(channel))
00535                 {
00536                         // copy the data out of this segment
00537                         S32 bytes_in_segment = (*it).size() - (start - (*it).data());
00538                         bytes_to_copy = llmin(bytes_left, bytes_in_segment);
00539                         memcpy(dest, start, bytes_to_copy); /*Flawfinder: ignore*/
00540                         len += bytes_to_copy;
00541                         bytes_left -= bytes_to_copy;
00542                         rv = start + bytes_to_copy - 1;
00543                         ++it;
00544                 }
00545                 else
00546                 {
00547                         ++it;
00548                 }
00549         }
00550         else
00551         {
00552                 it = mSegments.begin();
00553         }
00554         while(bytes_left && (it != end))
00555         {
00556                 if(!((*it).isOnChannel(channel)))
00557                 {
00558                         ++it;
00559                         continue;
00560                 }
00561                 bytes_to_copy = llmin(bytes_left, (*it).size());
00562                 memcpy(dest + len, (*it).data(), bytes_to_copy); /*Flawfinder: ignore*/
00563                 len += bytes_to_copy;
00564                 bytes_left -= bytes_to_copy;
00565                 rv = (*it).data() + bytes_to_copy - 1;
00566                 ++it;
00567         }
00568         return rv;
00569 }
00570 
00571 U8* LLBufferArray::seek(
00572         S32 channel,
00573         U8* start,
00574         S32 delta) const
00575 {
00576         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00577         const_segment_iterator_t it;
00578         const_segment_iterator_t end = mSegments.end();
00579         U8* rv = start;
00580         if(0 == delta)
00581         {
00582                 if((U8*)npos == start)
00583                 {
00584                         // someone is looking for end of data. 
00585                         segment_list_t::const_reverse_iterator rit = mSegments.rbegin();
00586                         segment_list_t::const_reverse_iterator rend = mSegments.rend();
00587                         while(rit != rend)
00588                         {
00589                                 if(!((*rit).isOnChannel(channel)))
00590                                 {
00591                                         ++rit;
00592                                         continue;
00593                                 }
00594                                 rv = (*rit).data() + (*rit).size();
00595                                 break;
00596                         }
00597                 }
00598                 else if(start)
00599                 {
00600                         // This is sort of a weird case - check if zero bytes away
00601                         // from current position is on channel and return start if
00602                         // that is true. Otherwise, return NULL.
00603                         it = getSegment(start);
00604                         if((it == end) || !(*it).isOnChannel(channel))
00605                         {
00606                                 rv = NULL;
00607                         }
00608                 }
00609                 else
00610                 {
00611                         // Start is NULL, so return the very first byte on the
00612                         // channel, or NULL.
00613                         it = mSegments.begin();
00614                         while((it != end) && !(*it).isOnChannel(channel))
00615                         {
00616                                 ++it;
00617                         }
00618                         if(it != end)
00619                         {
00620                                 rv = (*it).data();
00621                         }
00622                 }
00623                 return rv;
00624         }
00625         if(start)
00626         {
00627                 it = getSegment(start);
00628                 if((it != end) && (*it).isOnChannel(channel))
00629                 {
00630                         if(delta > 0)
00631                         {
00632                                 S32 bytes_in_segment = (*it).size() - (start - (*it).data());
00633                                 S32 local_delta = llmin(delta, bytes_in_segment);
00634                                 rv += local_delta;
00635                                 delta -= local_delta;
00636                                 ++it;
00637                         }
00638                         else
00639                         {
00640                                 S32 bytes_in_segment = start - (*it).data();
00641                                 S32 local_delta = llmin(llabs(delta), bytes_in_segment);
00642                                 rv -= local_delta;
00643                                 delta += local_delta;
00644                         }
00645                 }
00646         }
00647         else if(delta < 0)
00648         {
00649                 // start is NULL, and delta indicates seeking backwards -
00650                 // return NULL.
00651                 return NULL;
00652         }
00653         else
00654         {
00655                 // start is NULL and delta > 0
00656                 it = mSegments.begin();
00657         }
00658         if(delta > 0)
00659         {
00660                 // At this point, we have an iterator into the segments, and
00661                 // are seeking forward until delta is zero or we run out
00662                 while(delta && (it != end))
00663                 {
00664                         if(!((*it).isOnChannel(channel)))
00665                         {
00666                                 ++it;
00667                                 continue;
00668                         }
00669                         if(delta <= (*it).size())
00670                         {
00671                                 // it's in this segment
00672                                 rv = (*it).data() + delta;
00673                         }
00674                         delta -= (*it).size();
00675                         ++it;
00676                 }
00677                 if(delta && (it == end))
00678                 {
00679                         // Whoops - sought past end.
00680                         rv = NULL;
00681                 }
00682         }
00683         else //if(delta < 0)
00684         {
00685                 // We are at the beginning of a segment, and need to search
00686                 // backwards.
00687                 segment_list_t::const_reverse_iterator rit(it);
00688                 segment_list_t::const_reverse_iterator rend = mSegments.rend();
00689                 while(delta && (rit != rend))
00690                 {
00691                         if(!((*rit).isOnChannel(channel)))
00692                         {
00693                                 ++rit;
00694                                 continue;
00695                         }
00696                         if(llabs(delta) <= (*rit).size())
00697                         {
00698                                 // it's in this segment.
00699                                 rv = (*rit).data() + (*rit).size() + delta;
00700                                 delta = 0;
00701                         }
00702                         else
00703                         {
00704                                 delta += (*rit).size();
00705                         }
00706                         ++rit;
00707                 }
00708                 if(delta && (rit == rend))
00709                 {
00710                         // sought past the beginning.
00711                         rv = NULL;
00712                 }
00713         }
00714         return rv;
00715 }
00716 
00717 bool LLBufferArray::takeContents(LLBufferArray& source)
00718 {
00719         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00720         std::copy(
00721                 source.mBuffers.begin(),
00722                 source.mBuffers.end(),
00723                 std::back_insert_iterator<buffer_list_t>(mBuffers));
00724         source.mBuffers.clear();
00725         std::copy(
00726                 source.mSegments.begin(),
00727                 source.mSegments.end(),
00728                 std::back_insert_iterator<segment_list_t>(mSegments));
00729         source.mSegments.clear();
00730         source.mNextBaseChannel = 0;
00731         return true;
00732 }
00733 
00734 LLBufferArray::segment_iterator_t LLBufferArray::makeSegment(
00735         S32 channel,
00736         S32 len)
00737 {
00738         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00739         // start at the end of the buffers, because it is the most likely
00740         // to have free space.
00741         LLSegment segment;
00742         buffer_list_t::reverse_iterator it = mBuffers.rbegin();
00743         buffer_list_t::reverse_iterator end = mBuffers.rend();
00744         bool made_segment = false;
00745         for(; it != end; ++it)
00746         {
00747                 if((*it)->createSegment(channel, len, segment))
00748                 {
00749                         made_segment = true;
00750                         break;
00751                 }
00752         }
00753         segment_iterator_t send = mSegments.end();
00754         if(!made_segment)
00755         {
00756                 LLBuffer* buf = new LLHeapBuffer;
00757                 mBuffers.push_back(buf);
00758                 if(!buf->createSegment(channel, len, segment))
00759                 {
00760                         // failed. this should never happen.
00761                         return send;
00762                 }
00763         }
00764 
00765         // store and return the newly made segment
00766         mSegments.insert(send, segment);
00767         std::list<LLSegment>::reverse_iterator rv = mSegments.rbegin();
00768         ++rv;
00769         send = rv.base();
00770         return send;
00771 }
00772 
00773 bool LLBufferArray::eraseSegment(const segment_iterator_t& erase_iter)
00774 {
00775         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00776 
00777         // Find out which buffer contains the segment, and if it is found,
00778         // ask it to reclaim the memory.
00779         bool rv = false;
00780         LLSegment segment(*erase_iter);
00781         buffer_iterator_t iter = mBuffers.begin();
00782         buffer_iterator_t end = mBuffers.end();
00783         for(; iter != end; ++iter)
00784         {
00785                 // We can safely call reclaimSegment on every buffer, and once
00786                 // it returns true, the segment was found.
00787                 if((*iter)->reclaimSegment(segment))
00788                 {
00789                         rv = true;
00790                         break;
00791                 }
00792         }
00793 
00794         // No need to get the return value since we are not interested in
00795         // the interator retured by the call.
00796         (void)mSegments.erase(erase_iter);
00797         return rv;
00798 }
00799 
00800 
00801 bool LLBufferArray::copyIntoBuffers(
00802         S32 channel,
00803         const U8* src,
00804         S32 len,
00805         std::vector<LLSegment>& segments)
00806 {
00807         LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
00808         if(!src || !len) return false;
00809         S32 copied = 0;
00810         LLSegment segment;
00811         buffer_iterator_t it = mBuffers.begin();
00812         buffer_iterator_t end = mBuffers.end();
00813         for(; it != end;)
00814         {
00815                 if(!(*it)->createSegment(channel, len, segment))
00816                 {
00817                         ++it;
00818                         continue;
00819                 }
00820                 segments.push_back(segment);
00821                 S32 bytes = llmin(segment.size(), len);
00822                 memcpy(segment.data(), src + copied, bytes);  /* Flawfinder: Ignore */
00823                 copied += bytes;
00824                 len -= bytes;
00825                 if(0 == len)
00826                 {
00827                         break;
00828                 }
00829         }
00830         while(len)
00831         {
00832                 LLBuffer* buf = new LLHeapBuffer;
00833                 mBuffers.push_back(buf);
00834                 if(!buf->createSegment(channel, len, segment))
00835                 {
00836                         // this totally failed - bail. This is the weird corner
00837                         // case were we 'leak' memory. No worries about an actual
00838                         // leak - we will still reclaim the memory later, but this
00839                         // particular buffer array is hosed for some reason.
00840                         // This should never happen.
00841                         return false;
00842                 }
00843                 segments.push_back(segment);
00844                 memcpy(segment.data(), src + copied, segment.size());   /*Flawfinder: ignore*/
00845                 copied += segment.size();
00846                 len -= segment.size();
00847         }
00848         return true;
00849 }

Generated on Thu Jul 1 06:08:19 2010 for Second Life Viewer by  doxygen 1.4.7