/* * Skip the header and text-convert the rest. */ int ReformatMagicWindow::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcPtr = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); long length = srcLen; int retval = -1; fUseRTF = false; RTFBegin(); if (srcLen <= kHeaderLen) goto bail; ConvertEOL(srcPtr + kHeaderLen, srcLen - kHeaderLen, true); //done: RTFEnd(); SetResultBuffer(pOutput); retval = 0; bail: return retval; }
/* * Convert GWP into formatted text. */ int ReformatGWP::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcBuf = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); fUseRTF = false; CheckGSCharConv(); RTFBegin(); /* convert EOL markers and IIgs characters */ uint8_t ch; while (srcLen) { ch = *srcBuf++; srcLen--; if (ch == '\r') { /* got CR, check for CRLF -- not really expected on IIgs */ if (srcLen != 0 && *srcBuf == '\n') { srcBuf++; srcLen--; } BufPrintf("\r\n"); } else if (ch == '\n') { BufPrintf("\r\n"); } else { // RTF is always off, so just use BufPrintf BufPrintf("%c", ConvertGSChar(ch)); } } RTFEnd(); SetResultBuffer(pOutput); return 0; }
/* * Convert the text. */ int ReformatGutenberg::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcPtr = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); long length = srcLen; int retval = -1; fUseRTF = false; RTFBegin(); ConvertEOL(srcPtr, srcLen, true, true); RTFEnd(); SetResultBuffer(pOutput); retval = 0; return retval; }
/* * Reformat an Apple /// Business BASIC program into a text format that * mimics the output of the "LIST" command. */ int ReformatBusiness::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcPtr = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); long length = srcLen; int retval = -1; int nestLevels = 0; if (srcLen > 65536) fUseRTF = false; if (fUseRTF) { if (id != ReformatHolder::kReformatBusiness_Hilite) fUseRTF = false; } RTFBegin(kRTFFlagColorTable); /* * Make sure there's enough here to get started. We want to return an * "okay" result because we want this treated like a reformatted empty * BASIC program rather than a non-BASIC file. */ if (length < 2) { LOGI(" BA3 truncated?"); //fExpBuf.CreateWorkBuf(); BufPrintf("\r\n"); goto done; } uint16_t fileLength; fileLength = Read16(&srcPtr, &length); LOGI(" BA3 internal file length is: %d", fileLength); while (length > 0) { uint16_t increment; uint16_t extendedToken; uint16_t lineNum; bool inQuote = false; bool inRem = false; bool firstData = true; bool literalYet = false; increment = Read8(&srcPtr, &length); LOGI(" BA3 increment to next line is: %d", increment); if (increment == 0) { /* ProDOS sticks an extra byte on the end? */ if (length > 1) { LOGI(" BA3 ended early; len is %d", length); } break; } /* print line number */ RTFSetColor(kLineNumColor); lineNum = Read16(&srcPtr, &length); LOGI(" BA3 line number: %d", lineNum); BufPrintf(" %u ", lineNum); RTFSetColor(kDefaultColor); if (nestLevels > 0) { for (int i =0; i < nestLevels; i++) BufPrintf(" "); } /* print a line */ while (*srcPtr != 0 && length > 0) { if (*srcPtr & 0x80) { /* token */ //RTFBoldOn(); literalYet = false; RTFSetColor(kKeywordColor); if (*srcPtr == 0x81) { // Token is FOR - indent nestLevels ++; } else if (*srcPtr == 0x82) { // Token is NEXT - outdent nestLevels --; } if (!firstData) BufPrintf(" "); if (((*srcPtr) & 0x7f) == 0x7f) { extendedToken = Read8(&srcPtr, &length); BufPrintf("%s", &gExtendedBusinessTokens[((*srcPtr) & 0x7f) * 10]); // We need to have some tokens NOT add a space after them. if ((*srcPtr == 0x80) || // TAB( (*srcPtr == 0x82) || // SPC( (*srcPtr == 0x9d) || // SGN( (*srcPtr == 0x9e) || // INT( (*srcPtr == 0x9f) || // ABS( (*srcPtr == 0xa1) || // TYP( (*srcPtr == 0xa2) || // REC( (*srcPtr == 0xad) || // PDL( (*srcPtr == 0xae) || // BUTTON( (*srcPtr == 0xaf) || // SQR( (*srcPtr == 0xb0) || // RND( (*srcPtr == 0xb1) || // LOG( (*srcPtr == 0xb2) || // EXP( (*srcPtr == 0xb3) || // COS( (*srcPtr == 0xb4) || // SIN( (*srcPtr == 0xb5) || // TAN( (*srcPtr == 0xb6) || // ATN( (*srcPtr == 0xc3) || // STR$( (*srcPtr == 0xc4) || // HEX$( (*srcPtr == 0xc5) || // CHR$( (*srcPtr == 0xc6) || // LEN( (*srcPtr == 0xc7) || // VAL( (*srcPtr == 0xc8) || // ASC( (*srcPtr == 0xc9) || // TEN( (*srcPtr == 0xcc) || // CONV( (*srcPtr == 0xcd) || // CONV&( (*srcPtr == 0xce) || // CONV$( (*srcPtr == 0xcf) || // CONV%( (*srcPtr == 0xd0) || // LEFT$( (*srcPtr == 0xd1) || // RIGHT$( (*srcPtr == 0xd2) || // MID$( (*srcPtr == 0xd3)) // INSTR$( firstData = true; else firstData = false; } else { BufPrintf("%s", &gBusinessTokens[((*srcPtr) & 0x7f) * 10]); // We need to have some tokens NOT add a space after them. if ((*srcPtr == 0x99) || // HPOS (*srcPtr == 0x9a) || // VPOS (*srcPtr == 0x9f) || // TIME$ (*srcPtr == 0xa0) || // DATE$ (*srcPtr == 0xa1) || // PREFIX$ (*srcPtr == 0xa2) || // EXFN. (*srcPtr == 0xa3) || // EXFN%. (*srcPtr == 0xb0) || // SUB$(. (*srcPtr == 0xb6) || // SCALE( (*srcPtr == 0xc0) || // REM (*srcPtr == 0xe3)) // SPC( firstData = true; else firstData = false; } //RTFBoldOff(); RTFSetColor(kDefaultColor); if (*srcPtr == 0xc0) { // REM -- do rest of line in green RTFSetColor(kCommentColor); inRem = true; } } else { /* simple chracter */ if (*srcPtr == ':') // Reset line if we have a colon firstData = true; if (!firstData) { if (!literalYet) { BufPrintf(" "); literalYet = true; } } if (fUseRTF) { if (*srcPtr == '"' && !inRem) { if (!inQuote) { RTFSetColor(kStringColor); RTFPrintChar(*srcPtr); } else { RTFPrintChar(*srcPtr); RTFSetColor(kDefaultColor); } inQuote = !inQuote; } else if (*srcPtr == ':' && !inRem && !inQuote) { RTFSetColor(kColonColor); RTFPrintChar(*srcPtr); RTFSetColor(kDefaultColor); } else { RTFPrintChar(*srcPtr); } } else { BufPrintf("%c", *srcPtr); } } srcPtr++; length--; } if (inQuote || inRem) RTFSetColor(kDefaultColor); inQuote = inRem = false; srcPtr++; length--; if (!length) { LOGI(" BA3 truncated in mid-line"); break; } RTFNewPara(); } done: RTFEnd(); SetResultBuffer(pOutput); retval = 0; //bail: return retval; }
/* * Reformat an Integer BASIC program into a text format that mimics the * output of the "LIST" command. */ int ReformatInteger::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcPtr = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); long length = srcLen; int retval = -1; //srcPtr += 0xff0; //0x228e; //srcLen -= 0xff0; //0x228e; if (srcLen > 65536) fUseRTF = false; if (fUseRTF) { if (id != ReformatHolder::kReformatInteger_Hilite) fUseRTF = false; } RTFBegin(kRTFFlagColorTable); /* * Make sure there's enough here to get started. We want to return an * "okay" result because we want this treated like a reformatted empty * BASIC program rather than a non-Integer file. */ if (length < 2) { LOGI(" INT truncated?"); BufPrintf("\r\n"); goto done; } while (length > 0) { uint8_t lineLen; uint16_t lineNum; bool trailingSpace; bool newTrailingSpace = false; /* pull the length byte, which we sanity-check */ lineLen = *srcPtr++; length--; if (lineLen == 0) { LOGI(" INT found zero-length line?"); break; } /* line number */ RTFSetColor(kLineNumColor); lineNum = Read16(&srcPtr, &length); BufPrintf("%5u ", lineNum); RTFSetColor(kDefaultColor); trailingSpace = true; while (*srcPtr != 0x01 && length > 0) { if (*srcPtr == 0x28) { /* start of quoted text */ RTFSetColor(kStringColor); BufPrintf("\""); length--; while (*++srcPtr != 0x29 && length > 0) { /* escape chars, but let Ctrl-D and Ctrl-G through */ if (fUseRTF && *srcPtr != 0x84 && *srcPtr != 0x87) RTFPrintChar(*srcPtr & 0x7f); else BufPrintf("%c", *srcPtr & 0x7f); length--; } if (*srcPtr != 0x29) { LOGI(" INT ended while in a string constant"); break; } BufPrintf("\""); RTFSetColor(kDefaultColor); srcPtr++; length--; } else if (*srcPtr == 0x5d) { /* start of REM statement, run to EOL */ //RTFBoldOn(); RTFSetColor(kKeywordColor); BufPrintf("%sREM ", trailingSpace ? "" : " "); //RTFBoldOff(); RTFSetColor(kCommentColor); length--; while (*++srcPtr != 0x01) { if (fUseRTF) RTFPrintChar(*srcPtr & 0x7f); else BufPrintf("%c", *srcPtr & 0x7f); length--; } RTFSetColor(kDefaultColor); if (*srcPtr != 0x01) { LOGI(" INT ended while in a REM statement"); break; } } else if (*srcPtr >= 0xb0 && *srcPtr <= 0xb9) { /* start of integer constant */ srcPtr++; length--; if (length < 2) { LOGI(" INT ended while in an integer constant"); break; } int val; val = Read16(&srcPtr, &length); BufPrintf("%d", val); } else if (*srcPtr >= 0xc1 && *srcPtr <= 0xda) { /* start of variable name */ while ((*srcPtr >= 0xc1 && *srcPtr <= 0xda) || (*srcPtr >= 0xb0 && *srcPtr <= 0xb9)) { /* note no RTF-escaped chars in this range */ BufPrintf("%c", *srcPtr & 0x7f); srcPtr++; length--; } } else if (*srcPtr < 0x80) { /* found a token; try to get the whitespace right */ /* (maybe should've left whitespace on the ends of tokens that are always followed by whitespace...?) */ const char* token; token = gIntegerTokens[*srcPtr]; //RTFBoldOn(); if (*srcPtr == 0x03) // colon RTFSetColor(kColonColor); else RTFSetColor(kKeywordColor); if (token[0] >= 0x21 && token[0] <= 0x3f || *srcPtr < 0x12) { /* does not need leading space */ BufPrintf("%s", token); } else { /* needs leading space; combine with prev if it exists */ if (trailingSpace) BufPrintf("%s", token); else BufPrintf(" %s", token); } if (token[strlen(token)-1] == ' ') newTrailingSpace = true; //RTFBoldOff(); RTFSetColor(kDefaultColor); srcPtr++; length--; } else { /* should not happen */ LOGI(" INT unexpected value 0x%02x at byte %d", *srcPtr, srcPtr - pHolder->GetSourceBuf(part)); /* skip past it and keep trying */ srcPtr++; length--; } trailingSpace = newTrailingSpace; newTrailingSpace = false; } /*while line*/ /* skip past EOL token */ if (*srcPtr != 0x01 && length > 0) { LOGI("bailing"); // must've failed during processing goto bail; } srcPtr++; length--; RTFNewPara(); } done: RTFEnd(); SetResultBuffer(pOutput); retval = 0; bail: return retval; }
/* * Reformat an Applesoft BASIC program into a text format that mimics the * output of the "LIST" command (with POKE 33,73 to suppress CRs). */ int ReformatApplesoft::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcPtr = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); long length = srcLen; int retval = -1; if (srcLen > 65536) fUseRTF = false; if (fUseRTF) { if (id != ReformatHolder::kReformatApplesoft_Hilite) fUseRTF = false; } RTFBegin(kRTFFlagColorTable); /* * Make sure there's enough here to get started. We want to return an * "okay" result because we want this treated like a reformatted empty * BASIC program rather than a non-Applesoft file. */ if (length < 2) { LOGI(" BAS truncated?"); //fExpBuf.CreateWorkBuf(); BufPrintf("\r\n"); goto done; } while (length > 0) { uint16_t nextAddr; uint16_t lineNum; bool inQuote = false; bool inRem = false; nextAddr = Read16(&srcPtr, &length); if (nextAddr == 0) { /* ProDOS sticks an extra byte on the end? */ if (length > 1) { LOGI(" BAS ended early; len is %d", length); } break; } /* print line number */ RTFSetColor(kLineNumColor); lineNum = Read16(&srcPtr, &length); BufPrintf(" %u ", lineNum); RTFSetColor(kDefaultColor); assert(kTokenLen == 8); // we do "<< 3" below, so this must hold /* print a line */ while (*srcPtr != 0 && length > 0) { if (*srcPtr & 0x80) { /* token */ //RTFBoldOn(); RTFSetColor(kKeywordColor); BufPrintf(" %s ", &gApplesoftTokens[((*srcPtr) & 0x7f) << 3]); //RTFBoldOff(); RTFSetColor(kDefaultColor); if (*srcPtr == 0xb2) { // REM -- do rest of line in green RTFSetColor(kCommentColor); inRem = true; } } else { /* simple character */ if (fUseRTF) { if (*srcPtr == '"' && !inRem) { if (!inQuote) { RTFSetColor(kStringColor); RTFPrintChar(*srcPtr); } else { RTFPrintChar(*srcPtr); RTFSetColor(kDefaultColor); } inQuote = !inQuote; } else if (*srcPtr == ':' && !inRem && !inQuote) { RTFSetColor(kColonColor); RTFPrintChar(*srcPtr); RTFSetColor(kDefaultColor); } else if (inRem && *srcPtr == '\r') { RTFNewPara(); } else { RTFPrintChar(*srcPtr); } } else { if (inRem && *srcPtr == '\r') { BufPrintf("\r\n"); } else { BufPrintf("%c", *srcPtr); } } } srcPtr++; length--; } if (inQuote || inRem) RTFSetColor(kDefaultColor); inQuote = inRem = false; srcPtr++; length--; if (!length) { LOGI(" BAS truncated in mid-line"); break; } RTFNewPara(); } done: RTFEnd(); SetResultBuffer(pOutput); retval = 0; //bail: return retval; }
/* * Convert Teach Text into formatted text. * * The text is in the data fork and the formatting is in the resource fork. */ int ReformatTeach::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* dataBuf; const uint8_t* rsrcBuf; long dataLen, rsrcLen; const uint8_t* styleBlock; long styleLen; if (part != ReformatHolder::kPartData) return -1; dataBuf = pHolder->GetSourceBuf(ReformatHolder::kPartData); dataLen = pHolder->GetSourceLen(ReformatHolder::kPartData); rsrcBuf = pHolder->GetSourceBuf(ReformatHolder::kPartRsrc); rsrcLen = pHolder->GetSourceLen(ReformatHolder::kPartRsrc); if (dataBuf == NULL || rsrcBuf == NULL || dataLen <= 0 || rsrcLen <= 0) { LOGI("Teach reformatter missing one fork of the file"); return -1; } CheckGSCharConv(); /* find the rStyleBlock */ if (!ReformatResourceFork::GetResource(rsrcBuf, rsrcLen, 0x8012, 0x0001, &styleBlock, &styleLen)) { LOGI("Resource fork of Teach Text file not found"); return -1; } RStyleBlock rStyleBlock; if (!rStyleBlock.Create(styleBlock, styleLen)) { LOGI("Unable to unpack rStyleBlock"); return -1; } fUseRTF = true; RTFBegin(); /* * Configure ruler options. The format allows us to have more than one * ruler, but doesn't provide a way to select between them, so we have * to assume that the first ruler is global. * * In practice, the Teach application doesn't provide a way to set * margins or tab stops, so there's really not much to do. It seems to * create tab stops with 64-pixel widths, which translates to 10 tab * stops per page. WordPad seems to default to 12, so I figure there's * not much point in futzing with it since the fonts are all different * anyway. */ RStyleBlock::TERuler* pRuler = rStyleBlock.GetRuler(0); assert(pRuler != NULL); if (pRuler->GetJustification() != RStyleBlock::TERuler::kJustLeft) { LOGI("WARNING: not using left justified Teach text"); /* ignore it */ } for (int style = 0; style < rStyleBlock.GetNumStyleItems(); style++) { RStyleBlock::StyleItem* pStyleItem; RStyleBlock::TEStyle* pStyle; int numBytes; /* set up the style */ pStyleItem = rStyleBlock.GetStyleItem(style); assert(pStyleItem != NULL); if (pStyleItem->GetLength() == RStyleBlock::StyleItem::kUnusedItem) continue; numBytes = pStyleItem->GetLength(); pStyle = rStyleBlock.GetStyle(pStyleItem->GetStyleIndex()); /* * Set the font first; that defines the point size multiplier. Set * the size second, because the point size determines whether we * show underline. Set the style last. */ RTFSetGSFont(pStyle->GetFontFamily()); RTFSetGSFontSize(pStyle->GetFontSize()); RTFSetGSFontStyle(pStyle->GetTextStyle()); /* * The Teach app doesn't let you set text colors, but it appears * there's a way to do it, since the SpyHunterGS Read.Me file has * a bit of red in it. */ if (pStyle->GetTextColor() != 0) { // do something with color, someday } /* output the characters */ uint8_t uch; while (numBytes--) { if (!dataLen) { LOGI("WARNING: Teach underrun (%ld wanted)", numBytes); break; } uch = *dataBuf; if (uch == '\r') { RTFNewPara(); } else if (uch == '\t') { RTFTab(); } else { RTFPrintExtChar(ConvertGSChar(uch)); } dataBuf++; dataLen--; } } if (dataLen) { LOGI("WARNING: Teach overrun (%ld remain)", dataLen); /* no big deal */ } RTFEnd(); SetResultBuffer(pOutput, true); return 0; }
/* * Convert AWGS into formatted text. */ int ReformatAWGS_WP::Process(const ReformatHolder* pHolder, ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part, ReformatOutput* pOutput) { const uint8_t* srcBuf = pHolder->GetSourceBuf(part); long srcLen = pHolder->GetSourceLen(part); fUseRTF = true; Chunk doc, header, footer; uint16_t val; Charset::CheckGSCharConv(); /* must at least have the doc header and globals */ if (srcLen < kMinExpectedLen) { LOGI("Too short to be AWGS"); return -1; } RTFBegin(kRTFFlagColorTable); /* * Pull interesting values out of the document header. */ val = Get16LE(srcBuf + 0); if (val != kExpectedVersion1 && val != kExpectedVersion2) { LOGI("AWGS_WP: unexpected version number (got 0x%04x, wanted 0x%04x)", val, kExpectedVersion1); DebugBreak(); } val = Get16LE(srcBuf + 2); if (val != kDocHeaderLen) { LOGI("Unexpected doc header len (got 0x%04x, wanted 0x%04x)", val, kDocHeaderLen); return -1; } /* the color table is 32 bytes at +56, should we be interested */ srcBuf += kDocHeaderLen; srcLen -= kDocHeaderLen; /* * Pull interesting values out of the WP global variables section. */ val = Get16LE(srcBuf + 0); if (val > kExpectedIntVersion) { LOGI("Unexpected internal version number (got %d, expected %d)", val, kExpectedIntVersion); return -1; } /* date/time are pascal strings */ LOGI("File saved at '%.26hs' '%.10s'", srcBuf + 6, srcBuf + 32); srcBuf += kWPGlobalsLen; srcLen -= kWPGlobalsLen; /* * Now come the three chunks, in order: main document, header, footer. */ LOGI("AWGS_WP: scanning doc"); if (!ReadChunk(&srcBuf, &srcLen, &doc)) return -1; LOGI("AWGS_WP: scanning header"); if (!ReadChunk(&srcBuf, &srcLen, &header)) return -1; LOGI("AWGS_WP: scanning footer"); if (!ReadChunk(&srcBuf, &srcLen, &footer)) return -1; if (srcLen != 0) { LOGI("AWGS NOTE: %ld bytes left in file", srcLen); } /* * Dump the chunks, starting with header and footer. */ RTFSetColor(kColorMediumBlue); RTFSetFont(kFontCourierNew); RTFSetFontSize(10); BufPrintf("<header>"); RTFSetColor(kColorNone); RTFNewPara(); PrintChunk(&header); RTFSetColor(kColorMediumBlue); RTFSetFont(kFontCourierNew); RTFSetFontSize(10); BufPrintf("</header>"); RTFSetColor(kColorNone); RTFNewPara(); RTFSetColor(kColorMediumBlue); RTFSetFont(kFontCourierNew); RTFSetFontSize(10); BufPrintf("<footer>"); RTFSetColor(kColorNone); RTFNewPara(); PrintChunk(&footer); RTFSetColor(kColorMediumBlue); RTFSetFont(kFontCourierNew); RTFSetFontSize(10); BufPrintf("</footer>"); RTFSetColor(kColorNone); RTFNewPara(); LOGI("AWGS_WP: rendering document"); PrintChunk(&doc); RTFEnd(); SetResultBuffer(pOutput, true); return 0; }