/* -*- mode: C++; tab-width: 4 -*- */ /* ===================================================================== *\ Copyright (c) 2000-2001 Palm, Inc. or its subsidiaries. All rights reserved. This file is part of the Palm OS Emulator. 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. \* ===================================================================== */ #include #include // --------------------------------------------------------------------------- // ¥ ChunkType::ChunkType // --------------------------------------------------------------------------- EmROMReader::ChunkType::ChunkType(void) { fSize = 0; fSizeAdj = 0; fFree = false; fAddress = 0; fOwner = 0; fHOffset = 0; fLockCount = 0; fHdrSize = 0; recordNumber = 0; type = typeOther; dbNumber = 0; } // --------------------------------------------------------------------------- // ¥ ChunkType::ChunkType // --------------------------------------------------------------------------- EmROMReader::ChunkType::ChunkType(const EmAliasROMHeapChunkHdr2Type& chunk, UInt32 addr) { fPtr = chunk.GetPtr(); fSize = (chunk.long1 >> 0) & 0x00FFFFFFU; if (fSize == 0) { fFree = 0; fSizeAdj = 0; fLockCount = 0; fOwner = 0; fHdrSize = 0; fAddress = 0; } else { fFree = (chunk.long1 >> 31) & 0x0001; fSizeAdj = (chunk.long1 >> 24) & 0x000F; fLockCount = (chunk.long2 >> 28) & 0x000F; fHOffset = (chunk.long2 >> 0) & 0x00FFFFFFU; fOwner = (chunk.long2 >> 24) & 0x000F; fHdrSize = chunk.GetSize(); fAddress = addr + fHdrSize; } recordNumber = 0; dbNumber = 0; type = fFree ? typeFree : typeOther; } // --------------------------------------------------------------------------- // ¥ ChunkType::ChunkType // --------------------------------------------------------------------------- EmROMReader::ChunkType::ChunkType(const EmAliasROMHeapChunkHdr1Type& chunk, UInt32 addr) { fPtr = chunk.GetPtr(); fSize = chunk.size; if (fSize == 0) { fFree = 0; fSizeAdj = 0; fLockCount = 0; fOwner = 0; fHdrSize = 0; fAddress = 0; } else { fFree = !!(chunk.flags & 0x80); fSizeAdj = chunk.flags & 0x0F; fLockCount = chunk.lockOwner >> 4; fHOffset = chunk.hOffset; fOwner = chunk.lockOwner & 0x0F; fHdrSize = chunk.GetSize(); fAddress = addr + fHdrSize; } recordNumber = 0; dbNumber = 0; type = fFree ? typeFree : typeOther; } #pragma mark - // --------------------------------------------------------------------------- // ¥ DatabaseItemType::DatabaseItemType // --------------------------------------------------------------------------- EmROMReader::DatabaseItemType::DatabaseItemType(void) { fDeleted = fDirty = fBusy = fSecret = false; fCategory = fType = fID = fChunkLID = 0; fChunk = NULL; } // --------------------------------------------------------------------------- // ¥ DatabaseItemType::DatabaseItemType // --------------------------------------------------------------------------- EmROMReader::DatabaseItemType::DatabaseItemType(const EmAliasROMDBRecordHeader1Type record, EmROMReader* rom) { UInt32 bits = record.recordID; fRecord = true; fDeleted = !!((bits >> 31) & 1); fDirty = !!((bits >> 30) & 1); fBusy = !!((bits >> 29) & 1); fSecret = !!((bits >> 28) & 1); fCategory = (bits >> 24) & 0xF; fID = bits & 0x00FFFFFFU; fType = 0; fChunkLID = record.chunkLID; ChunkList::iterator block = rom->Chunks().find(fChunkLID); if (block != rom->Chunks().end()) fChunk = &block->second; else fChunk = NULL; } // --------------------------------------------------------------------------- // ¥ DatabaseItemType::DatabaseItemType // --------------------------------------------------------------------------- EmROMReader::DatabaseItemType::DatabaseItemType(const EmAliasROMDBResourceHeader1Type resource, EmROMReader* rom) { fRecord = false; fType = resource.type; fID = resource.id; fDeleted = fDirty = fBusy = fSecret = false; fCategory = 0; fChunkLID = resource.chunkLID; ChunkList::iterator block = rom->Chunks().find(fChunkLID); if (block != rom->Chunks().end()) fChunk = &block->second; else fChunk = NULL; } #pragma mark - // --------------------------------------------------------------------------- // ¥ DatabaseType::DatabaseType // --------------------------------------------------------------------------- EmROMReader::DatabaseType::DatabaseType(void) { fAppInfoChunk = fSortInfoChunk = NULL; } // --------------------------------------------------------------------------- // ¥ DatabaseType::DatabaseType // --------------------------------------------------------------------------- EmROMReader::DatabaseType::DatabaseType(ChunkType* hdr, EmROMReader* rom) { int i; if (hdr->Size() < EmAliasROMDBHeader1Type::GetSize()) return; EmAliasROMDBHeader1Type db(hdr->GetPtr()); char name[dmDBNameLength]; A::BlockCopy(name, db.name.GetPtr(), dmDBNameLength); name[dmDBNameLength-1] = '\0'; fName = name; fCreationTime = db.creationTime; fModificationTime = db.modificationTime; fBackupTime = db.backupTime; fType = db.type; fCreator = db.creator; fVersion = db.version; fUniqueIDSeed = db.uniqueIDSeed; fFlags = db.flags; fVersion = db.version; fAppInfoChunk = 0; if (db.appinfoLID != 0) { ChunkList::iterator ai = rom->Chunks().find(db.appinfoLID); if (ai != rom->Chunks().end()) fAppInfoChunk = &ai->second; } fSortInfoChunk = 0; if (db.sortinfoLID != 0) { ChunkList::iterator si = rom->Chunks().find(db.sortinfoLID); if (si != rom->Chunks().end()) fSortInfoChunk = &si->second; } for (i=0; i::GetSize()) return false; EmAliasROMCardHeader5Type cardHdr(fPtr); // Make sure the stack size isn't something ludicrous. if ((cardHdr.initStack == 0) || (cardHdr.initStack > 0x000FFFFFL)) // 1 Meg return false; if (cardHdr.signature != sysCardSignature) return false; // Make sure the header version isn't ludicrous. if ((cardHdr.hdrVersion == 0) || (cardHdr.hdrVersion > 255)) // arbitrary val return false; // Make sure this isn't a "RAM only" card. if (cardHdr.flags & memCardHeaderFlagRAMOnly) return false; char buffer[memMaxNameLen + 1]; fFlag328 = (cardHdr.flags & 0x0010) != 0; fFlagEZ = (cardHdr.flags & 0x0020) != 0; fFlagVZ = (cardHdr.flags & 0x0040) != 0; fFlagSZ = (cardHdr.flags & 0x0080) != 0; fCardVersion = cardHdr.hdrVersion; buffer[memMaxNameLen] = '\0'; A::BlockCopy(buffer, cardHdr.cardName.GetPtr(), memMaxNameLen - 1); fCardName = buffer; A::BlockCopy(buffer, cardHdr.cardManuf.GetPtr(), memMaxNameLen - 1); fCardManuf = buffer; fCompanyID = cardHdr.companyID; fHalID = cardHdr.halID; fRomVersion = cardHdr.romVersionNumber; A::BlockCopy(buffer, cardHdr.romVersionString.GetPtr(), memMaxNameLen - 1); fRomVersionString = buffer; SetCardAddress(GuessCardAddress()); unsigned long bigROM = (fCardVersion < 2) ? 0x3000 : cardHdr.bigrom; if ((fCardAddress & 0x0FFFFF) != (bigROM & 0x0FFFFF)) { /* Whoops, we probably just read a Small ROM. Skip to the probable Big ROM, and continue from there. */ fPtr = A::add(fPtr, bigROM & 0x0FFFFF); fSize -= (bigROM & 0x0FFFFF); return AcquireCardHeader(); } return true; // Card header verified properly } // --------------------------------------------------------------------------- // ¥ EmROMReader::GuessCardAddress // --------------------------------------------------------------------------- UInt32 EmROMReader::GuessCardAddress(void) { EmAliasROMCardHeader5Type cardHdr(fPtr); return (unsigned long)cardHdr.ramlist - 0x200; } // --------------------------------------------------------------------------- // ¥ EmROMReader::SetCardAddress // --------------------------------------------------------------------------- void EmROMReader::SetCardAddress(UInt32 address) { fCardAddress = address; } // --------------------------------------------------------------------------- // ¥ EmROMReader::AcquireROMHeap // --------------------------------------------------------------------------- bool EmROMReader::AcquireROMHeap(void) { // Local IDs cannot be understood without card address if (!fCardAddress) return false; EmAliasROMStoreHeader4Type storeHdr(GetCardStorePtr()); if (storeHdr[1].GetPtr() >= fEndPtr) return false; // Buffer big enough for store header? if (storeHdr.signature != sysStoreSignature) return false; fStoreVersion = storeHdr.version; ptr_type romHeapListPtr = A::add(fPtr, (UInt32)storeHdr.heapAddr-fCardAddress); EmAliasUInt16 romHeapCount(romHeapListPtr); if (romHeapListPtr < fPtr) return false; // Heap list within buffer? if (romHeapCount[1].GetPtr() >= fEndPtr) return false; // Buffer big enough for heap list? EmAliasUInt32 romHeapList(romHeapCount[1].GetPtr()); fChunks.clear(); fDatabases.clear(); fFeatures.clear(); /* Heap arrangements past version 1 will only have a single heap. */ for (int heap=0; heap= fEndPtr) return false; // Buffer big enough for heap list? ptr_type romHeapPtr = A::add(fPtr, (UInt32)romHeapList[heap]-fCardAddress); unsigned long checkSize; if (romHeapPtr < fPtr) return false; // Heap within buffer? EmAliasROMHeapHeader1Type heapHdr1(romHeapPtr); if (heapHdr1.flags & 0x2000) // Version 4 heap { EmAliasROMHeapHeader3Type heapHdr3(romHeapPtr); checkSize = heapHdr3[1].GetSize(); if (heapHdr3[1].GetPtr() >= fEndPtr) return false; // Buffer big enough for heap header? ptr_type chunkPtr = heapHdr3[1].GetPtr(); unsigned long addr = A::diff(chunkPtr, fPtr) + fCardAddress; for (;;) { if (chunkPtr >= fEndPtr) goto fail; EmAliasROMHeapChunkHdr2Type chunkHdr(chunkPtr); ChunkType ct(chunkHdr, addr); if (ct.TotalSize() == 0) break; /* store a ChunkType record mapped by the "local ID" of each chunk */ fChunks[ct.LocalID()] = ct; chunkPtr = A::add(chunkPtr, ct.TotalSize()); addr += ct.TotalSize(); checkSize += ct.TotalSize(); } checkSize += 4; /* zero-length tail "chunk" */ if (checkSize != heapHdr3.size) goto fail; // Double-check of heap size failed // If a free chunk is listed, perform verification if ((UInt32)heapHdr3.freeChunk) { UInt32 freeLID = (UInt32)romHeapList + ((UInt32)heapHdr3.freeChunk * 2) + 8; if (fChunks.find(freeLID) == fChunks.end()) goto fail; // Unable to find "free" chunk if (!fChunks[freeLID].Free()) goto fail; // Supposedly free chunk isn't } } else if (heapHdr1.flags & 0x4000) // Version 3 heap { EmAliasROMHeapHeader3Type heapHdr3(romHeapPtr); checkSize = heapHdr3[1].GetSize(); if (heapHdr3[1].GetPtr() >= fEndPtr) return false; // Buffer big enough for heap header? ptr_type chunkPtr = heapHdr3[1].GetPtr(); unsigned long addr = A::diff(chunkPtr, fPtr) + fCardAddress; for (;;) { if (chunkPtr >= fEndPtr) goto fail; EmAliasROMHeapChunkHdr2Type chunkHdr(chunkPtr); ChunkType ct(chunkHdr, addr); if (ct.TotalSize() == 0) break; /* store a ChunkType record mapped by the "local ID" of each chunk */ fChunks[ct.LocalID()] = ct; chunkPtr = A::add(chunkPtr, ct.TotalSize()); addr += ct.TotalSize(); checkSize += ct.TotalSize(); } checkSize += 4; /* zero-length tail "chunk" */ if (checkSize != heapHdr3.size) goto fail; // Double-check of heap size failed // If a free chunk is listed, perform verification if ((UInt32)heapHdr3.freeChunk) { UInt32 freeLID = (UInt32)romHeapList + ((UInt32)heapHdr3.freeChunk * 2) + 8; if (fChunks.find(freeLID) == fChunks.end()) goto fail; // Unable to find "free" chunk if (!fChunks[freeLID].Free()) goto fail; // Supposedly free chunk isn't } } else if (heapHdr1.flags & 0x8000) // Version 2 heap { EmAliasROMHeapHeader2Type heapHdr2(romHeapPtr); checkSize = heapHdr2[1].GetSize(); if (heapHdr2[1].GetPtr() >= fEndPtr) return false; // Buffer big enough for heap header? ptr_type chunkPtr = heapHdr2[1].GetPtr(); unsigned long addr = A::diff(chunkPtr, fPtr) + fCardAddress; for (;;) { if (chunkPtr >= fEndPtr) goto fail; EmAliasROMHeapChunkHdr2Type chunkHdr(chunkPtr); ChunkType ct(chunkHdr, addr); if (ct.TotalSize() == 0) break; /* store a ChunkType record mapped by the "local ID" of each chunk */ fChunks[ct.LocalID()] = ct; chunkPtr = A::add(chunkPtr, ct.TotalSize()); addr += ct.TotalSize(); checkSize += ct.TotalSize(); } checkSize += 4; /* zero-length tail "chunk" */ if (checkSize != heapHdr2.size) goto fail; // Double-check of heap size failed } else // Version 1 heap { EmAliasROMHeapHeader1Type heapHdr1(romHeapPtr); checkSize = heapHdr1[1].GetSize(); if (heapHdr1[1].GetPtr() >= fEndPtr) return false; // Buffer big enough for heap header? ptr_type chunkPtr = heapHdr1[1].GetPtr(); unsigned long addr = A::diff(chunkPtr, fPtr) + fCardAddress; for (;;) { if (chunkPtr >= fEndPtr) goto fail; EmAliasROMHeapChunkHdr1Type chunkHdr(chunkPtr); ChunkType ct(chunkHdr, addr); if (ct.TotalSize() == 0) break; /* store a ChunkType record mapped by the "local ID" of each chunk */ fChunks[ct.LocalID()] = ct; chunkPtr = A::add(chunkPtr, ct.TotalSize()); addr += ct.TotalSize(); checkSize += ct.TotalSize(); } checkSize += 2; /* zero-length tail "chunk" */ if ((UInt16)(checkSize & 0xFFFF) != (UInt16)heapHdr1.size) goto fail; // Double-check of heap size failed } } // next heap return true; // Sucessfull acquisition fail: fChunks.clear(); return false; // Failure } // --------------------------------------------------------------------------- // ¥ EmROMReader::AcquireDatabases // --------------------------------------------------------------------------- bool EmROMReader::AcquireDatabases(void) { if (fChunks.size() == 0) return false; // Must get chunks first EmAliasROMStoreHeader4Type storeHdr(GetCardStorePtr()); ChunkList::iterator dbHdrChunk = fChunks.find(storeHdr.dbLID); if (dbHdrChunk == fChunks.end()) return false; // Could not find database directory chunk dbHdrChunk->second.type = ChunkType::typeDBTable; fDatabases.clear(); fFeatures.clear(); ptr_type dbHdrPtr = dbHdrChunk->second.GetPtr(); #if LOG_DATABASES_HACK LogAppendMsg ("-----"); #endif for (;;) { EmAliasROMDBDir1Type dbHdr(dbHdrPtr); for (int i=0; isecond.type = ChunkType::typeDBHeader; #if LOG_DATABASES_HACK DatabaseType dbInfo(&dbChunk->second, this); LogAppendMsg ("%s", dbInfo.Name ().c_str ()); #endif fDatabases.push_back(DatabaseType(&dbChunk->second, this)); for (unsigned int j=0; jtype = ChunkType::typeRecord; chunk->dbNumber = i; chunk->recordNumber = j; } } } if (dbHdr.nextTable == 0) break; else { dbHdrChunk = fChunks.find(dbHdr.nextTable); if (dbHdrChunk == fChunks.end()) break; // Could not find database directory chunk dbHdrPtr = dbHdrChunk->second.GetPtr(); } } return true; } // --------------------------------------------------------------------------- // ¥ EmROMReader::AcquireFeatures // --------------------------------------------------------------------------- bool EmROMReader::AcquireFeatures(void) { /* Nothing to see here... */ if (fDatabases.size() == 0) return false; // Must get databases first fFeatures.clear(); DatabaseList::iterator dbiter = fDatabases.begin(); for (; dbiter != fDatabases.end(); dbiter++) { if (dbiter->Creator() == 'psys') { for (DatabaseItemList::iterator iter = dbiter->Items().begin(); iter != dbiter->Items().end(); iter++) { if (iter->Type() == 'feat') { EmAliasROMFtrTableType table(iter->Chunk()->GetPtr()); ptr_type pos = table.creator.GetPtr(); for (int i=0; i creator(pos); int j; for (j=0; jCreator() == 'psys') { for (EmROMReader::DatabaseItemList::iterator jter = iter->Items().begin(); jter != iter->Items().end(); jter++) { if ((jter->Type() == 'Tbsb') && (jter->ID() == 19001)) { fSplashChunk = jter->Chunk(); return true; } } } } return false; } // --------------------------------------------------------------------------- // ¥ EmROMReader::ContainsDB // --------------------------------------------------------------------------- bool EmROMReader::ContainsDB(string dbName) const { for ( EmROMReader::DatabaseList::const_iterator i = fDatabases.begin(); i != fDatabases.end(); i++) { if (i->Name() == dbName) return true; } return false; } // --------------------------------------------------------------------------- // ¥ EmROMReader::Version // --------------------------------------------------------------------------- void EmROMReader::Version( int& major, int& minor, int& fix, int& stage, int& build) const { major = minor = fix = stage = build = 0; FeatureList::const_iterator psys = fFeatures.find('psys'); if (psys == fFeatures.end()) return; map::const_iterator psys_1 = psys->second.find(1); if (psys_1 == psys->second.end()) return; unsigned long ver = psys_1->second; major = (ver >> 24) & 0x00FF; minor = (ver >> 20) & 0x000F; fix = (ver >> 16) & 0x000F; stage = (ver >> 12) & 0x000F; build = (ver >> 0) & 0x0FFF; } // --------------------------------------------------------------------------- // ¥ EmROMReader::Version // --------------------------------------------------------------------------- unsigned long EmROMReader::Version(void) const { int major, minor, fix, state, build; Version(major, minor, fix, state, build); return (major << 16) | (minor << 8) | fix; } // --------------------------------------------------------------------------- // ¥ EmROMReader::IsBitmapColor // --------------------------------------------------------------------------- int EmROMReader::IsBitmapColor (ChunkType& chunk, bool bootScreen) { ptr_type pos = chunk.GetPtr(); if (bootScreen) pos = A::add(pos, 6); for (;;) { if (!chunk.Contains(pos, EmAliasBitmapTypeV2::GetSize())) return -1; EmAliasBitmapTypeV2 bitmap(pos); if (bitmap.pixelSize >= 8) return 1; if (!bitmap.nextDepthOffset) break; unsigned long offset = bitmap.nextDepthOffset; pos = A::add(pos, offset * 4); } return 0; }