Example #1
0
/*
 * 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;
}
Example #2
0
/*
 * 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;
}
Example #3
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;
}
Example #4
0
/*
 * 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;
}
Example #5
0
/*
 * 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;
}
Example #6
0
/*
 * 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;
}
Example #7
0
/*
 * 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;
}
Example #8
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;
}