/* * CiderPress * Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved. * See the file LICENSE for distribution terms. */ /* * DreamGrafix super-hi-res conversions. * * Based on code provided by Jason Andersen. */ #include "StdAfx.h" #include "SuperHiRes.h" /* * ========================================================================== * ReformatDG256SHR * ========================================================================== */ /* * Decide whether or not we want to handle this file. */ void ReformatDG256SHR::Examine(ReformatHolder* pHolder) { ReformatHolder::ReformatApplies applies = ReformatHolder::kApplicNot; if (fDG.ScanDreamGrafix(pHolder) && fDG.fNumColors == 256) applies = ReformatHolder::kApplicYes; pHolder->SetApplic(ReformatHolder::kReformatSHR_DG256, applies, ReformatHolder::kApplicNot, ReformatHolder::kApplicNot); } /* * Convert a 256-color DreamGrafix Super Hi-Res Image. */ int ReformatDG256SHR::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcBuf = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); int retval = -1; if (fDG.UnpackDG(srcBuf, srcLen, &fScreen, NULL)) { MyDIBitmap* pDib = SHRScreenToBitmap8(&fScreen); if (pDib != NULL) { SetResultBuffer(pOutput, pDib); retval = 0; } } return retval; } /* * ========================================================================== * ReformatDG3200SHR * ========================================================================== */ /* * Decide whether or not we want to handle this file. */ void ReformatDG3200SHR::Examine(ReformatHolder* pHolder) { ReformatHolder::ReformatApplies applies = ReformatHolder::kApplicNot; if (fDG.ScanDreamGrafix(pHolder) && fDG.fNumColors == 3200) applies = ReformatHolder::kApplicYes; pHolder->SetApplic(ReformatHolder::kReformatSHR_DG3200, applies, ReformatHolder::kApplicNot, ReformatHolder::kApplicNot); } /* * Convert a 3200-color DreamGrafix Super Hi-Res Image. */ int ReformatDG3200SHR::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcBuf = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); int retval = -1; if (fDG.UnpackDG(srcBuf, srcLen, &fScreen, fExtColorTable)) { MyDIBitmap* pDib = SHR3200ToBitmap24(); if (pDib != NULL) { SetResultBuffer(pOutput, pDib); retval = 0; } } return retval; } /* * ========================================================================== * ReformatDreamGrafix * ========================================================================== */ /* * Examine a DreamGrafix file. This figures out if its any of the * DreamGrafix formats, i.e. 256-color, 3200-color, packed, or unpacked. */ bool DreamGrafix::ScanDreamGrafix(ReformatHolder* pHolder) { long fileType = pHolder->GetFileType(); long auxType = pHolder->GetAuxType(); long fileLen = pHolder->GetSourceLen(ReformatHolder::kPartData); bool relaxed, couldBe; relaxed = pHolder->GetOption(ReformatHolder::kOptRelaxGfxTypeCheck) != 0; couldBe = false; if (fileType == Reformat::kTypePNT && auxType == 0x8005) couldBe = true; // $c0/8005 DG packed else if (fileType == Reformat::kTypePIC && auxType == 0x8003) couldBe = false; // $c1/8003 DG unpacked -- not supported else if (relaxed) { if (fileType == Reformat::kTypeBIN && auxType == 0x8005) couldBe = true; } if (fileLen < 256) couldBe = false; if (!couldBe) return false; const uint8_t* ptr; ptr = pHolder->GetSourceBuf(ReformatHolder::kPartData) + fileLen - kHeaderOffset; if (memcmp(ptr+6, "\x0a""DreamWorld", 11) != 0) return false; fNumColors = (*ptr == 0) ? 256 : 3200; fHeight = Reformat::Get16LE(ptr + 2); fWidth = Reformat::Get16LE(ptr + 4); if (fWidth != 320 || fHeight != 200) { LOGI("ODD: strange height %dx%x in DG", fWidth, fHeight); return false; } return true; } /* * Unpack a DreamGrafix SHR image compressed with LZW. * * Returns true on success, false if the uncompress step failed to produce * exactly 32768+32*200 bytes. */ bool DreamGrafix::UnpackDG(const uint8_t* srcBuf, long srcLen, ReformatSHR::SHRScreen* pScreen, uint8_t* extColorTable) { int expectedLen; uint8_t* tmpBuf; int actual; if (extColorTable == NULL) { /* * 32000 for pixels (320*200*0.5 bytes) * 256 for SCB (200 + 56 unused) * 512 for basic palette (16 sets * 16 colors * 2 bytes)\ * 512 optional/unused? */ expectedLen = 33280; } else { /* * 32000 for pixels (320*200*0.5 bytes) * 6400 for palette (200 lines * 16 entries * 2 bytes) * 512 optional/unused? */ expectedLen = 38912; } /* over-alloc -- our LZW decoder doesn't check often */ tmpBuf = new uint8_t[expectedLen + 1024]; if (tmpBuf == NULL) return false; actual = UnpackLZW(srcBuf, srcLen, tmpBuf, expectedLen); if (actual != expectedLen && actual != (expectedLen-512)) { LOGW("UnpackLZW expected %d, got %d", expectedLen, actual); delete[] tmpBuf; return false; } memcpy(pScreen->pixels, tmpBuf, 32000); if (extColorTable == NULL) { memcpy(pScreen->scb, tmpBuf + 32000, 256); memcpy(pScreen->colorTable, tmpBuf + 32256, 512); } else { const uint16_t* pSrcTable; uint16_t* pDstTable; pSrcTable = (const uint16_t*) (tmpBuf + 32000); pDstTable = (uint16_t*) extColorTable; int table; for (table = 0; table < ReformatSHR::kNumLines; table++) { int entry; for (entry = 0; entry < ReformatSHR::kNumEntriesPerColorTable; entry++) { pDstTable[(ReformatSHR::kNumEntriesPerColorTable-1) - entry] = *pSrcTable++; } pDstTable += ReformatSHR::kNumEntriesPerColorTable; } } delete[] tmpBuf; return true; } /* * Constants for LZW. */ static const int kClearCode = 256; static const int kEofCode = 257; static const int kFirstFreeCode = 258; static const unsigned int bitMasks[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1ff, 0x3ff, 0x7ff, 0xfff }; /* initialize the table */ #define INIT_TABLE() { \ nBitMod1 = 9; \ nBitMask = bitMasks[nBitMod1]; \ maxCode = 1 << nBitMod1; \ freeCode = kFirstFreeCode; \ }; /* add a new code to our data structure */ #define ADD_CODE() { \ hashChar[freeCode] = k; \ hashNext[freeCode] = oldCode; \ freeCode++; \ }; /* read the next code and put the value into iCode */ #define READ_CODE() { \ int bit_idx = bitOffset & 0x7; \ int byte_idx = bitOffset >> 3; \ \ iCode = srcBuf[ byte_idx ]; \ iCode &= 0xFF; \ iCode |= (srcBuf[ byte_idx+1 ]<<8); \ iCode &= 0xFFFF; \ iCode |= (srcBuf[ byte_idx+2 ]<<16); \ iCode >>= bit_idx; \ iCode &= nBitMask; \ bitOffset += nBitMod1; \ }; /*static*/ int DreamGrafix::UnpackLZW(const uint8_t* srcBuf, long srcLen, uint8_t* dstBuf, long dstLen) { uint16_t finChar, oldCode, inCode, freeCode, maxCode, k; uint16_t nBitMod1, nBitMask; int bitOffset; uint16_t hashNext[4096]; uint16_t hashChar[4096]; uint8_t* pOrigDst = dstBuf; int iCode; uint16_t stack[32768]; int stackIdx = 0; /* initialize table and code reader */ INIT_TABLE(); bitOffset = 0; while (true) { if (dstBuf - pOrigDst > dstLen) { LOGI("LZW overrun"); return -1; } int A; int Y; READ_CODE(); if (iCode == kEofCode) { break; } if (iCode == kClearCode) { // Got Clear INIT_TABLE(); READ_CODE(); oldCode = iCode; k = iCode; finChar = iCode; *dstBuf++ = (uint8_t) iCode; continue; } A = inCode = iCode; if (iCode < freeCode) { goto inTable; } stack[stackIdx] = finChar; stackIdx++; A = oldCode; inTable: if (A < 256) { goto gotChar; } while (A >= 256) { Y = A; A = hashChar[Y]; stack[stackIdx] = A; stackIdx++; A = hashNext[Y]; } gotChar: A &= 0xFF; finChar = A; k = A; Y = 0; dstBuf[Y++] = A; while (stackIdx) { stackIdx--; A = stack[stackIdx]; dstBuf[Y++] = A; } dstBuf += Y; ADD_CODE(); oldCode = inCode; if (freeCode < maxCode) { continue; // goto nextCode; } if (12 == nBitMod1) { continue; // goto nextCode; } nBitMod1++; nBitMask = bitMasks[nBitMod1]; //printf("nBitMod1 = %d, nBitMask = %04x\n", // nBitMod1, nBitMask); maxCode <<= 1; } return dstBuf - pOrigDst; }