Esempio n. 1
0
// see http://itexmac.sourceforge.net/pdfsync.html for the specification
int Pdfsync::RebuildIndex()
{
    size_t len;
    ScopedMem<char> data(file::ReadAll(syncfilepath, &len));
    if (!data)
        return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;
    // convert the file data into a list of zero-terminated strings
    str::TransChars(data, "\r\n", "\0\0");

    // parse preamble (jobname and version marker)
    char *line = data;
    char *dataEnd = data + len;

    // replace star by spaces (TeX uses stars instead of spaces in filenames)
    str::TransChars(line, "*/", " \\");
    ScopedMem<TCHAR> jobName(str::conv::FromAnsi(line));
    jobName.Set(str::Join(jobName, _T(".tex")));
    jobName.Set(PrependDir(jobName));

    line = Advance0Line(line, dataEnd);
    UINT versionNumber = 0;
    if (!line || !str::Parse(line, "version %u", &versionNumber) || versionNumber != 1)
        return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;

    // reset synchronizer database
    srcfiles.Reset();
    lines.Reset();
    points.Reset();
    fileIndex.Reset();
    sheetIndex.Reset();

    Vec<size_t> filestack;
    UINT page = 1;
    sheetIndex.Append(0);

    // add the initial tex file to the source file stack
    filestack.Push(srcfiles.Count());
    srcfiles.Append(jobName.StealData());
    PdfsyncFileIndex findex = { 0 };
    fileIndex.Append(findex);

    PdfsyncLine psline;
    PdfsyncPoint pspoint;

    // parse data
    UINT maxPageNo = engine->PageCount();
    while ((line = Advance0Line(line, dataEnd))) {
        switch (*line) {
        case 'l':
            psline.file = filestack.Last();
            if (str::Parse(line, "l %u %u %u", &psline.record, &psline.line, &psline.column))
                lines.Append(psline);
            else if (str::Parse(line, "l %u %u", &psline.record, &psline.line)) {
                psline.column = 0;
                lines.Append(psline);
            }
            // else dbg("Bad 'l' line in the pdfsync file");
            break;

        case 's':
            if (str::Parse(line, "s %u", &page))
                sheetIndex.Append(points.Count());
            // else dbg("Bad 's' line in the pdfsync file");
            // if (0 == page || page > maxPageNo)
            //     dbg("'s' line with invalid page number in the pdfsync file");
            break;

        case 'p':
            pspoint.page = page;
            if (0 == page || page > maxPageNo)
                /* ignore point for invalid page number */;
            else if (str::Parse(line, "p %u %u %u", &pspoint.record, &pspoint.x, &pspoint.y))
                points.Append(pspoint);
            else if (str::Parse(line, "p* %u %u %u", &pspoint.record, &pspoint.x, &pspoint.y))
                points.Append(pspoint);
            // else dbg("Bad 'p' line in the pdfsync file");
            break;

        case '(':
            {
                ScopedMem<TCHAR> filename(str::conv::FromAnsi(line + 1));
                // if the filename contains quotes then remove them
                // TODO: this should never happen!?
                if (filename[0] == '"' && filename[str::Len(filename) - 1] == '"')
                    filename.Set(str::DupN(filename + 1, str::Len(filename) - 2));
                // undecorate the filepath: replace * by space and / by \ 
                str::TransChars(filename, _T("*/"), _T(" \\"));
                // if the file name extension is not specified then add the suffix '.tex'
                if (str::IsEmpty(path::GetExt(filename)))
                    filename.Set(str::Join(filename, _T(".tex")));
                // ensure that the path is absolute
                if (PathIsRelative(filename))
                    filename.Set(PrependDir(filename));

                filestack.Push(srcfiles.Count());
                srcfiles.Append(filename.StealData());
                findex.start = findex.end = lines.Count();
                fileIndex.Append(findex);
            }
            break;

        case ')':
            if (filestack.Count() > 1)
                fileIndex.At(filestack.Pop()).end = lines.Count();
            // else dbg("Unbalanced ')' line in the pdfsync file");
            break;

        default:
            // dbg("Ignoring invalid pdfsync line starting with '%c'", *line);
            break;
        }
    }

    fileIndex.At(0).end = lines.Count();
    assert(filestack.Count() == 1);

    return Synchronizer::RebuildIndex();
}