mkvtoolnix/mm_io.cpp

323 lines
5.8 KiB
C++

/*
mkvmerge -- utility for splicing together matroska files
from component media subtypes
mm_io_c.cpp
Written by Moritz Bunkus <moritz@bunkus.org>
Distributed under the GPL
see the file COPYING for details
or visit http://www.gnu.org/copyleft/gpl.html
*/
/*!
\file
\version $Id$
\brief IO callback class implementation
\author Moritz Bunkus <moritz@bunkus.org>
*/
#include <exception>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(SYS_WINDOWS)
#include <stdarg.h>
#include <w32api/windef.h>
#include <w32api/winbase.h>
#endif // SYS_WINDOWS
#include "mm_io.h"
using namespace std;
#if defined(SYS_UNIX)
mm_io_c::mm_io_c(const char *path, const open_mode mode) {
char *cmode;
switch (mode) {
case MODE_READ:
cmode = "rb";
break;
case MODE_WRITE:
cmode = "wb";
break;
case MODE_CREATE:
cmode = "wb+";
break;
default:
throw 0;
}
file = (FILE *)fopen(path, cmode);
if (file == NULL)
throw exception();
}
mm_io_c::mm_io_c() {
file = NULL;
}
mm_io_c::~mm_io_c() {
close();
}
uint64 mm_io_c::getFilePointer() {
return ftello((FILE *)file);
}
void mm_io_c::setFilePointer(int64 offset, seek_mode mode) {
int whence;
if (mode == seek_beginning)
whence = SEEK_SET;
else if (mode == seek_end)
whence = SEEK_END;
else
whence = SEEK_CUR;
if (fseeko((FILE *)file, offset, whence) != 0)
throw exception();
}
size_t mm_io_c::write(const void *buffer, size_t size) {
size_t bwritten;
bwritten = fwrite(buffer, 1, size, (FILE *)file);
if (ferror((FILE *)file) != 0) {
fprintf(stderr, "Error writing to the output file: %d (%s)\n", errno,
strerror(errno));
exit(1);
}
return bwritten;
}
uint32 mm_io_c::read(void *buffer, size_t size) {
return fread(buffer, 1, size, (FILE *)file);
}
void mm_io_c::close() {
if (file != NULL)
fclose((FILE *)file);
}
bool mm_io_c::eof() {
return feof((FILE *)file) != 0 ? true : false;
}
char *mm_io_c::gets(char *buffer, size_t max_size) {
return fgets(buffer, max_size, (FILE *)file);
}
string mm_io_c::getline() {
char c;
string s;
while (!feof((FILE *)file)) {
if (fread(&c, 1, 1, (FILE *)file) == 1) {
if (c == '\r')
continue;
if (c == '\n')
return s;
s += c;
}
}
return s;
}
#else // SYS_UNIX
mm_io_c::mm_io_c(const char *path, const open_mode mode) {
DWORD access_mode, share_mode, disposition;
switch (mode) {
case MODE_READ:
access_mode = GENERIC_READ;
share_mode = FILE_SHARE_READ;
disposition = OPEN_EXISTING;
break;
case MODE_WRITE:
access_mode = GENERIC_WRITE;
share_mode = 0;
disposition = OPEN_ALWAYS;
break;
case MODE_CREATE:
access_mode = GENERIC_WRITE;
share_mode = 0;
disposition = CREATE_ALWAYS;
break;
default:
throw exception();
}
file = (void *)CreateFile(path, access_mode, share_mode, NULL, disposition,
0, NULL);
if ((HANDLE)file == (HANDLE)0xFFFFFFFF)
throw exception();
}
mm_io_c::mm_io_c() {
file = NULL;
}
mm_io_c::~mm_io_c() {
close();
}
void mm_io_c::close() {
if (file != NULL)
CloseHandle((HANDLE)file);
}
uint64 mm_io_c::getFilePointer() {
LONG dummy = 0;
return SetFilePointer((HANDLE)file, 0, &dummy, FILE_CURRENT);
}
void mm_io_c::setFilePointer(int64 offset, seek_mode mode) {
DWORD method;
LONG high;
switch (mode) {
case seek_beginning:
method = FILE_BEGIN;
break;
case seek_current:
method = FILE_CURRENT;
break;
case seek_end:
method = FILE_END;
break;
}
high = offset >> 32;
SetFilePointer((HANDLE)file, offset & 0xffffffff, &high, method);
}
uint32 mm_io_c::read(void *buffer, size_t size) {
DWORD bytes_read;
if (!ReadFile((HANDLE)file, buffer, size, &bytes_read, NULL))
return 0;
return bytes_read;
}
size_t mm_io_c::write(const void *buffer,size_t size) {
DWORD bytes_written;
if (!WriteFile((HANDLE)file, buffer, size, &bytes_written, NULL))
return 0;
return bytes_written;
}
bool mm_io_c::eof() {
return false;
}
char *mm_io_c::gets(char *buffer, size_t max_size) {
// This will not be fast... But it shouldn't matter. gets is only
// used by the text subtitle readers.
DWORD bytes_read;
int idx;
idx = 0;
do {
if (!ReadFile((HANDLE)file, &buffer[idx], 1, &bytes_read, NULL)) {
if (idx == 0)
return NULL;
else {
if (idx <= max_size)
buffer[idx] = 0;
return buffer;
}
}
if (buffer[idx] == '\n') {
if ((idx + 1) < max_size)
buffer[idx + 1] = 0;
return buffer;
}
idx++;
} while (idx < max_size);
return buffer;
}
string mm_io_c::getline() {
char c;
string s;
DWORD bytes_read;
do {
ReadFile((HANDLE)file, &c, 1, &bytes_read, NULL);
if (bytes_read == 1) {
if (c == '\r')
continue;
if (c == '\n')
return s;
s += c;
}
} while (bytes_read == 1);
return s;
}
#endif
size_t mm_io_c::puts_unl(const char *s) {
int i;
size_t bytes_written;
bytes_written = 0;
for (i = 0; i < strlen(s); i++)
if (s[i] != '\r')
bytes_written += write(&s[i], 1);
return bytes_written;
}
/*
* Dummy class for output to /dev/null. Needed for two pass stuff.
*/
mm_null_io_c::mm_null_io_c() {
pos = 0;
}
uint64 mm_null_io_c::getFilePointer() {
return pos;
}
void mm_null_io_c::setFilePointer(int64 offset, seek_mode mode) {
if (mode == seek_beginning)
pos = offset;
else if (mode == seek_end)
pos = 0;
else
pos += offset;
}
uint32 mm_null_io_c::read(void *buffer, size_t size) {
memset(buffer, 0, size);
pos += size;
return size;
}
size_t mm_null_io_c::write(const void *buffer, size_t size) {
pos += size;
return size;
}
void mm_null_io_c::close() {
}