/* * 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; }
/* * Print one paragraph. * * Stop when we hit '\r'. We watch "maxLen" just to be safe. * * Returns the #of bytes consumed. */ int ReformatAWGS_WP::PrintParagraph(const uint8_t* ptr, long maxLen) { const uint8_t* startPtr = ptr; uint16_t firstFont; uint8_t firstStyle, firstSize, firstColor; uint8_t uch; if (maxLen < 7) { LOGI("AWGS_WP GLITCH: not enough storage for para header (%d)", maxLen); return 1; // don't return zero or we might loop forever } /* pull out the paragraph header */ firstFont = Get16LE(ptr); firstStyle = *(ptr + 2); firstSize = *(ptr + 3); firstColor = *(ptr + 4); ptr += 7; maxLen -= 7; /* * 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. */ //LOGI("+++ Para start: font=0x%04x size=%d style=0x%02x", // firstFont, firstSize, firstStyle); RTFSetGSFont(firstFont); RTFSetGSFontSize(firstSize); RTFSetGSFontStyle(firstStyle); while (maxLen > 0) { uch = *ptr++; maxLen--; switch (uch) { case 0x01: // font change - two bytes follow if (maxLen >= 2) { RTFSetGSFont(Get16LE(ptr)); ptr += 2; maxLen -= 2; } break; case 0x02: // text style change if (maxLen >= 1) { RTFSetGSFontStyle(*ptr++); maxLen--; } break; case 0x03: // text size change if (maxLen >= 1) { RTFSetGSFontSize(*ptr++); maxLen--; } break; case 0x04: // color change (0-15) if (maxLen >= 1) { ptr++; maxLen--; } break; case 0x05: // page token (replace with page #) case 0x06: // date token (replace with date) case 0x07: // time token (replace with time) RTFSetColor(kColorMediumBlue); if (uch == 0x05) BufPrintf("<page>"); else if (uch == 0x06) BufPrintf("<date>"); else BufPrintf("<time>"); RTFSetColor(kColorNone); break; case '\r': RTFNewPara(); return ptr - startPtr; case '\t': RTFTab(); break; default: RTFPrintUTF16Char(Charset::ConvertMacRomanToUTF16(uch)); break; } } LOGI("AWGS_WP: WARNING: ran out of data before hitting '\r'"); return ptr - startPtr; }