/* * TResourceFile.cc * * Turbo Vision - Version 2.0 * * Copyright (c) 1994 by Borland International * All Rights Reserved. * * Modified by Sergio Sigala * Modified by Max Okumoto */ #define Uses_TResourceFile #define Uses_TResourceItem #define Uses_fpstream #define Uses_TCollection #define Uses_TStringCollection #define Uses_TResourceCollection #include #include #include using std::ios; using std::streampos; /* * SS: Warning, this file is non-portable. It is not used by any of the * classes in the library. */ const long rStreamMagic = 0x52504246uL; // 'FBPR' TResourceFile::TResourceFile( fpstream *aStream ) : TObject(), stream(aStream), basePos(stream->tellp()) { struct Count_type { ushort lastCount; ushort pageCount; }; struct Info_type { ushort infoType; long infoSize; }; struct THeader { ushort signature; union { Count_type count; Info_type info; }; }; streampos streamSize = filelength(*stream); THeader header; int found = 0; int repeat; do { repeat = 0; if (basePos <= (streamSize - (long)sizeof(THeader))) { stream->seekg(basePos, ios::beg); stream->readBytes(&header, sizeof(THeader)); if (header.signature == 0x5a4d) { basePos += ((header.count.pageCount * 512L) - (-header.count.lastCount & 511)); repeat = 1; } else if (header.signature == 0x4246) { if (header.info.infoType == 0x5250) found = 1; else { basePos += header.info.infoSize + 16 - (header.info.infoSize)%16; repeat = 1; } } } } while (repeat); if (found) { stream->seekg(basePos + sizeof(long) * 2, ios::beg); *stream >> indexPos; stream->seekg(basePos + indexPos, ios::beg); *stream >> index; } else { indexPos = sizeof(long) * 3; index = new TResourceCollection(0, 8); } } TResourceFile::~TResourceFile() { flush(); destroy( (TCollection *)index ); delete stream; } short TResourceFile::count() { return index->getCount(); } void TResourceFile::remove( const char *key ) { int i; if (index->search( (char *)key, i)) { index->free(index->at(i)); modified = True; } } void TResourceFile::flush() { if (modified == True) { stream->seekp(basePos + indexPos, ios::beg); *stream << index; #if 1 assert(0); /* XXX */ #else long lenRez = stream->tellp() - basePos - sizeof(long) * 2; stream->seekp(basePos, ios::beg); *stream << rStreamMagic; *stream << lenRez; #endif *stream << indexPos; stream->flush(); modified = False; } } void *TResourceFile::get( const char *key) { int i; void *p; if (! index->search((char *)key, i)) return 0; stream->seekg(basePos + ((TResourceItem*)(index->at(i)))->pos, ios::beg); *stream >> p; return p; } const char *TResourceFile::keyAt(short i) { return ((TResourceItem*)(index->at(i)))->key; } void TResourceFile::put(TStreamable *item, const char *key) { int i; TResourceItem *p; if (index->search( (char *)key, i)) p = (TResourceItem*)(index->at(i)); else { p = new TResourceItem; p->key = newStr(key); index->atInsert(i, p); } p->pos = indexPos; stream->seekp(basePos + indexPos, ios::beg); *stream << item; indexPos = stream->tellp() - basePos; p->size = indexPos - p->pos; modified = True; } void copyStream( fpstream* dest, fpstream* src, long n) { const int xferSize=256; char *xferBuf = new char[xferSize]; size_t thisMove; while (n > 0) { if (n > xferSize) thisMove = xferSize; else thisMove = (int)n; src->readBytes(xferBuf, thisMove); dest->writeBytes(xferBuf, thisMove); n -= thisMove; } delete xferBuf; } struct SwitchInfo { fpstream* sourceStream; fpstream* destStream; long oldBasePos; long newBasePos; }; void doCopyResource(void* item, void* arg) { SwitchInfo* si = (SwitchInfo*)arg; si->sourceStream->seekg(si->oldBasePos + ((TResourceItem*)item)->pos); ((TResourceItem*)item)->pos = si->destStream->tellp() - si->newBasePos; copyStream( si->destStream, si->sourceStream, ((TResourceItem*)item)->size); } fpstream* TResourceFile::switchTo( fpstream *aStream, Boolean pack ) { SwitchInfo args; args.newBasePos = aStream->tellp(); args.oldBasePos = basePos; if (pack) { args.sourceStream = stream; args.destStream = aStream; aStream->seekp( args.newBasePos + sizeof(long)*3); index->forEach(doCopyResource, &args); indexPos = aStream->tellp() - args.newBasePos; } else { stream->seekg(basePos); copyStream(aStream, stream, indexPos); } modified = True; basePos = args.newBasePos; fpstream* oldStream = stream; stream = aStream; return oldStream; }