Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
790 lines (722 sloc) 19.5 KB
// CCF = Cabernet Configuration File
// Version 4.8
// - with support for hidden panels)
// - with support for CCF version 2 (Beep and Timer actions)
// WANRING: only works on BIG-ENDIAN machines!!!
// (because the ccf file format is also big endian)
// done 1999 Markus Fritze, <http://www.markus-fritze.de/>
//#define NDEBUG 1 // disable assert()
#include <MacTypes.h> // SInt8, SInt16, etc.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#define FNAME "default.ccf"
#define CHECK_LEAKEDMEM 1
#pragma align_array_members off
#pragma options align=packed
typedef struct
{
SInt32 versionPos; // position offset to version string
SInt32 filler1;
char id[8]; // = "@\245Z@_CCF";
SInt32 crcPos; // offset to the checksum (same like endPos)
SInt16 year;
SInt8 month;
SInt8 day;
SInt8 filler2;
SInt8 hour;
SInt8 minute;
SInt8 seconds;
SInt32 filler3;
char id2[4]; // = "CCF\0";
SInt32 version; // (1 = first version, 2 = with timers)
SInt32 endPos; // offset to the checksum (same like ptr2checksum)
SInt32 version2; // (version1: 60, version2: 1)
SInt32 sysHomePos; // offset to HOME panels
SInt32 devPos; // offset to first device
SInt32 macroPos; // offset to first macro
SInt32 confProp; // e.g. 0x02 = configuration is write protected
SInt32 macroXPosV1; // ??? (== 4 in version 2?!?)
SInt32 macroXPosV2; // ???
SInt16 filler4;
} sHeaderStruct;
typedef struct
{
SInt32 nextPos; // != NULL => position of next sEntryStruct
SInt32 namePos;
SInt32 filler1;
SInt32 filler2;
SInt32 actionPos;
SInt32 leftKeyPos;
SInt32 rightKeyPos;
SInt32 VolMinusKeyPos;
SInt32 VolPlusKeyPos;
SInt32 ChanMinusKeyPos;
SInt32 ChanPlusKeyPos;
SInt32 MuteKeyPos;
SInt32 filler3;
SInt32 leftKeyNamePos;
SInt32 rightKeyNamePos;
SInt32 panelsPos;
SInt8 attr;
} sEntryStruct;
typedef struct
{
SInt32 nextPos; // != NULL => position of next sPanelStruct
SInt32 namePos; // name of the panel (Bit 31 is set when panel is hidden)
SInt8 count; // number of entries, always (?) == count2
SInt8 count2;
struct
{
SInt16 x;
SInt16 y;
SInt32 subPanelPos;
SInt8 type;
} data[];
} sPanelStruct;
typedef struct
{
union
{
struct
{
SInt16 w;
SInt16 h;
SInt32 namePos;
SInt32 iconPos;
SInt32 filler;
SInt16 attr;
SInt16 filler2;
} def; // type = 0
struct
{
SInt16 w;
SInt16 h;
SInt32 actionPos;
SInt32 namePos;
SInt32 filler;
SInt16 attr;
SInt32 icon1Pos;
SInt32 icon2Pos;
SInt32 icon3Pos;
SInt32 icon4Pos;
SInt8 inactiveUnselColor;
SInt8 inactiveSelColor;
SInt8 activeUnselColor;
SInt8 activeSelColor;
} button; // type = 1
};
} sPanelSubStruct;
typedef struct
{
SInt16 size; // size of the structure in bytes
SInt16 w;
SInt16 h;
SInt16 mode;
char data[];
} sIconStruct;
typedef struct {
SInt8 type; // 0x01 = CODE, 0x04 = DELAY, 0x05 = ALIAS, etc.
SInt32 p1;
SInt32 p2;
} sActionStruct;
typedef struct
{
SInt8 count; // number of entries, always (?) == count2
SInt8 count2;
sActionStruct data[];
} sActionListStruct;
typedef struct
{
SInt16 size; // size of the structure in bytes
SInt32 namePos;
SInt16 details; // 0x0000 = pulse-width coding
// 0x0100 = pulse-position coding
// 0x5000 = RC5 (phase modulation)
// 0x5001 = RC5x (phase modulation)
// 0x6000 = RC6 (phase modulation)
SInt16 carrier;
SInt16 onceCounter;
SInt16 repeatCounter;
union {
struct
{
SInt16 device;
SInt16 command;
} RC5;
struct
{
SInt16 device;
SInt16 command;
SInt16 data;
} RC5x;
struct
{
SInt16 device;
SInt16 command;
} RC6;
struct
{
SInt16 data[];
} LRN;
};
} sIRCodeStruct;
typedef struct
{
SInt32 zero;
SInt16 sDays;
SInt16 sTime;
SInt16 eDays;
SInt16 eTime;
sActionStruct sAction;
sActionStruct eAction;
} sTimerStruct;
/***
*
***/
const char *gData;
#if CHECK_LEAKEDMEM
bool *gUse;
long gFileSize;
#endif
/***
*
***/
static inline const char *GetPosPtr(SInt32 pos)
{
return reinterpret_cast<const char*>(pos + gData);
}
static inline const sHeaderStruct *GetHeader(SInt32 pos)
{
const sHeaderStruct *p = reinterpret_cast<const sHeaderStruct*>(GetPosPtr(pos));
assert(p);
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, sizeof(sHeaderStruct));
#endif
return p;
}
static inline UInt16 GetCRC(SInt32 pos)
{
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, sizeof(UInt16));
#endif
return *reinterpret_cast<const UInt16*>(gData + pos);
}
static inline const sPanelStruct *GetPanel(SInt32 pos)
{
const sPanelStruct *p = reinterpret_cast<const sPanelStruct*>(GetPosPtr(pos));
assert(p);
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, sizeof(sPanelStruct) + 9 * p->count);
#endif
return p;
}
static inline const sEntryStruct *GetEntry(SInt32 pos)
{
const sEntryStruct *p = reinterpret_cast<const sEntryStruct*>(GetPosPtr(pos));
assert(p);
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, sizeof(sEntryStruct));
#endif
return p;
}
static inline const sActionListStruct *GetActionList(SInt32 pos)
{
const sActionListStruct *p = reinterpret_cast<const sActionListStruct*>(GetPosPtr(pos));
assert(p);
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, sizeof(sActionListStruct) + p->count * sizeof(sActionStruct));
#endif
return p;
}
static inline const sIRCodeStruct *GetIRCode(SInt32 pos)
{
const sIRCodeStruct *p = reinterpret_cast<const sIRCodeStruct*>(GetPosPtr(pos));
assert(p);
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, p->size);
#endif
return p;
}
static inline const sPanelSubStruct *GetSubPanel(SInt32 pos)
{
const sPanelSubStruct *p = reinterpret_cast<const sPanelSubStruct*>(GetPosPtr(pos));
assert(p);
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, sizeof(sPanelSubStruct));
#endif
return p;
}
static inline const sIconStruct *GetIcon(SInt32 pos)
{
const sIconStruct *p = reinterpret_cast<const sIconStruct*>(GetPosPtr(pos));
assert(p);
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, p->size);
#endif
return p;
}
static inline const sTimerStruct *GetTimerEntry(SInt32 pos)
{
const sTimerStruct *p = reinterpret_cast<const sTimerStruct*>(GetPosPtr(pos));
assert(p);
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, sizeof(sTimerStruct));
#endif
return p;
}
// return a ptr to a _pascal_ string (first byte = length, second byte = 1. char, third byte = 2. char, etc.)
static inline const char *GetCCFString(SInt32 pos)
{
if(pos == 0) return reinterpret_cast<const char*>("\p<NIL>"); // illegal position => <NIL> string
const char *p = reinterpret_cast<const char*>(GetPosPtr(pos));
assert(p);
#if CHECK_LEAKEDMEM
memset(gUse + pos, 0xFF, p[0] + 1);
#endif
return p;
}
/***
*
***/
static void PrintAction(const sActionStruct *si)
{
const sIRCodeStruct *irs;
const sEntryStruct *es;
const sPanelStruct *ps;
const sPanelSubStruct *pss;
const sTimerStruct *ts;
switch(si->type)
{
case 0x01: // Code
irs = GetIRCode(si->p2);
printf("[C] %#s ", GetCCFString(irs->namePos));
switch(irs->details)
{
case 0x0100: // pulse-position coding
printf("(pulse-position coding)\n");
goto cont;
case 0x0000: // learned
printf("(pulse-width coding)\n");
cont:
#if 0
int index;
printf("Carrier: %x\n", irs->carrier);
printf("Once: ");
for(index=0; index < irs->onceCounter*2; index += 2)
printf("%.4x/%.4x ", irs->LRN.data[index], irs->LRN.data[index+1]);
printf("\n");
printf("Repeat: ");
for(int i=0; i < irs->repeatCounter*2; i += 2)
printf("%.4x/%.4x ", irs->LRN.data[i + index], irs->LRN.data[i + index + 1]);
printf("\n");
#endif
break;
case 0x5000:
printf("%d %d\n", irs->RC5.device, irs->RC5.command);
break;
case 0x5001:
printf("%d %d %d\n", irs->RC5x.device, irs->RC5x.command, irs->RC5x.data);
break;
case 0x6000:
printf("%d %d\n", irs->RC6.device, irs->RC6.command);
break;
default:
printf("unknown: %x\n", irs->details);
printf("Carrier: %x\n", irs->carrier);
printf("Once : %x\n", irs->onceCounter);
printf("Repeat : %x\n", irs->repeatCounter);
break;
}
break;
case 0x02: // Button
es = GetEntry(si->p1);
if(es->namePos) printf("[B] %#s - ", GetCCFString(es->namePos));
pss = GetSubPanel(si->p2);
if(pss->button.namePos) printf("%#s", GetCCFString(pss->button.namePos));
printf("\n");
break;
case 0x03: // Jump (last possible action in a macro)
printf("Jump: ");
switch(si->p2)
{
default:
es = GetEntry(si->p1);
if(es->namePos) printf("%#s - ", GetCCFString(es->namePos));
ps = GetPanel(si->p2);
if(ps->namePos) printf("%#s", GetCCFString(ps->namePos));
printf("\n");
break;
case 0xdddddddd:
printf("Scroll down");
break;
case 0xEEEEEEEE:
printf("Scroll up");
break;
case 0xFFFFFFFF:
printf("Mouse mode");
break;
}
printf("\n");
break;
case 0x04: // Delay
// p2 contains the delay in ms
printf("[D] %.1f sec\n", float(si->p2) / 1000);
break;
case 0x05: // Alias
printf("[K] ");
es = GetEntry(si->p1);
if(es->namePos) printf("%#s - ", GetCCFString(es->namePos));
switch(si->p2)
{
case 0: printf("left"); break;
case 1: printf("right"); break;
case 2: printf("Vol-"); break;
case 3: printf("Vol+"); break;
case 4: printf("Chan-"); break;
case 5: printf("Chan+"); break;
case 6: printf("Mute"); break;
default:printf("unknown(%ld)", si->p2); break;
}
printf("\n");
break;
case 0x06: // Jump Device
es = GetEntry(si->p1);
if(es->namePos) printf("[A] %#s\n", GetCCFString(es->namePos));
break;
case 0x07: // Timer
printf("[T] TimerAction\n");
ts = GetTimerEntry(si->p2);
printf("Start: ");
PrintAction(&ts->sAction);
static const char *dayArr[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Son", "Wkly" };
printf(" ");
for(long i=0x0100,j=0; i<=0x8000; i<<=1,++j)
if(ts->sDays & i) printf("%s ", dayArr[j]);
printf("%d:%d\n", ts->sTime / 60, ts->sTime % 60);
printf("Stop : ");
PrintAction(&ts->eAction);
printf(" ");
for(long i=0x0100,j=0; i<=0x8000; i<<=1,++j)
if(ts->eDays & i) printf("%s ", dayArr[j]);
printf("%d:%d\n", ts->eTime / 60, ts->eTime % 60);
break;
case 0x08: // Beep
SInt32 val = si->p2;
printf("[S] %ld Hz %ld %% %ld0 ms\n", (val >> 8) & 0xFFFF, val & 0xFF, (val >> 24) & 0xFF);
break;
default:
printf("unknown Type : %d : %ld/%lx\n", si->type, si->p1, si->p2);
break;
}
}
static void PrintActionList(ConstStr255Param name, SInt32 pos)
{
printf("%#s: ", name);
const sActionListStruct *sa = GetActionList(pos);
for(int index=0; index<sa->count; ++index)
PrintAction(&sa->data[index]);
}
/***
*
***/
static void PrintIcon(SInt32 pos)
{
const sIconStruct *si = GetIcon(pos);
#if 0
printf("ICON(P:%lx,S:%d,W:%d,H:%d,M:%x)\n", pos, si->size, si->w, si->h, si->mode);
// print some nice ascii art...
const char *dataPtr = si->data;
int bitOffset = (si->mode == 0x1800) ? 1 : 2; // b/w (mode == 0x1800) or 4 colors (mode == 0x0100)
int bitMask = (1 << bitOffset) - 1;
const char *bitMap = (bitOffset == 1) ? "# " : "#+. ";
for(int h=0; h<si->h; ++h)
{
int bitPos = 8 - bitOffset;
for(int w=0; w<si->w; ++w)
{
putchar(bitMap[(*dataPtr >> bitPos) & bitMask]);
bitPos -= bitOffset;
if(bitPos < 0)
{
bitPos = 8 - bitOffset;
dataPtr++;
}
}
if(bitPos > 0)
++dataPtr;
printf("\n");
}
#endif
}
/***
* 2 bit color index => string
***/
static const char *GetColor(char color)
{
switch(color & 3)
{
default:
case 0: return "black";
case 1: return "dkGray";
case 2: return "ltGray";
case 3: return "white";
}
}
/***
* 8 bit font index => string
***/
static const char *GetFont(char font)
{
switch(font)
{
case 0: return "<none>";
case 1: return "Pronto 8";
case 2: return "Pronto 10";
case 3: return "Pronto 12";
case 4: return "Pronto 14";
case 5: return "Pronto 16";
case 6: return "Pronto 18";
default:return "Pronto xx";
}
}
/***
*
***/
static void PrintSubPanel(const sPanelStruct *ps, int index)
{
assert(ps);
const sPanelSubStruct *ps2 = GetSubPanel(ps->data[index].subPanelPos);
switch(ps->data[index].type)
{
case 0:
if(ps2->def.namePos) printf("Name : %#s\n", GetCCFString(ps2->def.namePos));
printf("Frame:\n");
printf("Pos : (%d,%d)-(%d,%d)\n", ps->data[index].x, ps->data[index].y, ps2->def.w, ps2->def.h);
printf("(Font:%s, Text;%s, Back:%s)\n", GetFont(ps2->def.attr >> 8), GetColor(ps2->def.attr), GetColor(ps2->def.attr >> 2));
if(ps2->def.iconPos) PrintIcon(ps2->def.iconPos);
break;
case 1:
if(ps2->button.namePos) printf("Name : %#s\n", GetCCFString(ps2->button.namePos));
printf("Button:\n");
printf("Pos : (%d,%d)-(%d,%d)\n", ps->data[index].x, ps->data[index].y, ps2->button.w, ps2->button.h);
printf("(Font:%s, Text;%s, Back:%s)\n", GetFont(ps2->button.attr >> 8), GetColor(ps2->button.attr), GetColor(ps2->button.attr >> 2));
printf("(inUnCol:%s", GetColor(ps2->button.inactiveUnselColor));
printf(", inSelCol:%s", GetColor(ps2->button.inactiveSelColor));
printf(", actUnCol:%s", GetColor(ps2->button.activeUnselColor));
printf(", actSelCol:%s)\n", GetColor(ps2->button.activeSelColor));
if(ps2->button.icon1Pos) PrintIcon(ps2->button.icon1Pos);
if(ps2->button.icon2Pos) PrintIcon(ps2->button.icon2Pos);
if(ps2->button.icon3Pos) PrintIcon(ps2->button.icon3Pos);
if(ps2->button.icon4Pos) PrintIcon(ps2->button.icon4Pos);
if(ps2->button.actionPos) PrintActionList("\pAction", ps2->button.actionPos);
break;
}
}
/***
* Print panel with all subpanels
***/
static void PrintPanel(SInt32 pos)
{
for(const sPanelStruct *ps = GetPanel(pos); ps != NULL; ps = GetPanel(ps->nextPos))
{
printf("Panelname : ");
bool isHidden = (ps->namePos & 0x80000000L) == 0x80000000L;
if(isHidden) putchar('[');
printf("%#s", GetCCFString(ps->namePos & 0x7FFFFFFFL));
if(isHidden) putchar(']');
printf("\n");
for(int i=0; i<ps->count; ++i)
PrintSubPanel(ps, i);
if(ps->nextPos == NULL)
break;
}
}
/***
* Print an entry (device, macrolist, home, etc.) with panels
***/
static void PrintEntry(const sEntryStruct *dl, bool printName = true)
{
assert(dl);
if(printName) printf("Entryname : %#s", GetCCFString(dl->namePos));
if(dl->attr)
{
printf(" (");
bool isPrinted = false;
if(dl->attr & 0x40) { printf("Is Template"); isPrinted = true; }
if(dl->attr & 0x01) { if(isPrinted) printf(","); printf("Is Read Only"); isPrinted = true; }
if(dl->attr & 0x20) { if(isPrinted) printf(","); printf("Has Separator"); isPrinted = true; }
printf(")");
}
printf("\n");
if(dl->actionPos) PrintActionList("\pAction", dl->actionPos);
if(dl->leftKeyPos) PrintActionList(dl->leftKeyNamePos ? StringPtr(GetCCFString(dl->leftKeyNamePos)) : "\pLeft", dl->leftKeyPos);
if(dl->rightKeyPos) PrintActionList(dl->rightKeyNamePos ? StringPtr(GetCCFString(dl->rightKeyNamePos)) : "\pRight", dl->rightKeyPos);
if(dl->VolMinusKeyPos) PrintActionList("\pVol-", dl->VolMinusKeyPos);
if(dl->VolPlusKeyPos) PrintActionList("\pVol+", dl->VolPlusKeyPos);
if(dl->ChanMinusKeyPos) PrintActionList("\pChan-", dl->ChanMinusKeyPos);
if(dl->ChanPlusKeyPos) PrintActionList("\pChan+", dl->ChanPlusKeyPos);
if(dl->MuteKeyPos) PrintActionList("\pMute", dl->MuteKeyPos);
if(dl->panelsPos) PrintPanel(dl->panelsPos);
puts("");
}
/***
* standard 16bit XModem CRC
***/
static UInt16 ComputeCrc(const char *bufptr, SInt32 count)
{
assert(bufptr);
UInt16 crc = 0;
while(--count>=0)
{
crc ^= static_cast<UInt16>(*bufptr++) << 8;
for(int i=0; i < 8; ++i)
{
if(crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
}
}
return crc;
}
/***
* load ccf file into ram
***/
static void loadFile(const char *filename)
{
FILE *f = fopen(filename, "rb");
assert(f);
fseek(f, 0, SEEK_END);
long fSize = ftell(f); // get the filesize
fseek(f, 0, SEEK_SET);
// alloc memory for the ccf file
if(gData) free(const_cast<char*>(gData));
gData = reinterpret_cast<const char*>(malloc(fSize));
assert(gData);
#if CHECK_LEAKEDMEM
// alloc memory for used table (debugging)
if(gUse) free(gUse);
gUse = reinterpret_cast<bool*>(malloc(fSize));
assert(gUse);
memset(gUse, false, fSize);
gFileSize = fSize;
#endif
// load the ccf file into memory
int count = fread(const_cast<char*>(gData), fSize, 1, f);
assert(count == 1);
fclose(f);
}
/***
*
***/
static void parseCCF()
{
// get the fileheader
const sHeaderStruct *hs = GetHeader(0);
assert(memcmp(hs->id, "@\245Z@_CCF", 8) == 0);
printf("Version string: \"%#s\"\n", GetCCFString(hs->versionPos));
printf("Modification date: %d:%.2d:%.2d %d.%d.%d\n", hs->hour, hs->minute, hs->seconds, hs->day, hs->month, hs->year);
assert(strcmp(hs->id2, "CCF") == 0);
if(hs->confProp & 2)
puts("configuration is write-protected");
if(hs->confProp & 4)
puts("HOME panels are write-protected");
// unknown values :-(
assert(hs->filler1 == 0);
assert(hs->filler2 == 0);
assert(hs->filler3 == 0);
assert(hs->filler4 == 0);
printf("Version : %d\n", hs->version);
// crc ok?
if(GetCRC(hs->crcPos) != ComputeCrc(gData, hs->crcPos))
{
puts("Wrong CRC!");
return;
}
puts("");
if(hs->sysHomePos)
{
const sEntryStruct *ss = GetEntry(hs->sysHomePos);
printf("%#s:", GetCCFString(ss->namePos));
PrintEntry(ss, false);
}
puts("");
puts("DEVICES:");
if(hs->devPos)
{
for(const sEntryStruct *dl = GetEntry(hs->devPos); dl != NULL; dl = GetEntry(dl->nextPos))
{
PrintEntry(dl);
if(dl->nextPos == NULL)
break;
}
}
puts("");
puts("MACRO GROUPS:");
if(hs->macroPos)
{
for(const sEntryStruct *dl = GetEntry(hs->macroPos); dl != NULL; dl = GetEntry(dl->nextPos))
{
PrintEntry(dl);
if(dl->nextPos == NULL)
break;
}
}
// ???
if(hs->version == 1)
{
if(hs->macroXPosV1)
PrintPanel(hs->macroXPosV1);
} else {
if(hs->macroXPosV2)
PrintPanel(hs->macroXPosV2);
}
}
/***
*
***/
static void PrintLeakedMemory()
{
#if CHECK_LEAKEDMEM
// print all unused memory addresses (did we forget something or does ProntoEdit leak memory?)
puts("");
puts("leaked memory:");
long lastPos = -1;
long i;
for(i=0; i<gFileSize; ++i)
{
if(gUse[i] == false)
{
if(lastPos < 0)
lastPos = i;
} else {
if(lastPos >= 0)
{
if(lastPos != i-1)
printf("%#lx-%#lx\n", lastPos, i-1);
else
printf("%#lx\n", lastPos);
lastPos = -1;
}
}
}
if(lastPos >= 0)
{
if(lastPos != i-1)
printf("%#lx-%#lx\n", lastPos, i-1);
else
printf("%#lx\n", lastPos);
}
#endif
}
/***
*
***/
int main()
{
loadFile(FNAME);
parseCCF();
PrintLeakedMemory();
}