diff options
Diffstat (limited to 'lib/dvdabstract.cpp')
-rw-r--r-- | lib/dvdabstract.cpp | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/lib/dvdabstract.cpp b/lib/dvdabstract.cpp new file mode 100644 index 0000000..582ad90 --- /dev/null +++ b/lib/dvdabstract.cpp @@ -0,0 +1,161 @@ +/* + * PSX-Tools Bundle Pack + * Copyright (C) 2002-2003 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 + */ + +/* $Id: dvdabstract.cpp,v 1.1 2005-11-02 21:34:02 pixel Exp $ */ + +#include "dvdabstract.h" + +dvdabstract::dvdabstract(Handle * h, int _m) : Handle(-1), r(h), v(h->tell()), m(_m) { +} + +off_t dvdabstract::seek(off_t offset, int wheel) throw (GeneralException) { + switch (wheel) { + case SEEK_SET: + v = offset; + break; + case SEEK_CUR: + v += offset; + break; + case SEEK_END: + throw IOGeneral("Can't seek from the end of the dvdabstract..."); + } +} + +off_t dvdabstract::tell() const { + return v; +} + +ssize_t dvdabstract::read(void * _buf, size_t count) throw (GeneralException) { + char i_buf[2352], * buf = (char *) _buf; + int sector, start, reminder, i_count; + + if (!count) return 0; + + sector = v / 2352; + start = v % 2352; + + read_sector(i_buf, sector); + + if ((start + count) < 2352) { + memcpy(buf, i_buf + start, count); + return count; + } + + reminder = 2352 - start; + memcpy(buf, i_buf + start, reminder); + sector++; + i_count = count - reminder; + buf += reminder; + + while (i_count >= 2352) { + read_sector(buf, sector); + i_count -= 2352; + sector++; + buf += 2352; + } + + reminder = i_count; + + if (reminder >= 0) { + read_sector(i_buf, sector); + memcpy(buf, i_buf, reminder); + } + + return count; +} + +ssize_t dvdabstract::write(const void * _buf, size_t count) throw (GeneralException) { + char i_buf[2352], * buf = (char *) _buf; + int sector, start, reminder, i_count; + + if (!count) return 0; + + sector = v / 2352; + start = v % 2352; + + memcpy(i_buf + start, buf, 2352 - start); + if (start >= 16) { + i_buf[15] = m; + if (m == MODE2_FORM1) { + i_buf[18] = i_buf[22] = 1; + } + } + write_sector(i_buf, sector); + + if ((start + count) < 2352) { + return count; + } + + reminder = 2352 - start; + sector++; + i_count = count - reminder; + buf += reminder; + + while (i_count >= 2352) { + write_sector(buf, sector); + i_count -= 2352; + sector++; + buf += 2352; + } + + reminder = i_count; + memcpy(i_buf, buf, reminder); + if (reminder >= 0) { + memcpy(buf, i_buf, reminder); + if (reminder <= 22) { + if (reminder <= 15) { + i_buf[15] = m; + if (m == MODE2_FORM1) { + i_buf[18] = i_buf[22] = 1; + } + } else if (i_buf[15] == MODE2_FORM1) { + i_buf[18] = i_buf[22] = 1; + } + } + write_sector(i_buf, sector); + } + + return count; +} + +void dvdabstract::read_sector(char * buf, int sector) { + r->seek(sector * 2048); + r->read(buf + 16, 2048); + buf[0] = buf[11] = 0; + buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = buf[7] = buf[8] = buf[9] = buf[10] = -1; + buf[12] = buf[13] = buf[14] = 0; + buf[15] = 1; +} + +void dvdabstract::write_sector(const char * buf, int sector) throw (GeneralException) { + r->seek(sector * 2048); + switch(buf[15]) { + case 0: + case 1: + r->write(buf + 16, 2048); + break; + case 2: + if ((buf[18] == 1) && (buf[22] == 1)) { + r->write(buf + 24, 2048); + break; + } + default: + throw GeneralException("dvdabstract::write_sector: unknown sector mode."); + } +} |