pdfsync.cpp.svn-base
来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· SVN-BASE 代码 · 共 809 行 · 第 1/2 页
SVN-BASE
809 行
// get the file name from the record section
char srcfilename[_MAX_PATH];
tstr_copy(srcfilename, dimof(srcfilename), this->srcfiles[record_sections[sec].srcfile].filename);
// Convert the source filepath to an absolute path
if (PathIsRelative(srcfilename))
_snprintf(srcfilepath, cchFilepath, "%s\\%s", this->dir, srcfilename, dimof(srcfilename));
else
str_copy(srcfilepath, cchFilepath, srcfilename);
// find the record declaration in the section
fsetpos(fp, &record_sections[sec].startpos);
bool found = false;
while (!feof(fp) && !found) {
UINT columnNumber = 0, lineNumber = 0, recordNumber = 0;
int ret = fscanf(fp, "l %u %u %u\n", &recordNumber, &lineNumber, &columnNumber);
if (ret==EOF || ret<2)
DBG_OUT("Bad 'l' line in the pdfsync file\n");
else {
if (recordNumber == selected_record) {
*line = lineNumber;
*col = columnNumber;
found = true;
}
}
}
assert(found);
fclose(fp);
return PDFSYNCERR_SUCCESS;
}
// Find a record corresponding to the given source file, line number and optionally column number.
// (at the moment the column parameter is ignored)
//
// If there are several *consecutively declared* records for the same line then they are all returned.
// The list of records is added to the vector 'records'
//
// If there is no record for that line, the record corresponding to the nearest line is selected
// (within a range of EPSILON_LINE)
//
// The function returns PDFSYNCERR_SUCCESS if a matching record was found.
//
UINT Pdfsync::source_to_record(FILE *fp, LPCTSTR srcfilename, UINT line, UINT col, vector<size_t> &records)
{
// find the source file entry
size_t isrc = (size_t)-1;
for(size_t i=0; i<this->srcfiles.size();i++) {
if (tstr_ieq(srcfilename, this->srcfiles[i].filename)) {
isrc = i;
break;
}
}
if (isrc == (size_t)-1)
return PDFSYNCERR_UNKNOWN_SOURCEFILE;
src_file srcfile=this->srcfiles[isrc];
if (srcfile.first_recordsection == (size_t)-1)
return PDFSYNCERR_NORECORD_IN_SOURCEFILE; // there is not any record declaration for that particular source file
// look for sections belonging to the specified file
// starting with the first section that is declared within the scope of the file.
UINT min_distance = (UINT)-1, // distance to the closest record
closestrec = (UINT)-1, // closest record
closestrecline = (UINT)-1; // closest record-line
fpos_t closestrecline_filepos = -1; // position of the closest record-line in the file
int c;
for(size_t isec=srcfile.first_recordsection; isec<=srcfile.last_recordsection; isec++ ) {
record_section &sec = this->record_sections[isec];
// does this section belong to the desired file?
if (sec.srcfile == isrc) {
// scan the 'l' declarations of the section to find the specified line and column
fpos_t linepos = sec.startpos;
fsetpos(fp, &linepos);
while ((c = fgetc(fp))=='l' && !feof(fp)) {
UINT columnNumber = 0, lineNumber = 0, recordNumber = 0;
fscanf(fp, " %u %u %u\n", &recordNumber, &lineNumber, &columnNumber);
UINT d = abs((int)lineNumber-(int)line);
if (d<EPSILON_LINE && d<min_distance) {
min_distance = d;
closestrec = recordNumber;
closestrecline = lineNumber;
closestrecline_filepos = linepos;
if (d==0)
goto read_linerecords; // We have found a record for the requested line!
}
fgetpos(fp, &linepos);
}
#ifndef NDEBUG
assert(feof(fp) || (linepos == sec.endpos));
#endif
}
}
if (closestrec == (UINT)-1)
return PDFSYNCERR_NORECORD_FOR_THATLINE;
read_linerecords:
// we read all the consecutive records until we reach a record belonging to another line
UINT recordNumber = closestrec, columnNumber, lineNumber;
fsetpos(fp, &closestrecline_filepos);
do {
records.push_back(recordNumber);
columnNumber = 0;
lineNumber = 0;
recordNumber = 0;
fscanf(fp, "%c %u %u %u\n", &c, &recordNumber, &lineNumber, &columnNumber);
} while (c =='l' && !feof(fp) && (lineNumber==closestrecline) );
return PDFSYNCERR_SUCCESS;
}
UINT Pdfsync::source_to_pdf(LPCTSTR srcfilename, UINT line, UINT col, UINT *page, UINT *x, UINT *y)
{
if (this->is_index_discarded())
rebuild_index();
FILE *fp = opensyncfile();
if (!fp)
return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;
vector<size_t> found_records;
UINT ret = source_to_record(fp, srcfilename, line, col, found_records);
if (ret!=PDFSYNCERR_SUCCESS || found_records.size() == 0 ) {
DBG_OUT("source->pdf: %s:%u -> no record found, error:%u\n", srcfilename, line, ret);
fclose(fp);
return ret;
}
// records have been found for the desired source position:
// we now find the pages and position in the PDF corresponding to the first record in the
// list of record found
for(size_t irecord=0;irecord<found_records.size();irecord++) {
size_t record = found_records[irecord];
for(size_t sheet=0;sheet<this->pdfsheet_index.size();sheet++) {
if (this->pdfsheet_index[sheet] != (size_t)-1) {
fsetpos(fp, &this->pline_sections[this->pdfsheet_index[sheet]].startpos);
int c;
while ((c = fgetc(fp))=='p' && !feof(fp)) {
// skip the optional star
if (fgetc(fp)=='*')
fgetc(fp);
// read the location
UINT recordNumber = 0, xPosition = 0, yPosition = 0;
fscanf(fp, "%u %u %u\n", &recordNumber, &xPosition, &yPosition);
if (recordNumber == record) {
*page = sheet;
*x = (UINT)SYNCCOORDINATE_TO_PDFCOORDINATE(xPosition);
*y = (UINT)SYNCCOORDINATE_TO_PDFCOORDINATE(yPosition);
DBG_OUT("source->pdf: %s:%u -> record:%u -> page:%u, x:%u, y:%u\n", srcfilename, line, record, sheet, *x, *y);
fclose(fp);
return PDFSYNCERR_SUCCESS;
}
}
#ifndef NDEBUG
fpos_t linepos;
fgetpos(fp, &linepos);
assert(feof(fp) || (linepos-1==this->pline_sections[this->pdfsheet_index[sheet]].endpos));
#endif
}
}
}
// the record does not correspond to any point in the PDF: this is possible...
fclose(fp);
return PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD;
}
// SYNCTEX synchronizer
#ifdef SYNCTEX_FEATURE
int SyncTex::rebuild_index() {
if (this->scanner)
synctex_scanner_free(this->scanner);
this->scanner = synctex_scanner_new_with_output_file(this->syncfilename, NULL, 1);
if (scanner)
return Synchronizer::rebuild_index();
else
return 1; // cannot rebuild the index
}
UINT SyncTex::pdf_to_source(UINT sheet, UINT x, UINT y, PTSTR srcfilepath, UINT cchFilepath, UINT *line, UINT *col)
{
if (this->is_index_discarded())
if (rebuild_index())
return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;
if (synctex_edit_query(this->scanner,sheet,x,y)>0) {
synctex_node_t node;
char srcfilename[_MAX_PATH];
while (node = synctex_next_result(this->scanner)) {
*line = synctex_node_line(node);
*col = synctex_node_column(node);
str_copy( srcfilename, dimof(srcfilename), synctex_scanner_get_name(this->scanner,synctex_node_tag(node)));
// Convert the source filepath to an absolute path
if (PathIsRelative(srcfilename))
_snprintf(srcfilepath, cchFilepath, "%s\\%s", this->dir, srcfilename, dimof(srcfilename));
else
str_copy(srcfilepath, cchFilepath, srcfilename);
return PDFSYNCERR_SUCCESS;
}
}
return PDFSYNCERR_NO_SYNC_AT_LOCATION;
// return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;
}
UINT SyncTex::source_to_pdf(LPCTSTR srcfilename, UINT line, UINT col, UINT *page, UINT *x, UINT *y)
{
if (this->is_index_discarded())
if (rebuild_index())
return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;
// convert the source file to an absolute path
char srcfilepath[_MAX_PATH];
if (PathIsRelative(srcfilename))
_snprintf(srcfilepath, dimof(srcfilepath), "%s\\%s", this->dir, srcfilename, dimof(srcfilename));
else
str_copy(srcfilepath, dimof(srcfilepath), srcfilename);
switch (synctex_display_query(this->scanner,srcfilepath,line,col)) {
case -1:
return PDFSYNCERR_UNKNOWN_SOURCEFILE;
case 0:
return PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD;
default:
synctex_node_t node;
while (node = synctex_next_result(this->scanner)) {
*page = synctex_node_page(node);
*x = SYNCCOORDINATE_TO_PDFCOORDINATE(synctex_node_box_h(node));
*y = SYNCCOORDINATE_TO_PDFCOORDINATE(synctex_node_box_v(node));
return PDFSYNCERR_SUCCESS;
}
return PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD;
}
//#else
//return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;
//#endif
}
#endif
// DDE commands handling
LRESULT OnDDEInitiate(HWND hwnd, WPARAM wparam, LPARAM lparam)
{
DBG_OUT("received WM_DDE_INITIATE from %p with %08lx\n", (HWND)wparam, lparam);
ATOM aServer = GlobalAddAtomW(PDFSYNC_DDE_SERVICE_W);
ATOM aTopic = GlobalAddAtomW(PDFSYNC_DDE_TOPIC_W);
if (LOWORD(lparam) == aServer && HIWORD(lparam) == aTopic) {
if (IsWindowUnicode((HWND)wparam))
DBG_OUT("The client window is ANSI!\n");
DBG_OUT("Sending WM_DDE_ACK to %p\n", (HWND)wparam);
SendMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, MAKELPARAM(aServer, 0));
}
else {
GlobalDeleteAtom(aServer);
GlobalDeleteAtom(aTopic);
}
return 0;
}
// DDE commands
LRESULT OnDDExecute(HWND hwnd, WPARAM wparam, LPARAM lparam)
{
DBG_OUT("Received WM_DDE_EXECUTE from %p with %08lx\n", (HWND)wparam, lparam);
UINT_PTR lo, hi;
UnpackDDElParam(WM_DDE_EXECUTE, lparam, &lo, &hi);
DBG_OUT("%08lx => lo %04x hi %04x\n", lparam, lo, hi);
DDEACK ack;
ack.bAppReturnCode = 0;
ack.reserved = 0;
ack.fBusy = 0;
PCSTR command = (LPCSTR)GlobalLock((HGLOBAL)hi);
ack.fAck = 0;
if (!command)
DBG_OUT("WM_DDE_EXECUTE: No command specified\n");
else {
// Parse the command
char pdffile[_MAX_PATH];
char srcfile[_MAX_PATH];
char destname[_MAX_PATH];
char dump[_MAX_PATH];
UINT line,col, newwindow = 0, setfocus = 0, forcerefresh = 0;
const char *pos;
pos = command;
while (pos < (command + strlen(command))) {
// Synchronization command.
// format is [<DDECOMMAND_SYNC_A>("<pdffile>","<srcfile>",<line>,<col>[,<newwindow>,<setfocus>])]
if ( (pos = command) &&
str_skip(&pos, "[" DDECOMMAND_SYNC_A "(\"") &&
str_copy_skip_until(&pos, pdffile, dimof(pdffile), '"') &&
str_skip(&pos, "\",\"") &&
str_copy_skip_until(&pos, srcfile, dimof(srcfile), '"') &&
(4 == sscanf(pos, "\",%u,%u,%u,%u)]", &line, &col, &newwindow, &setfocus)
|| 2 == sscanf(pos, "\",%u,%u)]", &line, &col))
)
{
// Execute the command.
// check if the PDF is already opened
WindowInfo *win = WindowInfoList_Find(pdffile);
// if not then open it
if (newwindow || !win || WS_SHOWING_PDF != win->state)
win = LoadPdf(pdffile);
if (win && WS_SHOWING_PDF == win->state ) {
if (!win->pdfsync)
DBG_OUT("PdfSync: No sync file loaded!\n");
else {
ack.fAck = 1;
assert(win->dm);
UINT page, x, y;
UINT ret = win->pdfsync->source_to_pdf(srcfile, line, col, &page, &x, &y);
WindowInfo_ShowForwardSearchResult(win, srcfile, line, col, ret, page, x, y);
if (setfocus)
SetFocus(win->hwndFrame);
}
}
}
// Open file DDE command.
// format is [<DDECOMMAND_OPEN_A>("<pdffilepath>"[,<newwindow>,<setfocus>,<forcerefresh>])]
else if ( (pos = command) &&
str_skip(&pos, "[" DDECOMMAND_OPEN_A "(\"") &&
str_copy_skip_until(&pos, pdffile, dimof(pdffile), '"') &&
(3 == sscanf(pos, "\",%u,%u,%u)]", &newwindow, &setfocus, &forcerefresh) || str_skip(&pos, "\")"))
)
{
// check if the PDF is already opened
WindowInfo *win = WindowInfoList_Find(pdffile);
// if not then open it
if ( newwindow || !win || WS_SHOWING_PDF != win->state)
win = LoadPdf(pdffile);
if (win && WS_SHOWING_PDF == win->state ) {
ack.fAck = 1;
if (forcerefresh)
PostMessage(win->hwndFrame, WM_CHAR, 'r', 0);
if (setfocus)
SetFocus(win->hwndFrame);
}
}
// Jump to named destination DDE command.
// format is [<DDECOMMAND_GOTO_A>("<pdffilepath>", "<destination name>")]
else if ( (pos = command) &&
str_skip(&pos, "[" DDECOMMAND_GOTO_A "(\"") &&
str_copy_skip_until(&pos, pdffile, dimof(pdffile), '"') &&
str_skip(&pos, "\",\"") &&
str_copy_skip_until(&pos, destname, dimof(destname), '"')
)
{
// check if the PDF is already opened
WindowInfo *win = WindowInfoList_Find(pdffile);
if (win && WS_SHOWING_PDF == win->state) {
win->dm->goToNamedDest(destname);
ack.fAck = 1;
SetFocus(win->hwndFrame);
}
}
else
DBG_OUT("WM_DDE_EXECUTE: unknown DDE command or bad command format\n");
// next command
str_copy_skip_until(&pos, dump, dimof(dump), ']');
str_skip(&pos, "]");
command = pos;
}
}
GlobalUnlock((HGLOBAL)hi);
DBG_OUT("Posting %s WM_DDE_ACK to %p\n", ack.fAck ? "ACCEPT" : "REJECT", (HWND)wparam);
WORD status = * (WORD *) & ack;
lparam = ReuseDDElParam(lparam, WM_DDE_EXECUTE, WM_DDE_ACK, status, hi);
PostMessageW((HWND)wparam, WM_DDE_ACK, (WPARAM)hwnd, lparam);
return 0;
}
LRESULT OnDDETerminate(HWND hwnd, WPARAM wparam, LPARAM lparam)
{
DBG_OUT("Received WM_DDE_TERMINATE from %p with %08lx\n", (HWND)wparam, lparam);
// Respond with another WM_DDE_TERMINATE message
PostMessage((HWND)wparam, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L);
return 0;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?