diff --git a/DIST/with-mdc.deploy b/DIST/with-mdc.deploy index d9eedbc..870b7db 100644 --- a/DIST/with-mdc.deploy +++ b/DIST/with-mdc.deploy @@ -4,8 +4,8 @@ faddenSoft http://www.faddensoft.com/ CiderPress http://a2ciderpress.com/ -4.0.1-a2 -42186 +4.0.1-a3 +42218 C:\DATA\faddenSoft\fs.ico Copyright © 2015 CiderPress project authors. All rights reserved. C:\Src\CiderPress\DIST\ReadMe.txt @@ -355,7 +355,7 @@ FALSE 4095 -Setup401a2.exe +Setup401a3.exe FALSE diff --git a/app/MyApp.h b/app/MyApp.h index 1e51c2f..7a12d00 100644 --- a/app/MyApp.h +++ b/app/MyApp.h @@ -15,7 +15,7 @@ #define kAppMajorVersion 4 #define kAppMinorVersion 0 #define kAppBugVersion 1 -#define kAppDevString L"-a2" +#define kAppDevString L"-a3" /* * Windows application object. diff --git a/reformat/HiRes.cpp b/reformat/HiRes.cpp index 77a0f8c..71d33a0 100644 --- a/reformat/HiRes.cpp +++ b/reformat/HiRes.cpp @@ -55,14 +55,14 @@ * The IIgs monochrome mode is not enabled on the RGB output unless you * turn off AN3 by hitting $c05e (it can be re-enabled by hitting $c05f). * This register turns off the half-pixel shift, so it doesn't appear to - * be possible to view hires output on an RGB monitor with the half-pixel + * be possible to view hi-res output on an RGB monitor with the half-pixel * shift intact. On the composite output, the removal of the half-pixel * shift is quite visible. */ /* * Regarding color... - * [ Fround on http://www.geocities.com/jonrelay/software/a2info/munafo.htm ] + * [ Found on http://www.geocities.com/jonrelay/software/a2info/munafo.htm ] From: munafo@gcctech.com Newsgroups: comp.emulators.apple2,comp.sys.apple2.programmer @@ -117,6 +117,8 @@ pattern colors and the YIQ axis colors are also given. YIQ -I 303 100 50 0 224 231 NTSC blue 347 62 15 38 65 155 + --- + I don't think these are 100% correct, e.g. he only found one value for both grey colors, even though one is noticeably darker than the other on-screen. @@ -143,7 +145,7 @@ The IIgs tech note #63 uses the following for border colors: White $F $0FFF --------------------------------------- -KEGS uses this (rearranged slightly to match the above): +KEGS uses this (rearranged slightly to match the order above): const int g_dbhires_colors[] = { \* rgb *\ 0x000, \* 0x0 black *\ @@ -180,7 +182,8 @@ void ReformatHiRes::Examine(ReformatHolder* pHolder) long fileLen = pHolder->GetSourceLen(ReformatHolder::kPartData); long fileType = pHolder->GetFileType(); long auxType = pHolder->GetAuxType(); - bool dosStructure = (pHolder->GetSourceFormat() == ReformatHolder::kSourceFormatDOS); + bool dosStructure = + (pHolder->GetSourceFormat() == ReformatHolder::kSourceFormatDOS); bool relaxed; relaxed = pHolder->GetOption(ReformatHolder::kOptRelaxGfxTypeCheck) != 0; @@ -193,10 +196,15 @@ void ReformatHiRes::Examine(ReformatHolder* pHolder) applies = ReformatHolder::kApplicProbably; } } else { - if (fileType == kTypeFOT /*&& auxType < 0x4000*/ && - (fileLen >= kExpectedSize-8 && fileLen <= kExpectedSize+1)) - { - applies = ReformatHolder::kApplicProbably; + if (fileType == kTypeFOT) { + if (auxType == 0x8066) { + // fhpack LZ4FH-compressed file + applies = ReformatHolder::kApplicYes; + } else if (fileLen >= kExpectedSize-8 && + fileLen <= kExpectedSize + 1) { + // uncompressed FOT file... probably + applies = ReformatHolder::kApplicProbably; + } } else if (relaxed && fileType == kTypeBIN && (fileLen >= kExpectedSize-8 && fileLen <= kExpectedSize+1)) { @@ -230,8 +238,20 @@ int ReformatHiRes::Process(const ReformatHolder* pHolder, long srcLen = pHolder->GetSourceLen(part); int retval = -1; - if (id == ReformatHolder::kReformatHiRes_BW) + if (id == ReformatHolder::kReformatHiRes_BW) { fBlackWhite = true; + } + + uint8_t expandBuf[kExpectedSize]; + if (pHolder->GetFileType() == kTypeFOT && + pHolder->GetAuxType() == 0x8066) + { + srcLen = ExpandLZ4FH(expandBuf, srcBuf, srcLen); + if (srcLen == 0) { + goto bail; // fail + } + srcBuf = expandBuf; + } if (srcLen > kExpectedSize+1 || srcLen < kExpectedSize-8) { LOGI(" HiRes file is not ~%d bytes long (got %d)", @@ -273,7 +293,92 @@ bail: } /* - * Convert a buffer of hires data to a 16-color DIB. + * (Lifted directly from fhpack.) + * + * Uncompress LZ4FH data from "srcBuf" to "dstBuf". "dstBuf" must hold + * kExpectedSize bytes. + * + * Returns the uncompressed length on success, 0 on failure. + */ +/*static*/ long ReformatHiRes::ExpandLZ4FH(uint8_t* outBuf, + const uint8_t* inBuf, long inLen) +{ + // constants + static const uint8_t LZ4FH_MAGIC = 0x66; + static const int MIN_MATCH_LEN = 4; + static const int INITIAL_LEN = 15; + static const int EMPTY_MATCH_TOKEN = 253; + static const int EOD_MATCH_TOKEN = 254; + static const int MAX_SIZE = kExpectedSize; + + uint8_t* outPtr = outBuf; + const uint8_t* inPtr = inBuf; + + LOGD("Expanding LZ4FH"); + + if (*inPtr++ != LZ4FH_MAGIC) { + LOGE("Missing LZ4FH magic"); + return 0; + } + + while (true) { + uint8_t mixedLen = *inPtr++; + + int literalLen = mixedLen >> 4; + if (literalLen != 0) { + if (literalLen == INITIAL_LEN) { + literalLen += *inPtr++; + } + if ((outPtr - outBuf) + literalLen > MAX_SIZE || + (inPtr - inBuf) + literalLen > inLen) { + LOGE("Buffer overrun"); + return 0; + } + memcpy(outPtr, inPtr, literalLen); + outPtr += literalLen; + inPtr += literalLen; + } + + int matchLen = mixedLen & 0x0f; + if (matchLen == INITIAL_LEN) { + uint8_t addon = *inPtr++; + if (addon == EMPTY_MATCH_TOKEN) { + matchLen = - MIN_MATCH_LEN; + } else if (addon == EOD_MATCH_TOKEN) { + break; // out of while + } else { + matchLen += addon; + } + } + + matchLen += MIN_MATCH_LEN; + if (matchLen != 0) { + int matchOffset = *inPtr++; + matchOffset |= (*inPtr++) << 8; + // Can't use memcpy() here, because we need to guarantee + // that the match is overlapping. + uint8_t* srcPtr = outBuf + matchOffset; + if ((outPtr - outBuf) + matchLen > MAX_SIZE || + (srcPtr - outBuf) + matchLen > MAX_SIZE) { + LOGE("Buffer overrun"); + return 0; + } + while (matchLen-- != 0) { + *outPtr++ = *srcPtr++; + } + } + } + + if (inPtr - inBuf != (long) inLen) { + LOGW("Warning: LZ4FH uncompress used only %ld of %zd bytes", + inPtr - inBuf, inLen); + } + + return outPtr - outBuf; +} + +/* + * Convert an 8KB buffer of hi-res data to a 16-color 560x384 DIB. */ MyDIBitmap* ReformatHiRes::HiResScreenToBitmap(const uint8_t* buf) { diff --git a/reformat/HiRes.h b/reformat/HiRes.h index 30dccc1..6c3d397 100644 --- a/reformat/HiRes.h +++ b/reformat/HiRes.h @@ -24,6 +24,9 @@ public: ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) override; + static void InitLineOffset(int* pOffsetBuf); + +private: enum { kPixelsPerLine = 280, kNumLines = 192, @@ -33,10 +36,11 @@ public: kExpectedSize = 8192, }; - - static void InitLineOffset(int* pOffsetBuf); MyDIBitmap* HiResScreenToBitmap(const uint8_t* buf); + static long ExpandLZ4FH(uint8_t* dstBuf, const uint8_t* srcBuf, + long srcLen); + int fLineOffset[kNumLines]; bool fBlackWhite; };