/* * 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.4 2006-02-02 14:09:49 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..."); default: throw IOGeneral("Invalid seek wheel."); } return v; } 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); v += 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; v += 2352; } reminder = i_count; if (reminder >= 0) { read_sector(i_buf, sector); memcpy(buf, i_buf, reminder); v += 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) { if (sector > 913000) printm(M_BARE, "sector %i.\n", sector); r->seek(sector * 2048); switch(buf[15]) { case 0: case 1: r->write(buf + 16, 2048); break; case 2: if (((buf[18] & 8) && (buf[22] & 8)) || (!buf[16] && !buf[17] && !buf[18] && !buf[19] && !buf[20] && !buf[21] && !buf[22] && !buf[23])) { r->write(buf + 24, 2048); break; } default: throw GeneralException("dvdabstract::write_sector: unknown sector mode."); } }