diff options
Diffstat (limited to 'libs/taglib/taglib/toolkit/tfile.cpp')
-rw-r--r-- | libs/taglib/taglib/toolkit/tfile.cpp | 565 |
1 files changed, 0 insertions, 565 deletions
diff --git a/libs/taglib/taglib/toolkit/tfile.cpp b/libs/taglib/taglib/toolkit/tfile.cpp deleted file mode 100644 index f63a06612a..0000000000 --- a/libs/taglib/taglib/toolkit/tfile.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * - * USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tfile.h" -#include "tstring.h" -#include "tdebug.h" - -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> - -#ifdef _WIN32 -# include <wchar.h> -# include <windows.h> -# include <io.h> -# define ftruncate _chsize -#else -# include <unistd.h> -#endif - -#include <stdlib.h> - -#ifndef R_OK -# define R_OK 4 -#endif -#ifndef W_OK -# define W_OK 2 -#endif - -using namespace TagLib; - -#ifdef _WIN32 - -typedef FileName FileNameHandle; - -#else - -struct FileNameHandle : public std::string -{ - FileNameHandle(FileName name) : std::string(name) {} - operator FileName () const { return c_str(); } -}; - -#endif - -class File::FilePrivate -{ -public: - FilePrivate(FileName fileName); - - FILE *file; - - FileNameHandle name; - - bool readOnly; - bool valid; - ulong size; - static const uint bufferSize = 1024; -}; - -File::FilePrivate::FilePrivate(FileName fileName) : - file(0), - name(fileName), - readOnly(true), - valid(true), - size(0) -{ - // First try with read / write mode, if that fails, fall back to read only. - -#ifdef _WIN32 - - if(wcslen((const wchar_t *) fileName) > 0) { - - file = _wfopen(name, L"rb+"); - - if(file) - readOnly = false; - else - file = _wfopen(name, L"rb"); - - if(file) - return; - - } - -#endif - - file = fopen(name, "rb+"); - - if(file) - readOnly = false; - else - file = fopen(name, "rb"); - - if(!file) { - debug("Could not open file " + String((const char *) name)); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -File::File(FileName file) -{ - d = new FilePrivate(file); -} - -File::~File() -{ - if(d->file) - fclose(d->file); - delete d; -} - -FileName File::name() const -{ - return d->name; -} - -ByteVector File::readBlock(ulong length) -{ - if(!d->file) { - debug("File::readBlock() -- Invalid File"); - return ByteVector::null; - } - - if(length == 0) - return ByteVector::null; - - if(length > FilePrivate::bufferSize && - length > ulong(File::length())) - { - length = File::length(); - } - - ByteVector v(static_cast<uint>(length)); - const int count = fread(v.data(), sizeof(char), length, d->file); - v.resize(count); - return v; -} - -void File::writeBlock(const ByteVector &data) -{ - if(!d->file) - return; - - if(d->readOnly) { - debug("File::writeBlock() -- attempted to write to a file that is not writable"); - return; - } - - fwrite(data.data(), sizeof(char), data.size(), d->file); -} - -long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &before) -{ - if(!d->file || pattern.size() > d->bufferSize) - return -1; - - // The position in the file that the current buffer starts at. - - long bufferOffset = fromOffset; - ByteVector buffer; - - // These variables are used to keep track of a partial match that happens at - // the end of a buffer. - - int previousPartialMatch = -1; - int beforePreviousPartialMatch = -1; - - // Save the location of the current read pointer. We will restore the - // position using seek() before all returns. - - long originalPosition = tell(); - - // Start the search at the offset. - - seek(fromOffset); - - // This loop is the crux of the find method. There are three cases that we - // want to account for: - // - // (1) The previously searched buffer contained a partial match of the search - // pattern and we want to see if the next one starts with the remainder of - // that pattern. - // - // (2) The search pattern is wholly contained within the current buffer. - // - // (3) The current buffer ends with a partial match of the pattern. We will - // note this for use in the next itteration, where we will check for the rest - // of the pattern. - // - // All three of these are done in two steps. First we check for the pattern - // and do things appropriately if a match (or partial match) is found. We - // then check for "before". The order is important because it gives priority - // to "real" matches. - - for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) { - - // (1) previous partial match - - if(previousPartialMatch >= 0 && int(d->bufferSize) > previousPartialMatch) { - const int patternOffset = (d->bufferSize - previousPartialMatch); - if(buffer.containsAt(pattern, 0, patternOffset)) { - seek(originalPosition); - return bufferOffset - d->bufferSize + previousPartialMatch; - } - } - - if(!before.isNull() && beforePreviousPartialMatch >= 0 && int(d->bufferSize) > beforePreviousPartialMatch) { - const int beforeOffset = (d->bufferSize - beforePreviousPartialMatch); - if(buffer.containsAt(before, 0, beforeOffset)) { - seek(originalPosition); - return -1; - } - } - - // (2) pattern contained in current buffer - - long location = buffer.find(pattern); - if(location >= 0) { - seek(originalPosition); - return bufferOffset + location; - } - - if(!before.isNull() && buffer.find(before) >= 0) { - seek(originalPosition); - return -1; - } - - // (3) partial match - - previousPartialMatch = buffer.endsWithPartialMatch(pattern); - - if(!before.isNull()) - beforePreviousPartialMatch = buffer.endsWithPartialMatch(before); - - bufferOffset += d->bufferSize; - } - - // Since we hit the end of the file, reset the status before continuing. - - clear(); - - seek(originalPosition); - - return -1; -} - - -long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &before) -{ - if(!d->file || pattern.size() > d->bufferSize) - return -1; - - // The position in the file that the current buffer starts at. - - ByteVector buffer; - - // These variables are used to keep track of a partial match that happens at - // the end of a buffer. - - /* - int previousPartialMatch = -1; - int beforePreviousPartialMatch = -1; - */ - - // Save the location of the current read pointer. We will restore the - // position using seek() before all returns. - - long originalPosition = tell(); - - // Start the search at the offset. - - long bufferOffset; - if(fromOffset == 0) { - seek(-1 * int(d->bufferSize), End); - bufferOffset = tell(); - } - else { - seek(fromOffset + -1 * int(d->bufferSize), Beginning); - bufferOffset = tell(); - } - - // See the notes in find() for an explanation of this algorithm. - - for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) { - - // TODO: (1) previous partial match - - // (2) pattern contained in current buffer - - long location = buffer.rfind(pattern); - if(location >= 0) { - seek(originalPosition); - return bufferOffset + location; - } - - if(!before.isNull() && buffer.find(before) >= 0) { - seek(originalPosition); - return -1; - } - - // TODO: (3) partial match - - bufferOffset -= d->bufferSize; - seek(bufferOffset); - } - - // Since we hit the end of the file, reset the status before continuing. - - clear(); - - seek(originalPosition); - - return -1; -} - -void File::insert(const ByteVector &data, ulong start, ulong replace) -{ - if(!d->file) - return; - - if(data.size() == replace) { - seek(start); - writeBlock(data); - return; - } - else if(data.size() < replace) { - seek(start); - writeBlock(data); - removeBlock(start + data.size(), replace - data.size()); - return; - } - - // Woohoo! Faster (about 20%) than id3lib at last. I had to get hardcore - // and avoid TagLib's high level API for rendering just copying parts of - // the file that don't contain tag data. - // - // Now I'll explain the steps in this ugliness: - - // First, make sure that we're working with a buffer that is longer than - // the *differnce* in the tag sizes. We want to avoid overwriting parts - // that aren't yet in memory, so this is necessary. - - ulong bufferLength = bufferSize(); - - while(data.size() - replace > bufferLength) - bufferLength += bufferSize(); - - // Set where to start the reading and writing. - - long readPosition = start + replace; - long writePosition = start; - - ByteVector buffer; - ByteVector aboutToOverwrite(static_cast<uint>(bufferLength)); - - // This is basically a special case of the loop below. Here we're just - // doing the same steps as below, but since we aren't using the same buffer - // size -- instead we're using the tag size -- this has to be handled as a - // special case. We're also using File::writeBlock() just for the tag. - // That's a bit slower than using char *'s so, we're only doing it here. - - seek(readPosition); - int bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file); - readPosition += bufferLength; - - seek(writePosition); - writeBlock(data); - writePosition += data.size(); - - buffer = aboutToOverwrite; - - // In case we've already reached the end of file... - - buffer.resize(bytesRead); - - // Ok, here's the main loop. We want to loop until the read fails, which - // means that we hit the end of the file. - - while(!buffer.isEmpty()) { - - // Seek to the current read position and read the data that we're about - // to overwrite. Appropriately increment the readPosition. - - seek(readPosition); - bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file); - aboutToOverwrite.resize(bytesRead); - readPosition += bufferLength; - - // Check to see if we just read the last block. We need to call clear() - // if we did so that the last write succeeds. - - if(ulong(bytesRead) < bufferLength) - clear(); - - // Seek to the write position and write our buffer. Increment the - // writePosition. - - seek(writePosition); - fwrite(buffer.data(), sizeof(char), buffer.size(), d->file); - writePosition += buffer.size(); - - // Make the current buffer the data that we read in the beginning. - - buffer = aboutToOverwrite; - - // Again, we need this for the last write. We don't want to write garbage - // at the end of our file, so we need to set the buffer size to the amount - // that we actually read. - - bufferLength = bytesRead; - } -} - -void File::removeBlock(ulong start, ulong length) -{ - if(!d->file) - return; - - ulong bufferLength = bufferSize(); - - long readPosition = start + length; - long writePosition = start; - - ByteVector buffer(static_cast<uint>(bufferLength)); - - ulong bytesRead = 1; - - while(bytesRead != 0) { - seek(readPosition); - bytesRead = fread(buffer.data(), sizeof(char), bufferLength, d->file); - readPosition += bytesRead; - - // Check to see if we just read the last block. We need to call clear() - // if we did so that the last write succeeds. - - if(bytesRead < bufferLength) - clear(); - - seek(writePosition); - fwrite(buffer.data(), sizeof(char), bytesRead, d->file); - writePosition += bytesRead; - } - truncate(writePosition); -} - -bool File::readOnly() const -{ - return d->readOnly; -} - -bool File::isReadable(const char *file) -{ - return access(file, R_OK) == 0; -} - -bool File::isOpen() const -{ - return (d->file != NULL); -} - -bool File::isValid() const -{ - return isOpen() && d->valid; -} - -void File::seek(long offset, Position p) -{ - if(!d->file) { - debug("File::seek() -- trying to seek in a file that isn't opened."); - return; - } - - switch(p) { - case Beginning: - fseek(d->file, offset, SEEK_SET); - break; - case Current: - fseek(d->file, offset, SEEK_CUR); - break; - case End: - fseek(d->file, offset, SEEK_END); - break; - } -} - -void File::clear() -{ - clearerr(d->file); -} - -long File::tell() const -{ - return ftell(d->file); -} - -long File::length() -{ - // Do some caching in case we do multiple calls. - - if(d->size > 0) - return d->size; - - if(!d->file) - return 0; - - long curpos = tell(); - - seek(0, End); - long endpos = tell(); - - seek(curpos, Beginning); - - d->size = endpos; - return endpos; -} - -bool File::isWritable(const char *file) -{ - return access(file, W_OK) == 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void File::setValid(bool valid) -{ - d->valid = valid; -} - -void File::truncate(long length) -{ - ftruncate(fileno(d->file), length); -} - -TagLib::uint File::bufferSize() -{ - return FilePrivate::bufferSize; -} |