/* * Baltisot * Copyright (C) 1999-2008 Nicolas "Pixel" Noble * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "Buffer.h" #include "generic.h" #include "Atomic.h" int Buffer::nb_buffer = 0; int Buffer::GetNbBuffer() { return nb_buffer; } Buffer::Buffer(bool _seekable) : Handle(-1), buffer(0), zero(0), realsiz(0), bufsiz(0), ptr(0), wptr(0), seekable(_seekable), got_eof(false) { Atomic::Increment(&nb_buffer); } Buffer::~Buffer() { free(buffer); Atomic::Decrement(&nb_buffer); } Buffer::Buffer(const Buffer & b) : Handle(-1), buffer(0), zero(b.zero), realsiz(b.realsiz), bufsiz(b.bufsiz), ptr(b.ptr), wptr(b.wptr), seekable(b.seekable), got_eof(b.got_eof) { buffer = (Byte *) malloc(bufsiz); memcpy(buffer, b.buffer, bufsiz); Atomic::Increment(&nb_buffer); } ssize_t Buffer::write(const void *buf, size_t count) throw (GeneralException) { if (!count) { return 0; } if (count + wptr > bufsiz) { int numblocks = (count + wptr) / realloc_threshold; int remains = (count + wptr) % realloc_threshold; buffer = (Byte *) realloc(buffer, bufsiz = ((numblocks + (remains ? 1 : 0)) * realloc_threshold)); } memcpy(buffer + wptr, buf, count); wptr += count; if (wptr > realsiz) { realsiz = wptr; } return count; } ssize_t Buffer::read(void *buf, size_t count) throw (GeneralException) { count = MIN(count, realsiz - ptr); if (!count) { if (got_eof) close(); got_eof = true; return 0; } got_eof = false; if (buf) memcpy(buf, buffer + ptr, count); ptr += count; if (!seekable) { if (ptr >= realloc_threshold) { int numblocks = (bufsiz / realloc_threshold) - (ptr / realloc_threshold); memmove(buffer, buffer + (bufsiz - numblocks * realloc_threshold), numblocks * realloc_threshold); ptr -= (bufsiz - numblocks * realloc_threshold); wptr -= (bufsiz - numblocks * realloc_threshold); realsiz -= (bufsiz - numblocks * realloc_threshold); buffer = (Byte *) realloc(buffer, bufsiz = (numblocks * realloc_threshold)); } } return count; } bool Buffer::CanRead() const { return true; } bool Buffer::CanWrite() const { return true; } String Buffer::GetName() const { if (seekable) return "Buffer"; else return "Fifo"; } Buffer Buffer::operator=(const Buffer & b) { if (b.buffer != buffer) { free(buffer); realsiz = b.realsiz; ptr = b.ptr; wptr = b.wptr; seekable = b.seekable; if ((bufsiz = b.bufsiz)) { buffer = (Byte *) malloc(bufsiz); memcpy(buffer, b.buffer, realsiz); } else { buffer = 0; } } return *this; } bool Buffer::CanWatch() const { return false; } ssize_t Buffer::GetSize() const { return realsiz; } ssize_t Buffer::GetRemaining() const { return realsiz - ptr; } Byte Buffer::operator[](size_t p) const { if (p >= realsiz) { return 0; } else { if (seekable) { return buffer[p]; } else { return buffer[ptr + p]; } } } Byte & Buffer::operator[](size_t p) { p++; if (p > bufsiz) { int numblocks = p / realloc_threshold; int remains = p % realloc_threshold; buffer = (Byte *) realloc(buffer, bufsiz = ((numblocks + (remains ? 1 : 0)) * realloc_threshold)); } if (p > realsiz) { memset(buffer + realsiz, 0, p - realsiz); realsiz = p; } p--; if (seekable) { return buffer[p]; } else { return buffer[ptr + p]; } } const Byte * Buffer::GetBuffer() const { if (seekable) { return buffer; } else { return buffer + ptr; } } bool Buffer::CanSeek() const { return seekable; } off_t Buffer::seek(off_t off, int wheel) throw (GeneralException) { size_t old_ptr; if (!seekable) { throw GeneralException("This buffer is a fifo, thus is not seekable"); } old_ptr = ptr; switch (wheel) { case SEEK_SET: ptr = off; break; case SEEK_CUR: ptr += off; break; case SEEK_END: ptr = realsiz + off; break; } if (ptr < 0) { ptr = old_ptr; throw GeneralException("Can't seek a Buffer before its start."); } operator[](ptr); return ptr; } off_t Buffer::tell() const { return ptr; } off_t Buffer::wseek(off_t off, int wheel) throw (GeneralException) { if (!seekable) { throw GeneralException("This buffer is a fifo, thus is not seekable"); } switch (wheel) { case SEEK_SET: wptr = off; break; case SEEK_CUR: wptr += off; break; case SEEK_END: wptr = realsiz + off; break; } operator[](wptr); return wptr; } off_t Buffer::wtell() const { return wptr; } void Buffer::reset() { free(buffer); realsiz = bufsiz = ptr = wptr = 0; got_eof = false; }