ciderpress/reformat/DreamGrafix.cpp
Andy McFadden 8f61f84585 Use types with explicit sizes
Much of what the "reformat" code does involves processing data that is
8, 16, or 32 bits.  We want to use size-specific types from stdint.h
(e.g. uint16_t) rather than "unsigned short".

This was a quick pass to replace the various "unsigned" declarations.
More can be done here and elsewhere.
2014-11-20 18:10:18 -08:00

371 lines
10 KiB
C++

/*
* 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)) {
LOGI("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;
}