Fields.cpp
4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
This file is a part of the NVDA project.
URL: http://www.nvda-project.org/
Copyright 2006-2010 NVDA contributers.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2.0, as published by
the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
This license can be found at:
http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/
#define WIN32_LEAN_AND_MEAN
#include <sstream>
#include <vector>
#include <utility>
#include <comdef.h>
#include <windows.h>
#include <common/log.h>
#include <remote/nvdaInProcUtils.h>
#include <remote/nvdaInProcUtils.h>
#include "Fields.h"
#include <remote/WinWord/Constants.h>
namespace WinWord {
/* Overview of the structures being accessed:
pRange.Fields property
pRange.Fields.Count property
pRange.Fields.Item method - takes an int (starting at 1) to give item 1 up to item Count. Returns a Field
Field.Type property
Field.Result property - the range for the ref / hyperlink object. This is the displayed range.
Field.Code property - Not used, but gives the hidden part of the ref / hyperlink.
Field.Result.Start property
Field.Result.End property
*/
Fields::Fields(IDispatch* pRange) {
IDispatchPtr pDispatchFields = nullptr;
auto res = _com_dispatch_raw_propget( pRange, wdDISPID_RANGE_FIELDS, VT_DISPATCH, &pDispatchFields);
if( res != S_OK || !pDispatchFields ) {
LOG_DEBUGWARNING(L"error getting fields from range");
return;
}
int count = 0;
res = _com_dispatch_raw_propget( pDispatchFields, wdDISPID_FIELDS_COUNT, VT_I4, &count);
if( res != S_OK || count <= 0 ) {
return;
}
for(int i = 1; i <= count; ++i) {
IDispatchPtr pDispatchItem = nullptr;
res = _com_dispatch_raw_method( pDispatchFields, wdDISPID_FIELDS_ITEM, DISPATCH_METHOD, VT_DISPATCH, &pDispatchItem, L"\x0003", i);
if( res != S_OK || !pDispatchItem){
LOG_DEBUGWARNING(L"error getting field item");
continue;
}
/*
Fields can be of many types, to get this we look at Type property. We care about:
Ref - a Reference to some other part of the file
Hyperlink - a link to another part of the file or to an external URL
The following are defined on msdn (WdFieldType Enumeration - https://msdn.microsoft.com/en-us/library/office/ff192211.aspx)
*/
const int CROSS_REFERENCE_TYPE_VALUE = 3; // wdFieldRef
const int HYPERLINK_TYPE_VALUE = 88; // wdFieldHyperlink
const int PAGE_NUMBER_TYPE_VALUE = 33; // wdFieldPage
int type = -1;
res = _com_dispatch_raw_propget( pDispatchItem, wdDISPID_FIELDS_ITEM_TYPE, VT_I4, &type);
if( res != S_OK || !(type == CROSS_REFERENCE_TYPE_VALUE || type == HYPERLINK_TYPE_VALUE || type == PAGE_NUMBER_TYPE_VALUE) ){
continue;
}
IDispatchPtr pDispatchFieldResult = nullptr;
res = _com_dispatch_raw_propget( pDispatchItem, wdDISPID_FIELDS_ITEM_RESULT, VT_DISPATCH, &pDispatchFieldResult);
if( res != S_OK || !pDispatchFieldResult){
LOG_DEBUGWARNING(L"error getting the result from the field item.");
continue;
}
long resultStart = 0, resultEnd = 0;
auto ok = S_OK == _com_dispatch_raw_propget( pDispatchFieldResult, wdDISPID_RANGE_START, VT_I4, &resultStart)
&& S_OK == _com_dispatch_raw_propget( pDispatchFieldResult, wdDISPID_RANGE_END, VT_I4, &resultEnd);
if(!ok){
LOG_DEBUGWARNING(L"error getting range start and end points");
continue;
}
auto itemRange = std::make_pair(resultStart, resultEnd);
switch(type){
case CROSS_REFERENCE_TYPE_VALUE: // intentional fall through to hyperlink case
case HYPERLINK_TYPE_VALUE:
m_links.push_back(itemRange);
break;
case PAGE_NUMBER_TYPE_VALUE:
m_pageNumbers.push_back(itemRange);
break;
}
}
}
bool inRange (long index, long start, long end) {
return index >= start && index <= end;
};
bool Fields::hasLinks(const int rangeStart, const int rangeEnd){
for( auto&& link : m_links) {
if( inRange(link.first, rangeStart, rangeEnd) ||
inRange(link.second, rangeStart, rangeEnd) ||
inRange(rangeStart, link.first, link.second) ||
inRange(rangeEnd, link.first, link.second) ){
return true;
}
}
return false;
}
bool Fields::hasLinks(){
return false == m_links.empty();
}
std::experimental::optional<int> Fields::getEndOfPageNumberFieldAtIndex(const int index){
for( auto&& pageNum : m_pageNumbers ){
if(inRange(index, pageNum.first, pageNum.second)){
return pageNum.second;
}
}
return std::experimental::optional<int>();
}
} // end namespace WinWord