summaryrefslogtreecommitdiff
path: root/libs/taglib/taglib/toolkit/tfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/taglib/taglib/toolkit/tfile.cpp')
-rw-r--r--libs/taglib/taglib/toolkit/tfile.cpp565
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;
-}