typedef FileName FileNameHandle;
-# define INVALID_FILE INVALID_HANDLE_VALUE
+ typedef HANDLE FileHandle;
+ const FileHandle InvalidFileHandle = INVALID_HANDLE_VALUE;
- HANDLE openFile(const FileName &path, bool readOnly)
+ inline FileHandle openFile(const FileName &path, bool readOnly)
{
const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE);
else if(!path.str().empty())
return CreateFileA(path.str().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
else
- return INVALID_FILE;
+ return InvalidFileHandle;
}
- size_t fread(void *ptr, size_t size, size_t nmemb, HANDLE stream)
+ inline void closeFile(FileHandle file)
{
- DWORD readLen;
- if(ReadFile(stream, ptr, size * nmemb, &readLen, NULL))
- return (readLen / size);
+ CloseHandle(file);
+ }
+
+ inline size_t readFile(FileHandle file, ByteVector &buffer)
+ {
+ DWORD length;
+ if(ReadFile(file, buffer.data(), static_cast<DWORD>(buffer.size()), &length, NULL))
+ return static_cast<size_t>(length);
else
return 0;
}
- size_t fwrite(const void *ptr, size_t size, size_t nmemb, HANDLE stream)
+ inline size_t writeFile(FileHandle file, const ByteVector &buffer)
{
- DWORD writtenLen;
- if(WriteFile(stream, ptr, size * nmemb, &writtenLen, NULL))
- return (writtenLen / size);
+ DWORD length;
+ if(WriteFile(file, buffer.data(), static_cast<DWORD>(buffer.size()), &length, NULL))
+ return static_cast<size_t>(length);
else
return 0;
}
-# if _DEBUG
-
// Convert a string in a local encoding into a UTF-16 string.
// This function should only be used to generate an error message.
}
}
-# endif
-
#else
-# define INVALID_FILE 0
-
struct FileNameHandle : public std::string
{
FileNameHandle(FileName name) : std::string(name) {}
operator FileName () const { return c_str(); }
};
- FILE *openFile(const FileName &path, bool readOnly)
+ typedef FILE* FileHandle;
+ const FileHandle InvalidFileHandle = 0;
+
+ inline FileHandle openFile(const FileName &path, bool readOnly)
{
return fopen(path, readOnly ? "rb" : "rb+");
}
+ inline void closeFile(FileHandle file)
+ {
+ fclose(file);
+ }
+
+ inline size_t readFile(FileHandle file, ByteVector &buffer)
+ {
+ return fread(buffer.data(), sizeof(char), buffer.size(), file);
+ }
+
+ inline size_t writeFile(FileHandle file, const ByteVector &buffer)
+ {
+ return fwrite(buffer.data(), sizeof(char), buffer.size(), file);
+ }
+
#endif
}
class FileStream::FileStreamPrivate
{
public:
- FileStreamPrivate(const FileName &fileName, bool openReadOnly);
-
-#ifdef _WIN32
-
- HANDLE file;
-
-#else
-
- FILE *file;
-
-#endif
+ FileStreamPrivate(const FileName &fileName, bool openReadOnly)
+ : file(InvalidFileHandle)
+ , name(fileName)
+ , readOnly(openReadOnly)
+ , size(0)
+ {
+ }
+ FileHandle file;
FileNameHandle name;
-
bool readOnly;
ulong size;
+
static const uint bufferSize = 1024;
};
-FileStream::FileStreamPrivate::FileStreamPrivate(const FileName &fileName, bool openReadOnly) :
- file(INVALID_FILE),
- name(fileName),
- readOnly(true),
- size(0)
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+FileStream::FileStream(FileName file, bool openReadOnly)
+ : d(new FileStreamPrivate(file, openReadOnly))
{
// First try with read / write mode, if that fails, fall back to read only.
if(!openReadOnly)
- file = openFile(name, false);
+ d->file = openFile(file, false);
- if(file != INVALID_FILE)
- readOnly = false;
+ if(d->file != InvalidFileHandle)
+ d->readOnly = false;
else
- file = openFile(name, true);
+ d->file = openFile(d->name, true);
- if(file == INVALID_FILE)
+ if(d->file == InvalidFileHandle)
{
# ifdef _WIN32
-
- debug("Could not open file " + fileNameToString(name));
-
+ debug("Could not open file " + fileNameToString(d->name));
# else
-
- debug("Could not open file " + String((const char *) name));
-
+ debug("Could not open file " + String(static_cast<const char *>(d->name)));
# endif
}
}
-////////////////////////////////////////////////////////////////////////////////
-// public members
-////////////////////////////////////////////////////////////////////////////////
-
-FileStream::FileStream(FileName file, bool openReadOnly)
- : d(new FileStreamPrivate(file, openReadOnly))
-{
-}
-
FileStream::~FileStream()
{
-#ifdef _WIN32
-
- if(isOpen())
- CloseHandle(d->file);
-
-#else
-
if(isOpen())
- fclose(d->file);
-
-#endif
+ closeFile(d->file);
delete d;
}
if(length == 0)
return ByteVector::null;
- if(length > FileStreamPrivate::bufferSize &&
- length > ulong(FileStream::length()))
- {
- length = FileStream::length();
- }
+ const ulong streamLength = static_cast<ulong>(FileStream::length());
+ if(length > bufferSize() && length > streamLength)
+ length = streamLength;
+
+ ByteVector buffer(static_cast<uint>(length));
- ByteVector v(static_cast<uint>(length));
- const int count = fread(v.data(), sizeof(char), length, d->file);
- v.resize(count);
- return v;
+ const size_t count = readFile(d->file, buffer);
+ buffer.resize(static_cast<uint>(count));
+
+ return buffer;
}
void FileStream::writeBlock(const ByteVector &data)
return;
}
- fwrite(data.data(), sizeof(char), data.size(), d->file);
+ writeFile(d->file, data);
}
void FileStream::insert(const ByteVector &data, ulong start, ulong replace)
return;
}
else if(data.size() < replace) {
- seek(start);
- writeBlock(data);
- removeBlock(start + data.size(), replace - data.size());
- return;
+ 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
long readPosition = start + replace;
long writePosition = start;
- ByteVector buffer;
+ ByteVector buffer = data;
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()) {
-
+ while(true)
+ {
// 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);
+ const size_t bytesRead = readFile(d->file, aboutToOverwrite);
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)
+ if(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();
+ writeBlock(buffer);
- // Make the current buffer the data that we read in the beginning.
+ // We hit the end of the file.
- buffer = aboutToOverwrite;
+ if(bytesRead == 0)
+ break;
- // 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.
+ writePosition += buffer.size();
- bufferLength = bytesRead;
+ // Make the current buffer the data that we read in the beginning.
+
+ buffer = aboutToOverwrite;
}
}
ByteVector buffer(static_cast<uint>(bufferLength));
- ulong bytesRead = 1;
-
- while(bytesRead != 0) {
+ while(true) {
seek(readPosition);
- bytesRead = fread(buffer.data(), sizeof(char), bufferLength, d->file);
+ const size_t bytesRead = readFile(d->file, buffer);
readPosition += bytesRead;
// Check to see if we just read the last block. We need to call clear()
clear();
seek(writePosition);
- fwrite(buffer.data(), sizeof(char), bytesRead, d->file);
+ writeFile(d->file, buffer);
+
+ if(bytesRead == 0)
+ break;
+
writePosition += bytesRead;
}
+
truncate(writePosition);
}
bool FileStream::isOpen() const
{
- return (d->file != INVALID_FILE);
+ return (d->file != InvalidFileHandle);
}
void FileStream::seek(long offset, Position p)