From f66e6dc084e365983de8dd29b3e83d515bc2f895 Mon Sep 17 00:00:00 2001 From: pixel Date: Thu, 4 Dec 2003 00:57:34 +0000 Subject: Completed the isobuilder class, and fixed stuff in the other iso code. --- lib/cdabstract.cpp | 8 +- lib/cdreader.cpp | 140 +++++++++- lib/cdutils.cpp | 234 +++++++++++++++- lib/isobuilder.cpp | 781 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1135 insertions(+), 28 deletions(-) create mode 100644 lib/isobuilder.cpp (limited to 'lib') diff --git a/lib/cdabstract.cpp b/lib/cdabstract.cpp index ce22fad..d7cf18e 100644 --- a/lib/cdabstract.cpp +++ b/lib/cdabstract.cpp @@ -25,7 +25,7 @@ bool cdabstract::canprobe() { #ifdef __linux__ return true; #endif -#if defined (_MSC_VER) || defined (_MINGW32) +#ifdef _WIN32 OSVERSIONINFO ov; memset(&ov, 0, sizeof(OSVERSIONINFO)); ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); @@ -61,7 +61,7 @@ std::vector cdabstract::probe() throw (GeneralException) { } #endif -#if defined (_MSC_VER) || defined (__MINGW32__) +#ifdef _WIN32 for (i = 'A'; i <= 'Z'; i++) { probed.set("%c:\\", i); if (subprobe(probed)) @@ -72,7 +72,7 @@ std::vector cdabstract::probe() throw (GeneralException) { return r; } -#if defined (_MSC_VER) || defined (__MINGW32__) +#ifdef _WIN32 HANDLE cdabstract::OpenIOCTLFile(char cLetter) { HANDLE hF; char szFName[16]; @@ -151,7 +151,7 @@ bool cdabstract::subprobe(String & probed) { } #endif -#if defined (_MSC_VER) || defined (__MINGW32__) +#ifdef _WIN32 int iDA, iDT, iDL; char letter[4]; HANDLE h; diff --git a/lib/cdreader.cpp b/lib/cdreader.cpp index d3d315f..5507588 100644 --- a/lib/cdreader.cpp +++ b/lib/cdreader.cpp @@ -14,6 +14,9 @@ #endif #include "cdabstract.h" +#define nsectorsarow 1 +#define cachesize 2048 + bool cdreader::CanWrite() const { return 0; } @@ -57,7 +60,7 @@ ssize_t cdreader::read(void *buf, size_t count) throw (GeneralException) { while (count > 0) { size_t n = MIN(2352 - remain, count); - getsector(sector); + fetchsector(sector); bcopy(sector + remain, buf, n); buf = ((char *) buf) + n; itell += n; @@ -72,6 +75,94 @@ void cdreader::sectorseek(int sec) { sector = sec; } +void cdreader::fetchsector(void * buf, int sec) { + if (sec >= 0) + sector = sec; + + if (sectors[sector]) { + actualize(sectors[sector]); + memcpy(buf, sectors[sector]->sector, 2352); + return; + } + + Byte buffers[2352 * nsectorsarow]; + + getsector(buffers, sec = sector, nsectorsarow); + + for (int i = nsectorsarow - 1; i >= 0; i--) { + introduce(buffers + i * 2352, sec + i); + } + + memcpy(buf, buffers, 2352); + + while (nsectors > cachesize) { + removetail(); + } +} + +cdreader::~cdreader() { + while (nsectors) { + removetail(); + } +} + +void cdreader::removetail() { + void * t = (void *) tail; + if (!tail) + return; + + sectors[tail->n] = 0; + + if (head == tail) { + free(t); + head = tail = 0; + nsectors = 0; + } else { + cachedsector * p; + (p = tail->prev)->next = 0; + free(t); + tail = p; + nsectors--; + } +} + +void cdreader::actualize(cachedsector * s) { + if (s == head) + return; + + if (s != tail) { + s->next->prev = s->prev; + } else { + tail = s->prev; + } + s->prev->next = s->next; + + head->prev = s; + s->prev = 0; + s->next = head; + head = s; +} + +void cdreader::introduce(Byte * datas, int n) { + cachedsector * s; + + s = (cachedsector *) malloc(sizeof(cachedsector)); + memcpy(s->sector, datas, 2352); + s->n = n; + + if (head) { + s->next = head; + head->prev = s; + head = s; + } else { + head = tail = s; + s->prev = s->next = 0; + } + sectors[n] = s; + + nsectors++; +} + #ifdef __linux__ #include #include @@ -94,24 +185,35 @@ cdreader::cdreader(const String & no) throw (GeneralException) : if (!S_ISBLK(s.st_mode)) { throw GeneralException(no + " is not a block device."); } + + for (i = 0; i < 400000; i++) { + sectors[i] = 0; + } + head = tail = 0; + nsectors = 0; } cdreader::cdreader(const cdreader & i) : Handle(i), n(i.n) { + for (i = 0; i < 400000; i++) { + sectors[i] = 0; + } + head = tail = 0; + nsectors = 0; } -void cdreader::getsector(void *buf, int sec) throw (GeneralException) { +void cdreader::getsector(void *buf, int sec, int nb) throw (GeneralException) { struct cdrom_msf * msf = (struct cdrom_msf *) buf; if (sec >= 0) sector = sec; sector += 150; - msf->cdmsf_min0 = sector /CD_SECS /CD_FRAMES; - msf->cdmsf_sec0 = (sector /CD_FRAMES)%CD_SECS; - msf->cdmsf_frame0= sector %CD_FRAMES; - msf->cdmsf_min1 = (sector+1)/CD_SECS /CD_FRAMES; - msf->cdmsf_sec1 = ((sector+1)/CD_FRAMES)%CD_SECS; - msf->cdmsf_frame1= (sector+1)%CD_FRAMES; + msf->cdmsf_min0 = sector /CD_SECS /CD_FRAMES; + msf->cdmsf_sec0 = (sector /CD_FRAMES)%CD_SECS; + msf->cdmsf_frame0= sector %CD_FRAMES; + msf->cdmsf_min1 = (sector + nb)/CD_SECS /CD_FRAMES; + msf->cdmsf_sec1 = ((sector + nb)/CD_FRAMES)%CD_SECS; + msf->cdmsf_frame1= (sector + nb)%CD_FRAMES; sector -= 150; @@ -119,7 +221,7 @@ void cdreader::getsector(void *buf, int sec) throw (GeneralException) { throw GeneralException(String("unable to read cd sector ") + sector + ": " + strerror(errno)); } - sector++; + sector += nb; } #endif @@ -128,10 +230,20 @@ cdreader::cdreader(const String & no) throw (GeneralException) : Handle(-1), n(no), sector(0) { if (!(hFile = cdabstract::OpenIOCTLFile(no[0]))) throw GeneralException("Error opening device " + no); + for (int i = 0; i < 400000; i++) { + sectors[i] = 0; + } + head = tail = 0; + nsectors = 0; } cdreader::cdreader(const cdreader & i) : Handle(i), n(i.n) { - hFile = i.hFile; + hFile = i.hFile; + for (int x = 0; x < 400000; x++) { + sectors[x] = 0; + } + head = tail = 0; + nsectors = 0; } void cdreader::close() throw (GeneralException) { @@ -150,7 +262,7 @@ typedef struct _RAW_READ_INFO { TRACK_MODE_TYPE TrackMode; } RAW_READ_INFO, *PRAW_READ_INFO; -void cdreader::getsector(void *buf, int sec) throw (GeneralException) { +void cdreader::getsector(void *buf, int sec, int nb) throw (GeneralException) { RAW_READ_INFO rawIOCTL; DWORD dwRet; BOOL bStat; @@ -159,14 +271,14 @@ void cdreader::getsector(void *buf, int sec) throw (GeneralException) { sector = sec; rawIOCTL.DiskOffset.QuadPart = sector * 2048; - rawIOCTL.SectorCount = 1; + rawIOCTL.SectorCount = nb; rawIOCTL.TrackMode = YellowMode2; while (!done) { SetLastError(0); bStat = DeviceIoControl(hFile, IOCTL_CDROM_RAW_READ, &rawIOCTL, sizeof(RAW_READ_INFO), - buf, 2352, &dwRet, NULL); + buf, 2352 * nb, &dwRet, NULL); if (!bStat) { DWORD dwErrCode = GetLastError(); if (dwErrCode == ERROR_INVALID_FUNCTION) { @@ -192,6 +304,8 @@ void cdreader::getsector(void *buf, int sec) throw (GeneralException) { done = true; } } + + sector += nb; } #endif diff --git a/lib/cdutils.cpp b/lib/cdutils.cpp index 413f95d..b3468e7 100644 --- a/lib/cdutils.cpp +++ b/lib/cdutils.cpp @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* $Id: cdutils.cpp,v 1.15 2003-11-25 01:55:45 pixel Exp $ */ +/* $Id: cdutils.cpp,v 1.16 2003-12-04 00:57:35 pixel Exp $ */ #include #include @@ -31,11 +31,14 @@ const long sec_sizes[7] = {0, 2048, 2336, 2048, 2324, 2352, 2352}; const long sec_offsts[7] = {0, 16, 16, 24, 24, 0, 0}; const String sec_modes[7] = {"MODE 0 (empty)", "MODE 1", "MODE 2", "MODE 2 FORM 1", "MODE 2 FORM 2", "Raw", "Autodetect"}; -cdutils::cdutils(Handle * r, Handle * w) : f_iso_r(r), f_iso_w(w), ppf_file(0), pt1(-1), pt2(-1), snum(0), ptl(0), root(0) {} +cdutils::cdutils(Handle * r, Handle * w) : rootDir(0), f_iso_r(r), f_iso_w(w), ppf_file(0), pt1(-1), pt2(-1), snum(0), ptl(0), root(0) {} cdutils::~cdutils() { if (ppf_file) delete ppf_file; + void * t = rootDir; + free(t); + rootDir = 0; } unsigned char cdutils::from_BCD(unsigned char x) { @@ -328,12 +331,13 @@ void cdutils::write_file(Handle * file, int type, int number) { } void cdutils::show_head_entry(void) { - printm(M_BARE, "Sector - Size - Date - Time - Flags - Name\n"); + printm(M_BARE, "Sector Size Date Time Flags Name XA flags\n"); } int cdutils::show_entry(struct DirEntry * dir) { - char pbuf[200]; - if (!dir->R) { + char pbuf[200], pad; + int s; + if ((!dir) || (!dir->R)) { return 1; } @@ -346,10 +350,32 @@ int cdutils::show_entry(struct DirEntry * dir) { strcpy(pbuf, ".."); } + s = 33 + dir->N; + if (s & 1) { + s++; + pad = 1; + } else { + pad = 0; + } + if (s != dir->R) { + if ((s + 14) == dir->R) { + Byte * p; + p = (Byte *) dir->id + dir->N + pad; + if ((p[6] == 'X') && (p[7] == 'A')) { + sprintf(pbuf, "%-14s %c%c%c%c%c", pbuf, + p[4] & 0x80 ? 'd' : '-', + p[4] & 0x40 ? 'a' : '-', + p[4] & 0x20 ? 's' : '-', + p[4] & 0x10 ? 'x' : '-', + p[4] & 0x08 ? 'f' : '-'); + } + } + } + if (dir->Year < 70) dir->Year += 100; - printm(M_BARE, "%6i - %8i - %2i/%02i/%04i - %2i:%02i:%02i%+03.1f - %c%c%c%c%c%c%c%c - %s\n", + printm(M_BARE, "%6i %9i %2i/%02i/%04i %2i:%02i:%02i%+03.1f %c%c%c%c%c%c%c%c %s\n", dir->Sector, dir->Size, dir->Day, dir->Month, dir->Year + 1900, dir->Hour, dir->Minute, dir->Second, ((float) dir->Offset) / 4, dir->Flags & 1 ? 'H' : '-', dir->Flags & 2 ? 'D' : '-', dir->Flags & 4 ? 'A' : '-', dir->Flags & 8 ? 'R' : '-', dir->Flags & 16 ? 'P' : '-', dir->Flags & 32 ? '1' : '-', dir->Flags & 64 ? '1' : '-', dir->Flags & 128 ? 'C' : '-', pbuf); @@ -432,9 +458,11 @@ struct cdutils::DirEntry * cdutils::find_dir_entry(Byte ** bufout, struct cdutil } if (rdir->R) { + free(*bufout); *bufout = buffer; } else { free(buffer); + rdir = 0; } return rdir; } @@ -512,9 +540,10 @@ int cdutils::show_iso_infos() { } int cdutils::get_iso_infos() { - unsigned char buffer[2048]; + Byte buffer[2048]; char pbuff[130]; short int s, nogood = 0; + int rootsec; read_sector(buffer, GUESS, 16); @@ -535,7 +564,10 @@ int cdutils::get_iso_infos() { pt2 = *((short int *) &(buffer[144])); snum = *((int *) &(buffer[80])); ptl = *((long int *) &(buffer[132])); - rootDir = *((struct DirEntry *) &(buffer[156])); + rootsec = ((struct DirEntry *) (&buffer[156]))->Sector; + read_sector(buffer, GUESS, rootsec); + rootDir = (struct DirEntry *) malloc(buffer[0]); + memcpy(rootDir, buffer, buffer[0]); return 1; } @@ -615,7 +647,7 @@ struct cdutils::DirEntry cdutils::find_path(String path) { if (!**pts) pts++; - for (dir = rootDir; *pts; pts++) { + for (dir = *rootDir; *pts; pts++) { if (!strlen(*pts)) continue; dir = find_dir_entry(&dir, *pts); @@ -639,7 +671,7 @@ struct cdutils::DirEntry cdutils::find_parent(String path) { } if (!*newpath) { free(newpath); - return rootDir; + return *rootDir; } pts = split(newpath, '/'); @@ -658,7 +690,7 @@ struct cdutils::DirEntry cdutils::find_parent(String path) { if (!**pts) pts++; - for (dir = rootDir; *pts; pts++) { + for (dir = *rootDir; *pts; pts++) { if (!strlen(*pts)) continue; dir = find_dir_entry(&dir, *pts); @@ -671,3 +703,183 @@ struct cdutils::DirEntry cdutils::find_parent(String path) { free(newpath); return dir; } + +struct cdutils::DirEntry * cdutils::find_path(Byte ** bufout, String path) { + char * newpath = path.strdup(); + char ** pts = split(newpath, '/'); + struct DirEntry * dir; + + *bufout = 0; + + if ((pt1 <= 0) && (pt2 <= 0)) + if (!get_iso_infos()) { + free(newpath); + return 0; + } + + if ((!pt1) & (!pt2)) { + printm(M_ERROR, "No path table defined.\n"); + free(newpath); + return 0; + } + + if (!**pts) + pts++; + + for (dir = rootDir; *pts; pts++) { + if (!strlen(*pts)) + continue; + dir = find_dir_entry(bufout, dir, *pts); + if (!dir) { + free(newpath); + free(*bufout); + return 0; + } + } + + if (!dir) { + free(*bufout); + } + + free(newpath); + return dir; +} + +struct cdutils::DirEntry * cdutils::find_parent(Byte ** bufout, String path) { + char * newpath = path.strdup(); + char ** pts, * p; + struct DirEntry * dir; + + *bufout = 0; + + if ((p = strchr(newpath, '/'))) { + *p = 0; + } + if (!*newpath) { + free(newpath); + return rootDir; + } + pts = split(newpath, '/'); + + if ((pt1 <= 0) && (pt2 <= 0)) + if (!get_iso_infos()) { + free(newpath); + return 0; + } + + if ((!pt1) & (!pt2)) { + printm(M_ERROR, "No path table defined.\n"); + free(newpath); + return 0; + } + + if (!**pts) + pts++; + + for (dir = rootDir; *pts; pts++) { + free(*bufout); + if (!strlen(*pts)) + continue; + dir = find_dir_entry(bufout, dir, *pts); + if (!dir) { + free(newpath); + return dir; + } + } + + if (!dir) { + free(*bufout); + } + + free(newpath); + return dir; +} + +cdfile::cdfile(cdutils * _cd, const cdutils::DirEntry * d, int _mode) : Handle(-1), cd(_cd), sector(d->Sector), mode(_mode), size(d->Size), name(d->id) { + if (mode == GUESS) { + mode = cd->guess_type(sector); + } + dir = (cdutils::DirEntry *) malloc(d->R); + memcpy(dir, d, d->R); + itell = 0; +} + +cdfile::cdfile(cdutils * _cd, int _sector, ssize_t _size, int _mode) : Handle(-1), cd(_cd), sector(_sector), mode(_mode), size(_size), name("raw reading") { + if (_size == -1) { + size = 0; + } + if (mode == GUESS) { + mode = cd->guess_type(sector); + } + dir = 0; + itell = 0; +} + +cdfile::~cdfile() { + void * t = dir; + free(t); + dir = 0; +} + +ssize_t cdfile::read(void *buf, size_t count) throw (GeneralException) { + Byte buffer[2352]; + size_t startsec, nsec, startbyte, nstartbytes; + + count = MIN(count, (size_t) (size - itell)); + + if (!count) + return 0; + + startsec = itell / sec_sizes[mode] + sector; + startbyte = itell % sec_sizes[mode]; + nstartbytes = sec_sizes[mode] - startbyte; + nstartbytes = MIN(nstartbytes, count); + count -= nstartbytes; + + cd->read_sector(buffer, mode, startsec); + memcpy(buf, buffer + startbyte, nstartbytes); + buf = (Byte *) buf + nstartbytes; + + if (count) { + cd->read_datas((Byte *) buf, mode, startsec + 1, count); + } + + itell += count + nstartbytes; + + return count + nstartbytes; +} + +bool cdfile::CanRead() const { + return true; +} + +String cdfile::GetName() const { + return String("cdfile: ") + name; +} + +bool cdfile::CanWatch() const { + return false; +} + +ssize_t cdfile::GetSize() const { + return size; +} + +bool cdfile::CanSeek() const { + return true; +} + +off_t cdfile::seek(off_t off, int wheel) throw (GeneralException) { + switch (wheel) { + case SEEK_SET: + itell = off; + break; + case SEEK_CUR: + itell += off; + break; + case SEEK_END: + itell = size + off; + break; + } + return itell; +} diff --git a/lib/isobuilder.cpp b/lib/isobuilder.cpp new file mode 100644 index 0000000..469d612 --- /dev/null +++ b/lib/isobuilder.cpp @@ -0,0 +1,781 @@ +#include "isobuilder.h" +void isobuilder::Date::dump(Byte * datas) { + char pbuf[256]; + + sprintf(pbuf, "%04i", year); + memcpy(datas + 0, pbuf, 4); + sprintf(pbuf, "%02i", month); + memcpy(datas + 4, pbuf, 2); + sprintf(pbuf, "%02i", day); + memcpy(datas + 6, pbuf, 2); + sprintf(pbuf, "%02i", hour); + memcpy(datas + 8, pbuf, 2); + sprintf(pbuf, "%02i", minute); + memcpy(datas + 10, pbuf, 2); + sprintf(pbuf, "%02i", second); + memcpy(datas + 12, pbuf, 2); + sprintf(pbuf, "%02i", hundredths); + memcpy(datas + 14, pbuf, 2); + + *((char *) (datas + 16)) = offset; +} + +isobuilder::Date::Date(int) { + year = month = day = hour = minute = second = hundredths = offset = 0; +} + +isobuilder::Date::Date(Byte * datas) { + char pbuf[256]; + char * cdatas = (char *) datas; + + memcpy(pbuf, cdatas + 0, 4); + pbuf[4] = 0; + sscanf(pbuf, "%d", &year); + + memcpy(pbuf, cdatas + 4, 2); + pbuf[2] = 0; + sscanf(pbuf, "%d", &month); + + memcpy(pbuf, cdatas + 6, 2); + pbuf[2] = 0; + sscanf(pbuf, "%d", &day); + + memcpy(pbuf, cdatas + 8, 2); + pbuf[2] = 0; + sscanf(pbuf, "%d", &hour); + + memcpy(pbuf, cdatas + 10, 2); + pbuf[2] = 0; + sscanf(pbuf, "%d", &minute); + + memcpy(pbuf, cdatas + 12, 2); + pbuf[2] = 0; + sscanf(pbuf, "%d", &second); + + memcpy(pbuf, cdatas + 14, 2); + pbuf[2] = 0; + sscanf(pbuf, "%d", &hundredths); + + offset = *(cdatas + 16); +} + +isobuilder::DirTree::DirTree(isobuilder::DirTree * _father, bool _dir) : father(_father), mode(-1), dir(_dir) { + DirTree * p; + + child = brother = 0; + + if (!father) + return; + + creation = father->creation; + + if (father->child) { + for (p = father->child; p->brother; p = p->brother); + p->brother = this; + } else { + father->child = this; + } +} + +isobuilder::DirTree::~DirTree() { + while (child) { + delete child; + } + + if (!father) + return; + + if (father->child == this) { + father->child = brother; + } else { + // Dirty, should not happen. + DirTree * p; + for (p = father->child; p->brother != this; p = p->brother); + p->brother = brother; + } +} + +void isobuilder::DirTree::dumpdirs(isobuilder * builder) throw (GeneralException) { + Byte * dir, * odir; + int cursiz, cursectsize, R; + String oldname; + DirTree * p; + + odir = dir = (Byte *) malloc(cursiz = size); + cursectsize = 2048; + + oldname = name; + name = "."; + R = buildentry(dir, cursectsize); + name = oldname; + cursectsize -= R; + dir += R; + + if (father) { + oldname = father->name; + father->name = ".."; + R = father->buildentry(dir, cursectsize); + father->name = oldname; + } else { + name = ".."; + R = buildentry(dir, cursectsize); + name = "."; + } + + cursectsize -= R; + dir += R; + + for (p = child; p; p = p->brother) { + if (p->dir) { + p->dumpdirs(builder); + } + while (!(R = p->buildentry(dir, cursectsize))) { + cursiz -= 2048; + dir += cursectsize; + cursectsize = 2048; + if (!cursiz) + throw GeneralException("Directory is too small! Entries don't fit."); + } + cursectsize -= R; + dir += R; + } + + builder->putdatas(odir, size, mode, sector); + + free(odir); +} + +int isobuilder::DirTree::buildpath(Byte * datas, int size, bool bigendian) throw (GeneralException) { + int N, r, tr; + Uint16 pn; + char pbuf[256], pad; + + if (!dir) { + if (brother) { + return brother->buildpath(datas, size, bigendian); + } else { + return 0; + } + } + + if (!father) { + numerate(1); + N = 1; + pbuf[0] = 0; + pn = 1; + } else { + N = name.strlen(); + strcpy(pbuf, name.to_charp()); + pn = father->node; + } + + pad = N & 1; + size -= (r = N + pad + 8); + + if (size < 0) + throw GeneralException("Path table too small."); + + datas[0] = N; + datas[1] = 0; + *((Uint32 *) (datas + 2)) = bigendian ? cdutils::swap_dword(sector) : sector; + *((Uint16 *) (datas + 6)) = bigendian ? cdutils::swap_word(pn) : pn; + memcpy(datas + 8, pbuf, N); + if (pad) + datas[8 + N] = 0; + + datas += r; + + if (brother) { + tr = brother->buildpath(datas, size, bigendian); + r += tr; + size -= tr; + datas += tr; + } + + if (child) { + tr = child->buildpath(datas, size, bigendian); + r += tr; + size -= tr; + datas += tr; + } + + return r; +} + +int isobuilder::DirTree::buildentry(Byte * buffer, int spaceleft, bool put_xa) { + int N, R; + char pbuf[256], pad; + Byte * p; + cdutils::DirEntry * d = (cdutils::DirEntry *) buffer; + + put_xa = put_xa && have_xa; + + memset(pbuf, 0, 256); + + if (name == ".") { + N = 1; + pbuf[0] = 0; + } else if (name == "..") { + N = 1; + pbuf[0] = 1; + } else { + strcpy(pbuf, name.to_charp()); + N = name.strlen(); + if (!dir) { + N += 2; + strcat(pbuf, ";1"); + } + } + + R = N + 33; + + if (R & 1) { + R++; + pad = 1; + } else { + pad = 0; + } + + if (put_xa) { + R += 14; + p = (Byte *) pbuf + N + pad; + p[4] = 0x05; + p[5] = 0x55; + p[6] = 'X'; + p[7] = 'A'; + + p[4] |= xa_dir ? 0x80 : 0; + p[4] |= xa_audio ? 0x40 : 0; + p[4] |= xa_str ? 0x20 : 0; + p[4] |= xa_xa ? 0x10 : 0; + p[4] |= xa_form1 ? 0x08 : 0; + } + + if (R > spaceleft) { + return 0; + } + + memset(d, 0, R); + + d->R = R; + d->N = N; + memcpy(d->id, pbuf, N + pad + (put_xa ? 14 : 0)); + + d->Sector = sector; + d->BESector = cdutils::swap_dword(sector); + d->Size = size; + d->BESize = cdutils::swap_dword(size); + d->Year = creation.year - 1900; + d->Month = creation.month; + d->Day = creation.day; + d->Hour = creation.hour; + d->Minute = creation.minute; + d->Second = creation.second; + d->Offset = creation.offset; + d->Flags |= hidden ? 1 : 0; + d->Flags |= dir ? 2 : 0; + + return R; +} + +void isobuilder::DirTree::fromdir(cdutils::DirEntry * d) { + Date t; + char pbuf[200], pad; + int s; + if ((!d) || (!d->R)) { + return; + } + + if ((d->N == 1) && (d->id[0] == 0)) { + name = "."; + } else if ((d->N == 1) && (d->id[0] == 1)) { + name = ".."; + } else { + memcpy(pbuf, d->id, s = (d->N - ((d->Flags & 2) ? 0 : 2))); + pbuf[s] = 0; + name = pbuf; + } + hidden = d->Flags & 1; + if (d->Year < 70) + d->Year += 100; + t.year = d->Year; + t.month = d->Month; + t.day = d->Day; + t.hour = d->Hour; + t.second = d->Second; + t.hundredths = 0; + t.offset = d->Offset; + + s = 33 + d->N; + if (s & 1) { + s++; + pad = 1; + } else { + pad = 0; + } + if (s != d->R) { + if ((s + 14) == d->R) { + Byte * p; + p = (Byte *) d->id + d->N + pad; + if ((p[6] == 'X') && (p[7] == 'A')) { + have_xa = true; + xa_dir = p[4] & 0x80; + xa_audio = p[4] & 0x40; + xa_str = p[4] & 0x20; + xa_xa = p[4] & 0x10; + xa_form1 = p[4] & 0x08; + } + } + } +} + +void isobuilder::DirTree::setbasicsxa() { + have_xa = true; + if (dir) + xa_dir = true; + xa_form1 = true; +} + +int isobuilder::DirTree::numerate(int n) { + DirTree * p; + + if (!dir) { + if (brother) { + return brother->numerate(n); + } else { + return n; + } + } + + node = n++; + + if (brother) + n = brother->numerate(n); + + if (child) + n = child->numerate(n); + + return n; +} + +isobuilder::isobuilder(Handle * _w, int _mode) : w(_w), sector(0), nsectors(0), basics(false), dmode(_mode) { + Byte sect[2352]; + memset(sect, 0, 2352); + + for (int i = 0; i < 16; i++) { + createsector(sect, MODE2, i); + } +} + +isobuilder::~isobuilder() { + if (!closed) + close(); + if (root) + delete root; +} + +void isobuilder::foreword(Handle * forewords, int mode) { + Byte sect[2352]; + for (int i = 0; i < 16; i++) { + forewords->read(sect, sec_sizes[mode]); + createsector(sect, mode, i); + } +} + +void isobuilder::foreword(Byte * forewords, int mode) { + for (int i = 0; i < 16; i++) { + createsector(forewords + i * sec_sizes[mode], mode, i); + } +} + +int isobuilder::getdispsect() { + return lastdispsect; +} + +int isobuilder::putfile(Handle * file, int mode, int n) { + Byte datas[2352]; + size_t filesize; + int fsect; + + if (n >= 0) { + sector = n; + } else { + sector = lastdispsect; + } + + fsect = sector; + + filesize = file->GetSize(); + + while (filesize > 0) { + memset(datas, 0, 2352); + filesize -= file->read(datas, sec_sizes[mode]); + if ((mode == MODE2_FORM1) || (mode == MODE2_FORM2)) { + if (filesize) { + clearEOF(); + } else { + setEOF(); + } + } + createsector(datas, mode); + } + + return fsect; +} + +void isobuilder::putdatas(Byte * _datas, size_t size, int smode, int n) { + Byte datas[2352]; + size_t eating; + if (n >= 0) { + sector = n; + } else { + sector = lastdispsect; + } + + if (smode < 0) + smode = dmode; + + while (size > 0) { + memset(datas, 0, 2352); + eating = MIN(size, (size_t) sec_sizes[smode]); + memcpy(datas, _datas, eating); + size -= eating; + _datas += eating; + if ((smode == MODE2_FORM1) || (smode == MODE2_FORM2)) { + if (size) { + clearEOF(); + } else { + setEOF(); + } + } + createsector(datas, smode); + } +} + +void isobuilder::createsector(Byte * datas, int smode, int n) { + Byte dsector[2352]; + if (n >= 0) + sector = n; + + if (smode < 0) + smode = dmode; + + w->seek(2352 * sector, SEEK_SET); + + memcpy(dsector + sec_offsts[smode], datas, sec_sizes[smode]); + + if ((smode == MODE2_FORM1) || (smode == MODE2_FORM2)) { + // Mode 2 Form 2 would be odd, but well.... + dsector[16] = dsector[20] = 0; // File Number + dsector[17] = dsector[21] = 0; // Channel Number + dsector[18] = dsector[22] = sub_EOR | sub_EOF | 8 | + (smode == MODE2_FORM2 ? 32 : 0); + dsector[19] = dsector[23] = 0; + } + + if (smode != MODE_RAW) { + sector += 150; + yazedc_o.minute = cdutils::to_BCD(sector / 60 / 75); + yazedc_o.second = cdutils::to_BCD((sector / 75) % 60); + yazedc_o.frame = cdutils::to_BCD(sector % 75); + sector -= 150; + yazedc_o.do_encode_L2(dsector, smode, 0); + } + + w->write(dsector, 2352); + + sector++; + + nsectors = MAX(nsectors, sector); + lastdispsect = MAX(lastdispsect, sector); +} + +void isobuilder::setEOF() { + sub_EOF = 128; + sub_EOR = 1; +} + +void isobuilder::clearEOF() { + sub_EOF = sub_EOR = 0; +} + +isobuilder::DirTree * isobuilder::setbasics(PVD _pvd, int _rootsize, int _ptsize, int _nvd) throw (GeneralException) { + if (basics) { + throw GeneralException("Basic ISO structures already set"); + } + basics = true; + + pvd = _pvd; + rootsize = _rootsize; + ptsize = _ptsize; + nvd = _nvd; + + ptsect = 17 + nvd; + rootsect = ptsect + ptsize * 4; + lastdispsect = rootsect + rootsize; + + root = new DirTree(0); + root->name = "."; + root->creation = pvd.volcreat; + root->sector = rootsect; + root->size = rootsize * 2048; + return root; +} + +isobuilder::DirTree * isobuilder::createdir(DirTree * p, const String & _name, int size, cdutils::DirEntry * d, int mode) throw (GeneralException) { + DirTree * r; + + if (!p) + throw GeneralException("Empty father"); + + if (closed) + throw GeneralException("ISO is closed"); + + if (!basics) + throw GeneralException("ISO basis not created (no root!)"); + + r = new DirTree(p); + + r->name = _name; + r->creation = p->creation; + r->fromdir(d); + if (_name != "") + r->name = _name; + r->size = size * 2048; + r->sector = lastdispsect; + r->mode = mode; + + lastdispsect += size; + + return r; +} + +isobuilder::DirTree * isobuilder::createfile(DirTree * p, Handle * file, const String & _name, cdutils::DirEntry * d, int mode) throw (GeneralException) { + DirTree * r; + + if (!p) + throw GeneralException("Empty father"); + + if (closed) + throw GeneralException("ISO is closed"); + + if (!basics) + throw GeneralException("ISO basis not created (no root!)"); + + r = new DirTree(p, false); + + r->name = _name; + r->creation = p->creation; + r->fromdir(d); + if (_name != "") + r->name = _name; + r->size = file->GetSize(); + r->sector = putfile(file, mode); + r->mode = mode; +} + +void isobuilder::copydir(isobuilder::DirTree * r, const String & _name, cdutils * cd, cdutils::DirEntry * d, int mode) { + Byte datas[2048]; + cdutils::DirEntry * p; + int nsectors = d->Size / 2048, ssize, c = 0; + int fsize, osize; + + r->fromdir(d); + if (_name != "") + r->name = _name; + + while (nsectors) { + cd->read_sector(datas, mode, d->Sector + c++); + nsectors--; + p = (cdutils::DirEntry *) datas; + ssize = 2048; + while ((ssize) && (p->R)) { + ssize -= p->R; + char pbuf[256]; + memcpy(pbuf, p->id, p->N); + pbuf[p->N] = 0; + if (p->Flags & 2) { + if (!((p->N == 1) && ((p->id[0] == 0) || (p->id[0] == 1)))) + copydir(createdir(r, "", p->Size / 2048, p, mode), "", cd, p, mode); + } else { + printm(M_INFO, "Dupping %s\n", pbuf); + int fmode; + if (mode == MODE1) { + fmode = mode; + } else { + fmode = MODE2_FORM1; + osize = fsize = p->Size; + int s, pad; + s = 33 + p->N; + if (s & 1) { + s++; + pad = 1; + } else { + pad = 0; + } + if ((s != p->R) && ((s + 14) == p->R)) { + if (!(p->id[p->N + pad + 4] & 8)) { + fmode = MODE2; + fsize = (p->Size / 2048) * 2336; + } + } + } + p->Size = fsize; + createfile(r, &cdfile(cd, p, fmode), "", p, fmode)->size = osize; + p->Size = osize; + } + p = (cdutils::DirEntry *) (((Byte *) p) + p->R); + } + } +} + +isobuilder::PVD isobuilder::createpvd(Handle * f) { + Byte datas[2048]; + f->read(datas, 2048); + return createpvd(datas); +} + +isobuilder::PVD isobuilder::createpvd(cdutils * cd) { + Byte datas[2048]; + cd->read_sector(datas, GUESS, 16); + return createpvd(datas); +} + +isobuilder::PVD isobuilder::createpvd(Byte * buffer) { + PVD r; + char pbuff[256]; + + memcpy(pbuff, buffer + 8, 32); + pbuff[32] = 0; + r.sysid = pbuff; + r.sysid.rtrim(); + memcpy(pbuff, buffer + 40, 32); + pbuff[32] = 0; + r.volid = pbuff; + r.volid.rtrim(); + memcpy(pbuff, buffer + 190, 128); + pbuff[128] = 0; + r.volsetid = pbuff; + r.volsetid.rtrim(); + memcpy(pbuff, buffer + 318, 128); + pbuff[128] = 0; + r.pubid = pbuff; + r.pubid.rtrim(); + memcpy(pbuff, buffer + 446, 128); + pbuff[128] = 0; + r.prepid = pbuff; + r.prepid.rtrim(); + memcpy(pbuff, buffer + 574, 128); + pbuff[128] = 0; + r.appid = pbuff; + r.appid.rtrim(); + memcpy(pbuff, buffer + 702, 37); + pbuff[37] = 0; + r.copyright = pbuff; + r.copyright.rtrim(); + memcpy(pbuff, buffer + 739, 37); + pbuff[37] = 0; + r.abstract = pbuff; + r.abstract.rtrim(); + memcpy(pbuff, buffer + 776, 37); + pbuff[37] = 0; + r.biblio = pbuff; + r.biblio.rtrim(); + + r.volcreat = Date(buffer + 813); + r.modif = Date(buffer + 830); + r.volexp = Date(buffer + 847); + r.voleff = Date(buffer + 864); + + memcpy(r.appdata, buffer + 883, 512); + + return r; +} + +void isobuilder::close(Handle * cue, int mode) throw (GeneralException) { + Byte datas[2048]; + Byte * pdatas; + char * cdatas = (char *) datas; + int psize; + + memset(datas, 0, 2048); + + pdatas = (Byte *) malloc(ptsize * 2048); + psize = root->buildpath(pdatas, ptsize * 2048); + putdatas(pdatas, ptsize * 2048, mode, ptsect); + putdatas(pdatas, ptsize * 2048, mode, ptsect + ptsize); + root->buildpath(pdatas, ptsize * 2048, true); + putdatas(pdatas, ptsize * 2048, mode, ptsect + ptsize * 2); + putdatas(pdatas, ptsize * 2048, mode, ptsect + ptsize * 3); + free(pdatas); + + datas[0] = 1; + datas[1] = 67; + datas[2] = 68; + datas[3] = 48; + datas[4] = 48; + datas[5] = 49; + datas[6] = 1; + datas[7] = 0; + + sprintf(cdatas + 8, "%-32s", pvd.sysid.to_charp()); + sprintf(cdatas + 40, "%-32s", pvd.volid.to_charp()); + *((Uint32 *) (datas + 80)) = nsectors; + *((Uint32 *) (datas + 84)) = cdutils::swap_dword(nsectors); + + datas[120] = 1; + datas[121] = 0; + datas[122] = 0; + datas[123] = 1; + datas[124] = 1; + datas[125] = 0; + datas[126] = 0; + datas[127] = 1; + datas[128] = 0; + datas[129] = 8; + datas[130] = 8; + datas[131] = 0; + *((Uint32 *) (datas + 132)) = psize; + *((Uint32 *) (datas + 136)) = cdutils::swap_dword(psize); + *((Uint32 *) (datas + 140)) = ptsect; + *((Uint32 *) (datas + 144)) = ptsect + ptsize; + *((Uint32 *) (datas + 148)) = cdutils::swap_dword(ptsect + ptsize * 2); + *((Uint32 *) (datas + 152)) = cdutils::swap_dword(ptsect + ptsize * 2); + + root->buildentry(datas + 156, 34, false); + + sprintf(cdatas + 190, "%-128s", pvd.volsetid.to_charp()); + sprintf(cdatas + 318, "%-128s", pvd.pubid.to_charp()); + sprintf(cdatas + 446, "%-128s", pvd.prepid.to_charp()); + sprintf(cdatas + 574, "%-128s", pvd.appid.to_charp()); + sprintf(cdatas + 702, "%-37s", pvd.copyright.to_charp()); + sprintf(cdatas + 739, "%-37s", pvd.appid.to_charp()); + sprintf(cdatas + 776, "%-37s", pvd.biblio.to_charp()); + + pvd.volcreat.dump(datas + 813); + pvd.modif.dump(datas + 830); + pvd.volexp.dump(datas + 847); + pvd.voleff.dump(datas + 864); + + memcpy(datas + 883, pvd.appdata, 512); + + clearEOF(); + sub_EOR = 1; + createsector(datas, mode, 16); + + memset(datas, 0, 2048); + datas[0] =255; + datas[1] = 67; + datas[2] = 68; + datas[3] = 48; + datas[4] = 48; + datas[5] = 49; + datas[6] = 1; + + setEOF(); + createsector(datas, mode); + + root->dumpdirs(this); + + closed = true; +} -- cgit v1.2.3