Compare commits
457 Commits
version/3.
...
version/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09ab029e2f | ||
|
|
da2f365cd2 | ||
|
|
496d458d22 | ||
|
|
9dda5a4e31 | ||
|
|
289daf0fbc | ||
|
|
61e2d2dd3b | ||
|
|
2523236cec | ||
|
|
1c182ff69d | ||
|
|
757970fe41 | ||
|
|
6e904ba1aa | ||
|
|
616826ab69 | ||
|
|
6e4da15a58 | ||
|
|
561e451192 | ||
|
|
74b4df9452 | ||
|
|
862980a67a | ||
|
|
5fb8891e86 | ||
|
|
f3d68a170e | ||
|
|
1fe8931129 | ||
|
|
d39b055ed1 | ||
|
|
639e16b722 | ||
|
|
9456ff838c | ||
|
|
eac3402176 | ||
|
|
9a29f54f8a | ||
|
|
5e7b5cbf68 | ||
|
|
bba11c18d1 | ||
|
|
379a171d24 | ||
|
|
87eaec3ce7 | ||
|
|
b5dace5f08 | ||
|
|
5ecf07e92d | ||
|
|
53d8dcfc77 | ||
|
|
6b31646d61 | ||
|
|
06f888d38c | ||
|
|
51ad61061f | ||
|
|
ff5b09c97b | ||
|
|
46ed4b2f79 | ||
|
|
8582676100 | ||
|
|
32181a3956 | ||
|
|
c17324b5ea | ||
|
|
a3f1bb546f | ||
|
|
493aab8bab | ||
|
|
92a51059b4 | ||
|
|
177c5ec709 | ||
|
|
63b2b04977 | ||
|
|
2e1f01a86a | ||
|
|
27baafab0d | ||
|
|
8ddcef9142 | ||
|
|
aa679ffb86 | ||
|
|
4fdcfb8623 | ||
|
|
c199c95218 | ||
|
|
3f9b6d632e | ||
|
|
714a6ac47d | ||
|
|
2438dd8a08 | ||
|
|
49146f41e3 | ||
|
|
8009a33b26 | ||
|
|
b8d07cc460 | ||
|
|
43dacf5951 | ||
|
|
8adbefb2b7 | ||
|
|
4eb272f4f0 | ||
|
|
f84dac822a | ||
|
|
0b4f416ddc | ||
|
|
6cef1f9091 | ||
|
|
5c9f5361bd | ||
|
|
ce245059b8 | ||
|
|
4fb205b317 | ||
|
|
624dae5958 | ||
|
|
d4384422f4 | ||
|
|
935d649096 | ||
|
|
2b147f7429 | ||
|
|
da6b395008 | ||
|
|
dda922a651 | ||
|
|
d179fccfcb | ||
|
|
ae4d96872d | ||
|
|
7075a8707b | ||
|
|
4b7f7861cd | ||
|
|
e7598df4d3 | ||
|
|
63e7a1fbb4 | ||
|
|
951859d8a7 | ||
|
|
41f40a9a10 | ||
|
|
a6290e367a | ||
|
|
af0a51930e | ||
|
|
ccb5d05eb4 | ||
|
|
9d7402242a | ||
|
|
819833a560 | ||
|
|
576ff21488 | ||
|
|
b60f8b4989 | ||
|
|
096d625445 | ||
|
|
dad77b3983 | ||
|
|
598b64fa95 | ||
|
|
b5d6aa3fe4 | ||
|
|
f32063e6dd | ||
|
|
3d9d44cf73 | ||
|
|
ac84115ac3 | ||
|
|
d58607242e | ||
|
|
7afd2be652 | ||
|
|
f256d45b65 | ||
|
|
edf15e9f55 | ||
|
|
2bb24f43fb | ||
|
|
be0447d4c0 | ||
|
|
ef7a0dc5a3 | ||
|
|
5d754c0419 | ||
|
|
1f23fb89c0 | ||
|
|
584ee1364f | ||
|
|
1e32c24a17 | ||
|
|
20ea55bdbc | ||
|
|
c62b4467b4 | ||
|
|
31095c39cc | ||
|
|
05d9d7cae8 | ||
|
|
78a548b861 | ||
|
|
6be4ad27ee | ||
|
|
589c5ba35a | ||
|
|
81d668784a | ||
|
|
75ad5a7e5c | ||
|
|
3f20a3d2c6 | ||
|
|
a57e969639 | ||
|
|
23b8c86e78 | ||
|
|
5c9ca9cbe2 | ||
|
|
5676f96fbf | ||
|
|
4104f7d18f | ||
|
|
10e6bbc2c5 | ||
|
|
21e6dd34b2 | ||
|
|
319922f044 | ||
|
|
ff3efaee93 | ||
|
|
08fb433923 | ||
|
|
1a752d28a4 | ||
|
|
00a20409f7 | ||
|
|
3bfd0c872a | ||
|
|
945cf5d963 | ||
|
|
4e40913aef | ||
|
|
3bc53474ed | ||
|
|
28dff1d5ca | ||
|
|
81bfec336c | ||
|
|
60a0c51e2b | ||
|
|
70c5d60564 | ||
|
|
1b2247103a | ||
|
|
a49c3a49d3 | ||
|
|
105438fc58 | ||
|
|
2910c6a77b | ||
|
|
6dd859c75e | ||
|
|
b7c7f66bf3 | ||
|
|
c7a60d4dc4 | ||
|
|
a841fcc89e | ||
|
|
b91d1a3f6a | ||
|
|
1378511c13 | ||
|
|
9a9cd62957 | ||
|
|
a9742fba7c | ||
|
|
9ea772f938 | ||
|
|
e64902ae8c | ||
|
|
0b1399479a | ||
|
|
0369d1f506 | ||
|
|
f19cf6d56a | ||
|
|
d12d1b2c3a | ||
|
|
b7fbb79565 | ||
|
|
541239ceac | ||
|
|
fd74095939 | ||
|
|
b24d190e55 | ||
|
|
8b351520bd | ||
|
|
5bbdcfd240 | ||
|
|
51ff30f386 | ||
|
|
6683092bb2 | ||
|
|
2c6f9de020 | ||
|
|
686f095f1e | ||
|
|
089fc5ea0a | ||
|
|
72ae14227e | ||
|
|
0e9948f9d4 | ||
|
|
0b6738b616 | ||
|
|
3c204e84f4 | ||
|
|
7774b76ad2 | ||
|
|
acd655b37b | ||
|
|
1a09683351 | ||
|
|
181afb7fd0 | ||
|
|
9d1354f6bd | ||
|
|
596591bb64 | ||
|
|
a67a984d29 | ||
|
|
37a963da92 | ||
|
|
384a700e05 | ||
|
|
7d2ecef14a | ||
|
|
bc72c34d0f | ||
|
|
ca7acb1f2c | ||
|
|
1365a02aea | ||
|
|
611785c04b | ||
|
|
e5995208a9 | ||
|
|
6f15bb415f | ||
|
|
ce7f78e0ca | ||
|
|
6323477a35 | ||
|
|
8c38f799ad | ||
|
|
1bf0b7222d | ||
|
|
0cc5374fe7 | ||
|
|
b2ac9982d4 | ||
|
|
84cbfb2e98 | ||
|
|
7479cadbba | ||
|
|
f711306085 | ||
|
|
148640be34 | ||
|
|
27a91062bd | ||
|
|
dc1816bb08 | ||
|
|
e836e85697 | ||
|
|
2d00653f6e | ||
|
|
4647ce2da5 | ||
|
|
51d43f809e | ||
|
|
370a115ab9 | ||
|
|
32b60f9b80 | ||
|
|
beeaef3868 | ||
|
|
ddd9691439 | ||
|
|
9da0031039 | ||
|
|
9537876bba | ||
|
|
958ae9bdf0 | ||
|
|
023b5a09f7 | ||
|
|
46fe57fb8d | ||
|
|
07e09bb88c | ||
|
|
1b7f310ea6 | ||
|
|
365ddb84a7 | ||
|
|
5fef44b11c | ||
|
|
1480aa9bb8 | ||
|
|
75271c44a8 | ||
|
|
543f1b7902 | ||
|
|
93a63a0678 | ||
|
|
2bf79a2fa1 | ||
|
|
ab956f15c3 | ||
|
|
deceee8997 | ||
|
|
b3c7d63809 | ||
|
|
2026c665b2 | ||
|
|
36fd005bb9 | ||
|
|
46bed67cce | ||
|
|
5b9af0c0aa | ||
|
|
85090180d0 | ||
|
|
f33ad357e9 | ||
|
|
c30ce67e16 | ||
|
|
3ca7369fb2 | ||
|
|
088ce31f7c | ||
|
|
4f94c22241 | ||
|
|
e1791b3006 | ||
|
|
e608ed5a01 | ||
|
|
35ebb16215 | ||
|
|
68d0891665 | ||
|
|
b11ff19a0f | ||
|
|
e7e616e07c | ||
|
|
14f2f9e917 | ||
|
|
791273c61d | ||
|
|
519326f751 | ||
|
|
d1f5d92a7b | ||
|
|
f448898531 | ||
|
|
d9b66fc0ef | ||
|
|
3bcd0bafd5 | ||
|
|
942181c8ae | ||
|
|
7df39b9fc8 | ||
|
|
f41b18f064 | ||
|
|
c5d649aa0b | ||
|
|
64ac22f50c | ||
|
|
719ee36f5c | ||
|
|
92851135d4 | ||
|
|
76fc47b24b | ||
|
|
f25abad9d7 | ||
|
|
23413b4781 | ||
|
|
e036dfc5bf | ||
|
|
9260bea850 | ||
|
|
c1f09034e0 | ||
|
|
557e4f75b5 | ||
|
|
e71d6b24d7 | ||
|
|
726a4c6d10 | ||
|
|
6af8d32078 | ||
|
|
f6b16e2ba8 | ||
|
|
e415b08da4 | ||
|
|
1d93e8d61e | ||
|
|
4bd34991e9 | ||
|
|
9709cfe20d | ||
|
|
a5e99ea996 | ||
|
|
d9df10fe10 | ||
|
|
f1677f5546 | ||
|
|
cb796e374a | ||
|
|
7c3491c679 | ||
|
|
6200b160ec | ||
|
|
9868fb03a2 | ||
|
|
a69130ff10 | ||
|
|
0b60643053 | ||
|
|
dc4644bf3a | ||
|
|
38b766f845 | ||
|
|
10d0be013e | ||
|
|
5126ae5891 | ||
|
|
49bcf49db1 | ||
|
|
3bbb272ad5 | ||
|
|
645cae184b | ||
|
|
bd9fa7017f | ||
|
|
fc9f3abfbb | ||
|
|
f2f1b36df9 | ||
|
|
03d2a166b7 | ||
|
|
f0a76aa918 | ||
|
|
c144c3562c | ||
|
|
e06f9462ab | ||
|
|
9aa5c3b2ae | ||
|
|
2c41c25fcd | ||
|
|
9ffc0ae8bc | ||
|
|
bb5e07d958 | ||
|
|
5024b62c0a | ||
|
|
82d5c605e5 | ||
|
|
737b1948bf | ||
|
|
1225e53162 | ||
|
|
b58bf443ff | ||
|
|
9bef80fbef | ||
|
|
36cb7a752b | ||
|
|
d3b211e787 | ||
|
|
e3f0fad272 | ||
|
|
e8f10dd2e8 | ||
|
|
edbfbd769e | ||
|
|
dc60cf0e67 | ||
|
|
083b364afd | ||
|
|
dd2bf418b9 | ||
|
|
97cc250047 | ||
|
|
49fc75926e | ||
|
|
9880ba39a7 | ||
|
|
a8c8148068 | ||
|
|
adebbe006b | ||
|
|
c3bc73ab2f | ||
|
|
c716cfbb07 | ||
|
|
ade4627f1a | ||
|
|
e508ff724c | ||
|
|
c54e3f8101 | ||
|
|
6925c2a2be | ||
|
|
398bf740d7 | ||
|
|
e302ad092e | ||
|
|
7a65d42a4c | ||
|
|
d3a14bfd61 | ||
|
|
03cafe4547 | ||
|
|
e5acc3f048 | ||
|
|
4931ce0364 | ||
|
|
e3d53e854a | ||
|
|
bdf6b25338 | ||
|
|
5dddba26ac | ||
|
|
746fa419ed | ||
|
|
7080f919e9 | ||
|
|
c4e0014d74 | ||
|
|
7d9797e091 | ||
|
|
67a8d8049f | ||
|
|
c3670b211f | ||
|
|
32274027ef | ||
|
|
d09943cbb8 | ||
|
|
150039f9ba | ||
|
|
820a315cbe | ||
|
|
8abe4622b9 | ||
|
|
da6ab1eabc | ||
|
|
e3ddcbe2dd | ||
|
|
b36cdebe8b | ||
|
|
3c0544c9a6 | ||
|
|
be358f8d24 | ||
|
|
e1abab393b | ||
|
|
0b21181f1a | ||
|
|
dfdd1c6d5e | ||
|
|
a8e96997cb | ||
|
|
6db07373ee | ||
|
|
36ae8cdce3 | ||
|
|
d77ba7d2db | ||
|
|
6e58fdac85 | ||
|
|
3f6933940e | ||
|
|
4bd8fe5855 | ||
|
|
9c421d55a9 | ||
|
|
1af6cbc1aa | ||
|
|
a9e7af6e6e | ||
|
|
c967fbc0a6 | ||
|
|
6929ba75c0 | ||
|
|
289777bd99 | ||
|
|
7535dfd2d0 | ||
|
|
23279b4d0a | ||
|
|
d34d3ecfb1 | ||
|
|
55f18574aa | ||
|
|
02ac1a43c1 | ||
|
|
b2c3a90adf | ||
|
|
9975c751a7 | ||
|
|
efbec8b367 | ||
|
|
9642f6d946 | ||
|
|
247aa49849 | ||
|
|
edaae885ee | ||
|
|
b101f64cd8 | ||
|
|
f75d1cbcb1 | ||
|
|
ac2e80dc07 | ||
|
|
85b17ae8d4 | ||
|
|
77955e5c3c | ||
|
|
19481983e5 | ||
|
|
5b2b420c48 | ||
|
|
15d3c12139 | ||
|
|
338a748823 | ||
|
|
8c45796dc8 | ||
|
|
a160e176da | ||
|
|
d332da0605 | ||
|
|
6ea55c6851 | ||
|
|
10ee7a901f | ||
|
|
db8b60ec49 | ||
|
|
09d47e7f55 | ||
|
|
13a3ea3503 | ||
|
|
ff53792e4f | ||
|
|
fd51518d92 | ||
|
|
01a43b49a5 | ||
|
|
3525fff8d0 | ||
|
|
6c75e2fe3c | ||
|
|
b322864ef4 | ||
|
|
f28e3fc9bb | ||
|
|
80e77b8372 | ||
|
|
c925b7b601 | ||
|
|
966789de90 | ||
|
|
d44a3117d9 | ||
|
|
c851c449da | ||
|
|
b2d9385f46 | ||
|
|
f40efe66fa | ||
|
|
5560479665 | ||
|
|
4ea8e4774e | ||
|
|
18ff03acdf | ||
|
|
aa27a09801 | ||
|
|
a8d7645004 | ||
|
|
081aafb914 | ||
|
|
5a5ba08c23 | ||
|
|
91b92c5613 | ||
|
|
bd5bc9cda0 | ||
|
|
db684eb33e | ||
|
|
a07cfdb683 | ||
|
|
b956a2c834 | ||
|
|
ba38688a83 | ||
|
|
3429e00721 | ||
|
|
32a6bd78d8 | ||
|
|
b2cedc5332 | ||
|
|
94bbed80d0 | ||
|
|
b4ecb6f2db | ||
|
|
3b5665fe92 | ||
|
|
b4f4ef9c5b | ||
|
|
3c4c05fb3e | ||
|
|
b0cad59508 | ||
|
|
d4030e72e4 | ||
|
|
481f7e3bfa | ||
|
|
c35243e215 | ||
|
|
00d8849a28 | ||
|
|
6b9ce935cd | ||
|
|
e440aba0d2 | ||
|
|
574d459f4e | ||
|
|
5fa0931a89 | ||
|
|
748b13850a | ||
|
|
9a09a6a447 | ||
|
|
79c56c924f | ||
|
|
eef73953cb | ||
|
|
781682f4ee | ||
|
|
4a10806352 | ||
|
|
13ae2f08ee | ||
|
|
3e8aeccc87 | ||
|
|
de39e0093a | ||
|
|
943f52aedf | ||
|
|
46eb2f439d | ||
|
|
4f5c519636 | ||
|
|
8f6677974e | ||
|
|
0f5cbc35a2 | ||
|
|
c54b1e037a | ||
|
|
0d19be2196 | ||
|
|
c1b579ec5d | ||
|
|
0a8246c676 | ||
|
|
ea02453f63 | ||
|
|
d1942da317 | ||
|
|
ed9764f923 | ||
|
|
3b5ed81216 | ||
|
|
12d0d4140e | ||
|
|
d6c8008978 | ||
|
|
488ca0fcc5 | ||
|
|
dfd15cadab | ||
|
|
1613257bdc |
5
3rdparty/CMakeLists.txt
vendored
5
3rdparty/CMakeLists.txt
vendored
@@ -2,3 +2,8 @@ if (NOT SYSTEM_EXPAT)
|
||||
add_subdirectory(expat)
|
||||
endif()
|
||||
|
||||
add_subdirectory(utf8)
|
||||
|
||||
if (ENABLE_DNS)
|
||||
add_subdirectory(udns)
|
||||
endif()
|
||||
|
||||
41
3rdparty/udns/CMakeLists.txt
vendored
Normal file
41
3rdparty/udns/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
include (SimGearComponent)
|
||||
INCLUDE (CheckFunctionExists)
|
||||
INCLUDE (CheckSymbolExists)
|
||||
include (CheckIncludeFile)
|
||||
|
||||
|
||||
CHECK_FUNCTION_EXISTS(poll HAVE_POLL)
|
||||
CHECK_FUNCTION_EXISTS(getopt HAVE_GETOPT)
|
||||
CHECK_FUNCTION_EXISTS(inet_ntop HAVE_INET_PTON_NTOP)
|
||||
CHECK_SYMBOL_EXISTS(AF_INET6 "netinet/in.h" HAVE_IPv6)
|
||||
# WINDOWS should be defined by msvc, should it?
|
||||
# somehow it is not, if somebody know a better way to define WINDOWS, please fix
|
||||
check_include_file(windows.h WINDOWS)
|
||||
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_BINARY_DIR}/config.h)
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
|
||||
set(HEADERS
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
udns_resolver.c
|
||||
udns_dn.c
|
||||
udns_dntosp.c
|
||||
udns_parse.c
|
||||
udns_resolver.c
|
||||
udns_init.c
|
||||
udns_misc.c
|
||||
udns_rr_a.c
|
||||
udns_rr_ptr.c
|
||||
udns_rr_mx.c
|
||||
udns_rr_txt.c
|
||||
udns_bl.c
|
||||
udns_rr_srv.c
|
||||
udns_rr_naptr.c
|
||||
udns_codes.c
|
||||
udns_jran.c
|
||||
udns_XtoX.c
|
||||
)
|
||||
|
||||
simgear_component(udns 3rdparty/udns "${SOURCES}" "${HEADERS}")
|
||||
502
3rdparty/udns/COPYING.LGPL
vendored
Normal file
502
3rdparty/udns/COPYING.LGPL
vendored
Normal file
@@ -0,0 +1,502 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
197
3rdparty/udns/Makefile.in
vendored
Normal file
197
3rdparty/udns/Makefile.in
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
#! /usr/bin/make -rf
|
||||
# Makefile.in
|
||||
# libudns Makefile
|
||||
#
|
||||
# Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
# This file is part of UDNS library, an async DNS stub resolver.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library, in file named COPYING.LGPL; if not,
|
||||
# write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
# Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
NAME = udns
|
||||
VERS = 0.4
|
||||
SOVER = 0
|
||||
|
||||
SRCS = udns_dn.c udns_dntosp.c udns_parse.c udns_resolver.c udns_init.c \
|
||||
udns_misc.c udns_XtoX.c \
|
||||
udns_rr_a.c udns_rr_ptr.c udns_rr_mx.c udns_rr_txt.c udns_bl.c \
|
||||
udns_rr_srv.c udns_rr_naptr.c udns_codes.c udns_jran.c
|
||||
USRCS = dnsget.c rblcheck.c ex-rdns.c
|
||||
DIST = COPYING.LGPL udns.h udns.3 dnsget.1 rblcheck.1 $(SRCS) $(USRCS) \
|
||||
NEWS TODO NOTES Makefile.in configure configure.lib \
|
||||
inet_XtoX.c getopt.c
|
||||
|
||||
OBJS = $(SRCS:.c=.o) $(GEN:.c=.o)
|
||||
LIB = lib$(NAME).a
|
||||
LIBFL = -L. -l$(NAME)
|
||||
|
||||
SOBJS = $(OBJS:.o=.lo)
|
||||
SOLIB = lib$(NAME)_s.so
|
||||
SOLIBV = lib$(NAME).so.$(SOVER)
|
||||
SOLIBFL= -L. -l$(NAME)_s
|
||||
|
||||
UTILS = $(USRCS:.c=)
|
||||
UOBJS = $(USRCS:.c=.o)
|
||||
SOUTILS = $(USRCS:.c=_s)
|
||||
|
||||
NAMEPFX = $(NAME)-$(VERS)
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
CDEFS = @CDEFS@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
LDSHARED = $(LD) -shared
|
||||
PICFLAGS = -fPIC
|
||||
AWK = awk
|
||||
TAR = tar
|
||||
|
||||
all: static
|
||||
|
||||
.SUFFIXES: .c .o .lo
|
||||
|
||||
static: $(LIB) $(UTILS)
|
||||
staticlib: $(LIB)
|
||||
$(LIB): $(OBJS)
|
||||
-rm -f $@
|
||||
$(AR) rv $@ $(OBJS)
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(CDEFS) -c $<
|
||||
|
||||
shared: $(SOLIBV) $(SOUTILS)
|
||||
sharedlib: $(SOLIBV)
|
||||
|
||||
$(SOLIBV): $(SOBJS)
|
||||
$(LDSHARED) -Wl,--soname,$(SOLIBV) -o $@ $(SOBJS) $(LDFLAGS) $(LIBS)
|
||||
$(SOLIB): $(SOLIBV)
|
||||
rm -f $@
|
||||
ln -s $(SOLIBV) $@
|
||||
.c.lo:
|
||||
$(CC) $(CFLAGS) $(PICFLAGS) $(CDEFS) -o $@ -c $<
|
||||
|
||||
# udns_codes.c is generated from udns.h
|
||||
udns_codes.c: udns.h
|
||||
@echo Generating $@
|
||||
@set -e; exec >$@.tmp; \
|
||||
set T type C class R rcode; \
|
||||
echo "/* Automatically generated. */"; \
|
||||
echo "#include \"udns.h\""; \
|
||||
while [ "$$1" ]; do \
|
||||
echo; \
|
||||
echo "const struct dns_nameval dns_$${2}tab[] = {"; \
|
||||
$(AWK) "/^ DNS_$${1}_[A-Z0-9_]+[ ]*=/ \
|
||||
{ printf \" {%s,\\\"%s\\\"},\\n\", \$$1, substr(\$$1,7) }" \
|
||||
udns.h ; \
|
||||
echo " {0,0}};"; \
|
||||
echo "const char *dns_$${2}name(enum dns_$${2} code) {"; \
|
||||
echo " static char nm[20];"; \
|
||||
echo " switch(code) {"; \
|
||||
$(AWK) "BEGIN{i=0} \
|
||||
/^ DNS_$${1}_[A-Z0-9_]+[ ]*=/ \
|
||||
{printf \" case %s: return dns_$${2}tab[%d].name;\\n\",\$$1,i++}\
|
||||
" udns.h ; \
|
||||
echo " }"; \
|
||||
echo " return _dns_format_code(nm,\"$$2\",code);"; \
|
||||
echo "}"; \
|
||||
shift 2; \
|
||||
done
|
||||
@mv $@.tmp $@
|
||||
|
||||
udns.3.html: udns.3
|
||||
groff -man -Thtml udns.3 > $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
dist: $(NAMEPFX).tar.gz
|
||||
$(NAMEPFX).tar.gz: $(DIST)
|
||||
$(TAR) -cv -f $@ -z --transform 's|^|$(NAMEPFX)/|' $(DIST)
|
||||
|
||||
subdist:
|
||||
cp -p $(DIST) $(TARGET)/
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
rm -f $(SOBJS)
|
||||
rm -f $(UOBJS)
|
||||
rm -f config.log
|
||||
distclean: clean
|
||||
rm -f $(LIB) $(SOLIB) $(SOLIBV) udns.3.html
|
||||
rm -f $(UTILS) $(SOUTILS)
|
||||
rm -f config.status config.h Makefile
|
||||
|
||||
|
||||
Makefile: configure configure.lib Makefile.in
|
||||
./configure
|
||||
@echo
|
||||
@echo Please rerun make >&2
|
||||
@exit 1
|
||||
|
||||
.PHONY: all static staticlib shared sharedlib dist clean distclean subdist \
|
||||
depend dep deps
|
||||
|
||||
depend dep deps: $(SRCS) $(USRC)
|
||||
@echo Generating deps for:
|
||||
@echo \ $(SRCS)
|
||||
@echo \ $(USRCS)
|
||||
@sed '/^# depend/q' Makefile.in > Makefile.tmp
|
||||
@set -e; \
|
||||
for f in $(SRCS) $(USRCS); do \
|
||||
echo $${f%.c}.o $${f%.c}.lo: $$f \
|
||||
`sed -n 's/^#[ ]*include[ ]*"\(.*\)".*/\1/p' $$f`; \
|
||||
done >> Makefile.tmp; \
|
||||
for f in $(USRCS:.c=.o); do \
|
||||
echo "$${f%.?}: $$f \$$(LIB)"; \
|
||||
echo " \$$(LD) \$$(LDLAGS) -o \$$@ $$f \$$(LIBFL) \$$(LIBS)"; \
|
||||
echo "$${f%.?}_s: $$f \$$(SOLIB)"; \
|
||||
echo " \$$(LD) \$$(LDFLAGS) -o \$$@ $$f \$$(SOLIBFL)"; \
|
||||
done >> Makefile.tmp ; \
|
||||
if cmp Makefile.tmp Makefile.in >/dev/null 2>&1 ; then \
|
||||
echo Makefile.in unchanged; rm -f Makefile.tmp; \
|
||||
else \
|
||||
echo Updating Makfile.in; mv -f Makefile.tmp Makefile.in ; \
|
||||
fi
|
||||
|
||||
# depend
|
||||
udns_dn.o udns_dn.lo: udns_dn.c udns.h
|
||||
udns_dntosp.o udns_dntosp.lo: udns_dntosp.c udns.h
|
||||
udns_parse.o udns_parse.lo: udns_parse.c udns.h
|
||||
udns_resolver.o udns_resolver.lo: udns_resolver.c config.h udns.h
|
||||
udns_init.o udns_init.lo: udns_init.c config.h udns.h
|
||||
udns_misc.o udns_misc.lo: udns_misc.c udns.h
|
||||
udns_XtoX.o udns_XtoX.lo: udns_XtoX.c config.h udns.h inet_XtoX.c
|
||||
udns_rr_a.o udns_rr_a.lo: udns_rr_a.c udns.h
|
||||
udns_rr_ptr.o udns_rr_ptr.lo: udns_rr_ptr.c udns.h
|
||||
udns_rr_mx.o udns_rr_mx.lo: udns_rr_mx.c udns.h
|
||||
udns_rr_txt.o udns_rr_txt.lo: udns_rr_txt.c udns.h
|
||||
udns_bl.o udns_bl.lo: udns_bl.c udns.h
|
||||
udns_rr_srv.o udns_rr_srv.lo: udns_rr_srv.c udns.h
|
||||
udns_rr_naptr.o udns_rr_naptr.lo: udns_rr_naptr.c udns.h
|
||||
udns_codes.o udns_codes.lo: udns_codes.c udns.h
|
||||
udns_jran.o udns_jran.lo: udns_jran.c udns.h
|
||||
dnsget.o dnsget.lo: dnsget.c config.h udns.h getopt.c
|
||||
rblcheck.o rblcheck.lo: rblcheck.c config.h udns.h getopt.c
|
||||
ex-rdns.o ex-rdns.lo: ex-rdns.c udns.h
|
||||
dnsget: dnsget.o $(LIB)
|
||||
$(LD) $(LDLAGS) -o $@ dnsget.o $(LIBFL) $(LIBS)
|
||||
dnsget_s: dnsget.o $(SOLIB)
|
||||
$(LD) $(LDFLAGS) -o $@ dnsget.o $(SOLIBFL)
|
||||
rblcheck: rblcheck.o $(LIB)
|
||||
$(LD) $(LDLAGS) -o $@ rblcheck.o $(LIBFL) $(LIBS)
|
||||
rblcheck_s: rblcheck.o $(SOLIB)
|
||||
$(LD) $(LDFLAGS) -o $@ rblcheck.o $(SOLIBFL)
|
||||
ex-rdns: ex-rdns.o $(LIB)
|
||||
$(LD) $(LDLAGS) -o $@ ex-rdns.o $(LIBFL) $(LIBS)
|
||||
ex-rdns_s: ex-rdns.o $(SOLIB)
|
||||
$(LD) $(LDFLAGS) -o $@ ex-rdns.o $(SOLIBFL)
|
||||
136
3rdparty/udns/NEWS
vendored
Normal file
136
3rdparty/udns/NEWS
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
NEWS
|
||||
User-visible changes in udns library. Recent changes on top.
|
||||
|
||||
0.4 (Jan 2014)
|
||||
|
||||
- bugfix: fix a bug in new list code introduced in 0.3
|
||||
- portability: use $(LD)/$(LDFLAGS)/$(LIBS)
|
||||
|
||||
0.3 (Jan 2014)
|
||||
|
||||
- bugfix: refactor double-linked list implementation in udns_resolver.c
|
||||
(internal to the library) to be more strict-aliasing-friendly, because
|
||||
old code were miscompiled by gcc.
|
||||
|
||||
- bugfix: forgotten strdup() in rblcheck
|
||||
|
||||
0.2 (Dec 2011)
|
||||
|
||||
- bugfix: SRV RR handling: fix domain name parsing and crash in case
|
||||
if no port is specified on input for SRV record query
|
||||
|
||||
- (trivial api) dns_set_opts() now returns number of unrecognized
|
||||
options instead of always returning 0
|
||||
|
||||
- dnsget: combine -f and -o options in dnsget (and stop documenting -f),
|
||||
and report unknown/invalid -o options (and error out)
|
||||
|
||||
- dnsget: pretty-print SSHFP RRs
|
||||
|
||||
0.1 (Dec 2010)
|
||||
|
||||
- bugfix: udns_new(old) - when actually cloning another context -
|
||||
makes the new context referencing memory from old, which leads
|
||||
to crashes when old is modified later
|
||||
|
||||
- use random queue IDs (the 16bit qID) in queries instead of sequentional
|
||||
ones, based on simple pseudo-random RNG by Bob Jenkins (udns_jran.[ch]).
|
||||
Some people believe that this improves security (CVE-2008-1447). I'm
|
||||
still not convinced (see comments in udns_resolver.c), but it isn't
|
||||
difficult to add after all.
|
||||
|
||||
- deprecate dns_random16() function which was declared in udns.h
|
||||
(not anymore) but never documented. In order to keep ABI compatible
|
||||
it is still exported.
|
||||
|
||||
- library has a way now to set query flags (DNS_SET_DO; DNS_SET_CD).
|
||||
|
||||
- dnsget now prints non-printable chars in all strings in DNS RRs using
|
||||
decimal escape sequences (\%03u) instead of hexadecimal (\%02x) when
|
||||
before - other DNS software does it like this.
|
||||
|
||||
- recognize a few more record types in dnsget, notable some DNSSEC RRs;
|
||||
add -f option for dnsget to set query flags.
|
||||
|
||||
- udns is not a Debian native package anymore (was a wrong idea)
|
||||
|
||||
0.0.9 (16 Jan 2007)
|
||||
|
||||
- incompat: minor API changes in dns_init() &friends. dns_init()
|
||||
now requires extra `struct dns_ctx *' argument. Not bumped
|
||||
soversion yet - I only expect one "release" with this change.
|
||||
|
||||
- many small bugfixes, here and there
|
||||
|
||||
- more robust FORMERR replies handling - not only such replies are now
|
||||
recognized, but udns retries queries without EDNS0 extensions if tried
|
||||
with, but server reported FORMERR
|
||||
|
||||
- portability changes, udns now includes getopt() implementation fo
|
||||
the systems lacking it (mostly windows), and dns_ntop()&dns_pton(),
|
||||
which are either just wrappers for system functions or reimplementations.
|
||||
|
||||
- build is now based on autoconf-like configuration
|
||||
|
||||
- NAPTR (RFC3403) RR decoding support
|
||||
|
||||
- new file NOTES which complements TODO somewhat, and includes some
|
||||
important shortcomings
|
||||
|
||||
- many internal cleanups, including some preparations for better error
|
||||
recovery, security and robustness (and thus API changes)
|
||||
|
||||
- removed some #defines which are now unused (like DNS_MAXSRCH)
|
||||
|
||||
- changed WIN32 to WINDOWS everywhere in preprocessor tests,
|
||||
to be able to build it on win64 as well
|
||||
|
||||
0.0.8 (12 Sep 2005)
|
||||
|
||||
- added SRV records (rfc2782) parsing,
|
||||
thanks to Thadeu Lima de Souza Cascardo for implementation.
|
||||
|
||||
- bugfixes:
|
||||
o use uninitialized value when no reply, library died with assertion:
|
||||
assert((status < 0 && result == 0) || (status >= 0 && result != 0)).
|
||||
o on some OSes, struct sockaddr_in has additional fields, so
|
||||
memcmp'ing two sockaddresses does not work.
|
||||
|
||||
- rblcheck(.1)
|
||||
|
||||
0.0.7 (20 Apr 2005)
|
||||
|
||||
- dnsget.1 manpage and several enhancements to dnsget.
|
||||
|
||||
- allow nameserver names for -n option of dnsget.
|
||||
|
||||
- API change: all dns_submit*() routines now does not expect
|
||||
last `now' argument, since requests aren't sent immediately
|
||||
anymore.
|
||||
|
||||
- API change: different application timer callback mechanism.
|
||||
Udns now uses single per-context timer instead of per-query.
|
||||
|
||||
- don't assume DNS replies only contain backward DN pointers,
|
||||
allow forward pointers too. Change parsing API.
|
||||
|
||||
- debianize
|
||||
|
||||
0.0.6 (08 Apr 2005)
|
||||
|
||||
- use double sorted list for requests (sorted by deadline).
|
||||
This should significantly speed up timeout processing for
|
||||
large number of requests.
|
||||
|
||||
- changed debugging interface, so it is finally useable
|
||||
(still not documented).
|
||||
|
||||
- dnsget routine is now Officially Useable, and sometimes
|
||||
even more useable than `host' from BIND distribution
|
||||
(and sometimes not - dnsget does not have -C option
|
||||
and TCP mode)
|
||||
|
||||
- Debian packaging in debian/ -- udns is now maintained as a
|
||||
native Debian package.
|
||||
|
||||
- alot (and I really mean alot) of code cleanups all over.
|
||||
226
3rdparty/udns/NOTES
vendored
Normal file
226
3rdparty/udns/NOTES
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
Assorted notes about udns (library).
|
||||
|
||||
UDP-only mode
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
First of all, since udns is (currently) UDP-only, there are some
|
||||
shortcomings.
|
||||
|
||||
It assumes that a reply will fit into a UDP buffer. With adoption of EDNS0,
|
||||
and general robustness of IP stacks, in most cases it's not an issue. But
|
||||
in some cases there may be problems:
|
||||
|
||||
- if an RRset is "very large" so it does not fit even in buffer of size
|
||||
requested by the library (current default is 4096; some servers limits
|
||||
it further), we will not see the reply, or will only see "damaged"
|
||||
reply (depending on the server).
|
||||
|
||||
- many DNS servers ignores EDNS0 option requests. In this case, no matter
|
||||
which buffer size udns library will request, such servers reply is limited
|
||||
to 512 bytes (standard pre-EDNS0 DNS packet size). (Udns falls back to
|
||||
non-EDNO0 query if EDNS0-enabled one received FORMERR or NOTIMPL error).
|
||||
|
||||
The problem is that with this, udns currently will not consider replies with
|
||||
TC (truncation) bit set, and will treat such replies the same way as it
|
||||
treats SERVFAIL replies, thus trying next server, or temp-failing the query
|
||||
if no more servers to try. In other words, if the reply is really large, or
|
||||
if the servers you're using don't support EDNS0, your application will be
|
||||
unable to resolve a given name.
|
||||
|
||||
Yet it's not common situation - in practice, it's very rare.
|
||||
|
||||
Implementing TCP mode isn't difficult, but it complicates API significantly.
|
||||
Currently udns uses only single UDP socket (or - maybe in the future - two,
|
||||
see below), but in case of TCP, it will need to open and close sockets for
|
||||
TCP connections left and right, and that have to be integrated into an
|
||||
application's event loop in an easy and efficient way. Plus all the
|
||||
timeouts - different for connect(), write, and several stages of read.
|
||||
|
||||
IPv6 vs IPv4 usage
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is only relevant for nameservers reachable over IPv6, NOT for IPv6
|
||||
queries. I.e., if you've IPv6 addresses in 'nameservers' line in your
|
||||
/etc/resolv.conf file. Even more: if you have BOTH IPv6 AND IPv4 addresses
|
||||
there. Or pass them to udns initialization routines.
|
||||
|
||||
Since udns uses a single UDP socket to communicate with all nameservers,
|
||||
it should support both v4 and v6 communications. Most current platforms
|
||||
supports this mode - using PF_INET6 socket and V4MAPPED addresses, i.e,
|
||||
"tunnelling" IPv4 inside IPv6. But not all systems supports this. And
|
||||
more, it has been said that such mode is deprecated.
|
||||
|
||||
So, list only IPv4 or only IPv6 addresses, but don't mix them, in your
|
||||
/etc/resolv.conf.
|
||||
|
||||
An alternative is to use two sockets instead of 1 - one for IPv6 and one
|
||||
for IPv4. For now I'm not sure if it's worth the complexity - again, of
|
||||
the API, not the library itself (but this will not simplify library either).
|
||||
|
||||
Single socket for all queries
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Using single UDP socket for sending queries to all nameservers has obvious
|
||||
advantages. First it's, again, trivial, simple to use API. And simple
|
||||
library too. Also, after sending queries to all nameservers (in case first
|
||||
didn't reply in time), we will be able to receive late reply from first
|
||||
nameserver and accept it.
|
||||
|
||||
But this mode has disadvantages too. Most important is that it's much easier
|
||||
to send fake reply to us, as the UDP port where we expects the reply to come
|
||||
to is constant during the whole lifetime of an application. More secure
|
||||
implementations uses random port for every single query. While port number
|
||||
(16 bits integer) can not hold much randomness, it's still of some help.
|
||||
Ok, udns is a stub resolver, so it expects sorta friendly environment, but
|
||||
on LAN it's usually much easier to fire an attack, due to the speed of local
|
||||
network, where a bad guy can generate alot of packets in a short time.
|
||||
|
||||
Spoofing of replies (Kaminsky attack, CVE-2008-1447)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
While udns uses random numbers for query IDs, it uses single UDP port for
|
||||
all queries (see previous item). And even if it used random UDP port for
|
||||
each query, the attack described in CVE-2008-1447 is still quite trivial.
|
||||
This is not specific to udns library unfortunately - it is inherent property
|
||||
of the protocol. Udns is designed to work in a LAN, it needs full recursive
|
||||
resolver nearby, and modern LAN usually uses high-bandwidth equipment which
|
||||
makes the Kaminsky attack trivial. The problem is that even with qID (16
|
||||
bits) and random UDP port (about 20 bits available to a regular process)
|
||||
combined still can not hold enough randomness, so on a fast network it is
|
||||
still easy to flood the target with fake replies and hit the "right" reply
|
||||
before real reply comes. So random qIDs don't add much protection anyway,
|
||||
even if this feature is implemented in udns, and using all available
|
||||
techniques wont solve it either.
|
||||
|
||||
See also long comment in udns_resolver.c, udns_newid().
|
||||
|
||||
Assumptions about RRs returned
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Currently udns processes records in the reply it received sequentially.
|
||||
This means that order of the records is significant. For example, if
|
||||
we asked for foo.bar A, but the server returned that foo.bar is a CNAME
|
||||
(alias) for bar.baz, and bar.baz, in turn, has address 1.2.3.4, when
|
||||
the CNAME should come first in reply, followed by A. While DNS specs
|
||||
does not say anything about order of records - it's an rrSET - unordered, -
|
||||
I think an implementation which returns the records in "wrong" order is
|
||||
somewhat insane...
|
||||
|
||||
CNAME recursion
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Another interesting point is the handling of CNAMEs returned as replies
|
||||
to non-CNAME queries. If we asked for foo.bar A, but it's a CNAME, udns
|
||||
expects BOTH the CNAME itself and the target DN to be present in the reply.
|
||||
In other words, udns DOES NOT RECURSE CNAMES. If we asked for foo.bar A,
|
||||
but only record in reply was that foo.bar is a CNAME for bar.baz, udns will
|
||||
return no records to an application (NXDOMAIN). Strictly speaking, udns
|
||||
should repeat the query asking for bar.baz A, and recurse. But since it's
|
||||
stub resolver, recursive resolver should recurse for us instead.
|
||||
|
||||
It's not very difficult to implement, however. Probably with some (global?)
|
||||
flag to en/dis-able the feature. Provided there's some demand for it.
|
||||
|
||||
To clarify: udns handles CNAME recursion in a single reply packet just fine.
|
||||
|
||||
Note also that standard gethostbyname() routine does not recurse in this
|
||||
situation, too.
|
||||
|
||||
Error reporting
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Too many places in the code (various failure paths) sets generic "TEMPFAIL"
|
||||
error condition. For example, if no nameserver replied to our query, an
|
||||
application will get generic TEMPFAIL, instead of something like TIMEDOUT.
|
||||
This probably should be fixed, but most applications don't care about the
|
||||
exact reasons of failure - 4 common cases are already too much:
|
||||
- query returned some valid data
|
||||
- NXDOMAIN
|
||||
- valid domain but no data of requested type - =NXDOMAIN in most cases
|
||||
- temporary error - this one sometimes (incorrectly!) treated as NXDOMAIN
|
||||
by (naive) applications.
|
||||
DNS isn't yes/no, it's at least 3 variants, temp err being the 3rd important
|
||||
case! And adding more variations for the temp error case is complicating things
|
||||
even more - again, from an application writer standpoint. For diagnostics,
|
||||
such more specific error cases are of good help.
|
||||
|
||||
Planned API changes
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
At least one thing I want to change for some future version is a way how
|
||||
queries are submitted and how replies are handled.
|
||||
|
||||
I want to made dns_query object to be owned by an application. So that instead
|
||||
of udns library allocating it for the lifetime of query, it will be pre-
|
||||
allocated by an application. This simplifies and enhances query submitting
|
||||
interface, and complicates it a bit too, in simplest cases.
|
||||
|
||||
Currently, we have:
|
||||
|
||||
dns_submit_dn(dn, cls, typ, flags, parse, cbck, data)
|
||||
dns_submit_p(name, cls, typ, flags, parse, cbck, data)
|
||||
dns_submit_a4(ctx, name, flags, cbck, data)
|
||||
|
||||
and so on -- with many parameters missed for type-specific cases, but generic
|
||||
cases being too complex for most common usage.
|
||||
|
||||
Instead, with dns_query being owned by an app, we will be able to separately
|
||||
set up various parts of the query - domain name (various forms), type&class,
|
||||
parser, flags, callback... and even change them at runtime. And we will also
|
||||
be able to reuse query structures, instead of allocating/freeing them every
|
||||
time. So the whole thing will look something like:
|
||||
|
||||
q = dns_alloc_query();
|
||||
dns_submit(dns_q_flags(dns_q_a4(q, name, cbck), DNS_F_NOSRCH), data);
|
||||
|
||||
The idea is to have a set of functions accepting struct dns_query* and
|
||||
returning it (so the calls can be "nested" like the above), to set up
|
||||
relevant parts of the query - specific type of callback, conversion from
|
||||
(type-specific) query parameters into a domain name (this is for type-
|
||||
specific query initializers), and setting various flags and options and
|
||||
type&class things.
|
||||
|
||||
One example where this is almost essential - if we want to support
|
||||
per-query set of nameservers (which isn't at all useless: imagine a
|
||||
high-volume mail server, were we want to direct DNSBL queries to a separate
|
||||
set of nameservers, and rDNS queries to their own set and so on). Adding
|
||||
another argument (set of nameservers to use) to EVERY query submitting
|
||||
routine is.. insane. Especially since in 99% cases it will be set to
|
||||
default NULL. But with such "nesting" of query initializers, it becomes
|
||||
trivial.
|
||||
|
||||
This change (the way how queries gets submitted) will NOT break API/ABI
|
||||
compatibility with old versions, since the new submitting API works in
|
||||
parallel with current (and current will use the new one as building
|
||||
blocks, instead of doing all work at once).
|
||||
|
||||
Another way to do the same is to manipulate query object right after a
|
||||
query has been submitted, but before any events processing (during this
|
||||
time, query object is allocated and initialized, but no actual network
|
||||
packets were sent - it will happen on the next event processing). But
|
||||
this way it become impossible to perform syncronous resolver calls, since
|
||||
those calls hide query objects they use internally.
|
||||
|
||||
Speaking of replies handling - the planned change is to stop using dynamic
|
||||
memory (malloc) inside the library. That is, instead of allocating a buffer
|
||||
for a reply dynamically in a parsing routine (or memdup'ing the raw reply
|
||||
packet if no parsing routine is specified), I want udns to return the packet
|
||||
buffer it uses internally, and change parsing routines to expect a buffer
|
||||
for result. When parsing, a routine will return true amount of memory it
|
||||
will need to place the result, regardless of whenever it has enough room
|
||||
or not, so that an application can (re)allocate properly sized buffer and
|
||||
call a parsing routine again.
|
||||
|
||||
This, in theory, also can be done without breaking current API/ABI, but in
|
||||
that case we'll again need a parallel set of routines (parsing included),
|
||||
which makes the library more complicated with too many ways of doing the
|
||||
same thing. Still, code reuse is at good level.
|
||||
|
||||
Another modification I plan to include is to have an ability to work in
|
||||
terms of domain names (DNs) as used with on-wire DNS packets, not only
|
||||
with asciiz representations of them. For this to work, the above two
|
||||
changes (query submission and result passing) have to be completed first
|
||||
(esp. the query submission part), so that it will be possible to specify
|
||||
some additional query flags (for example) to request domain names instead
|
||||
of the text strings, and to allow easy query submissions with either DNs
|
||||
or text strings.
|
||||
59
3rdparty/udns/TODO
vendored
Normal file
59
3rdparty/udns/TODO
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
TODO
|
||||
|
||||
The following is mostly an internal, not user-visible stuff.
|
||||
|
||||
* rearrange an API to make dns_query object owned by application,
|
||||
so that it'll look like this:
|
||||
struct dns_query *q;
|
||||
q = dns_query_alloc(ctx);
|
||||
dns_query_set(q, options, domain_name, flags, ...);
|
||||
dns_query_submit(ctx, q);
|
||||
For more information see NOTES file, section "Planned API changes".
|
||||
|
||||
* allow NULL callbacks? Or provide separate resolver
|
||||
context list of queries which are done but wich did not
|
||||
have callback, and dns_pick() routine to retrieve results
|
||||
from this query, i.e. allow non-callback usage? The
|
||||
non-callback usage may be handy sometimes (any *good*
|
||||
example?), but it will be difficult to provide type-safe
|
||||
non-callback interface due to various RR-specific types
|
||||
in use.
|
||||
|
||||
* DNS_OPT_FLAGS should be DNS_OPT_ADDFLAGS and DNS_OPT_SETFLAGS.
|
||||
Currently one can't add a single flag bit but preserve
|
||||
existing bits... at least not without retrieving all current
|
||||
flags before, which isn't that bad anyway.
|
||||
|
||||
* dns_set_opts() may process flags too (such as aaonly etc)
|
||||
|
||||
* a way to disable $NSCACHEIP et al processing?
|
||||
(with now separate dns_init() and dns_reset(), it has finer
|
||||
control, but still no way to init from system files but ignore
|
||||
environment variables and the like)
|
||||
|
||||
* initialize/open the context automatically, and be more
|
||||
liberal about initialization in general?
|
||||
|
||||
* dns_init(ctx, do_open) - make the parameter opposite, aka
|
||||
dns_init(ctx, skip_open) ?
|
||||
|
||||
* allow TCP queue?
|
||||
|
||||
* more accurate error reporting. Currently, udns always returns TEMPFAIL,
|
||||
but don't specify why it happened (ENOMEM, timeout, etc).
|
||||
|
||||
* check the error value returned by recvfrom() and
|
||||
sendto() and determine which errors to ignore.
|
||||
|
||||
* maybe merge dns_timeouts() and dns_ioevent(), to have
|
||||
only one entry point for everything? For traditional
|
||||
select-loop-based eventloop it may be easier, but for
|
||||
callback-driven event loops the two should be separate.
|
||||
Provide an option, or a single dns_events() entry point
|
||||
for select-loop approach, or just call dns_ioevent()
|
||||
from within dns_timeouts() (probably after renaming
|
||||
it to be dns_events()) ?
|
||||
|
||||
* implement /etc/hosts lookup too, ala [c-]ares??
|
||||
|
||||
* sortlist support?
|
||||
5
3rdparty/udns/config.h.in
vendored
Normal file
5
3rdparty/udns/config.h.in
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
#cmakedefine HAVE_POLL
|
||||
#cmakedefine HAVE_GETOPT
|
||||
#cmakedefine HAVE_INET_PTON_NTOP
|
||||
#cmakedefine HAVE_IPv6
|
||||
#cmakedefine WINDOWS
|
||||
165
3rdparty/udns/configure
vendored
Executable file
165
3rdparty/udns/configure
vendored
Executable file
@@ -0,0 +1,165 @@
|
||||
#! /bin/sh
|
||||
# autoconf-style configuration script
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
name=udns
|
||||
|
||||
if [ -f udns.h -a -f udns_resolver.c ] ; then :
|
||||
else
|
||||
echo "configure: error: sources not found at `pwd`" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
options="ipv6"
|
||||
|
||||
for opt in $options; do
|
||||
eval enable_$opt=
|
||||
done
|
||||
|
||||
if [ -f config.status ]; then
|
||||
. ./config.status
|
||||
fi
|
||||
|
||||
enable() {
|
||||
opt=`echo "$1" | sed 's/^--[^-]*-//'`
|
||||
case "$opt" in
|
||||
ipv6) ;;
|
||||
*) echo "configure: unrecognized option \`$1'" >&2; exit 1;;
|
||||
esac
|
||||
eval enable_$opt=$2
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--disable-*|--without-*|--no-*) enable "$1" n;;
|
||||
--enable-*|--with-*) enable "$1" y;;
|
||||
--help | --hel | --he | --h | -help | -hel | -he | -h )
|
||||
cat <<EOF
|
||||
configure: configure $name package.
|
||||
Usage: ./configure [options]
|
||||
where options are:
|
||||
--enable-option, --with-option --
|
||||
enable the named option/feature
|
||||
--disable-option, --without-option, --no-option --
|
||||
disable the named option/feature
|
||||
--help - print this help and exit
|
||||
Optional features (all enabled by default if system supports a feature):
|
||||
ipv6 - enable/disable IP version 6 (IPv6) support
|
||||
EOF
|
||||
exit 0
|
||||
;;
|
||||
*) echo "configure: unknown option \`$1'" >&2; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
. ./configure.lib
|
||||
|
||||
ac_msg "configure"
|
||||
ac_result "$name package"
|
||||
|
||||
ac_prog_c_compiler_v
|
||||
ac_prog_ranlib_v
|
||||
|
||||
ac_ign ac_yesno "for getopt()" ac_have GETOPT ac_link <<EOF
|
||||
#include <stdio.h>
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
extern int getopt(int, char **, char *);
|
||||
int main(int argc, char **argv) {
|
||||
getopt(argc, argv, "abc");
|
||||
return optarg ? optind : 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
if ac_library_find_v 'socket and connect' "" "-lsocket -lnsl" <<EOF
|
||||
int main() { socket(); connect(); return 0; }
|
||||
EOF
|
||||
then :
|
||||
else
|
||||
ac_fatal "cannot find libraries needed for sockets"
|
||||
fi
|
||||
|
||||
ac_ign \
|
||||
ac_yesno "for inet_pton() && inet_ntop()" \
|
||||
ac_have INET_PTON_NTOP \
|
||||
ac_link <<EOF
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
int main() {
|
||||
char buf[64];
|
||||
long x = 0;
|
||||
inet_pton(AF_INET, &x, buf);
|
||||
return inet_ntop(AF_INET, &x, buf, sizeof(buf));
|
||||
}
|
||||
EOF
|
||||
|
||||
if ac_yesno "for socklen_t" ac_compile <<EOF
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
int foo() { socklen_t len; len = 0; return len; }
|
||||
EOF
|
||||
then :
|
||||
else
|
||||
ac_define socklen_t int
|
||||
fi
|
||||
|
||||
if [ n != "$enable_ipv6" ]; then
|
||||
if ac_yesno "for IPv6" ac_have IPv6 ac_compile <<EOF
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
int main() {
|
||||
struct sockaddr_in6 sa;
|
||||
sa.sin6_family = AF_INET6;
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
then :
|
||||
elif [ "$enable_ipv6" ]; then
|
||||
ac_fatal "IPv6 is requested but not available"
|
||||
fi
|
||||
fi # !disable_ipv6?
|
||||
|
||||
if ac_yesno "for poll()" ac_have POLL ac_link <<EOF
|
||||
#include <sys/types.h>
|
||||
#include <sys/poll.h>
|
||||
int main() {
|
||||
struct pollfd pfd[2];
|
||||
return poll(pfd, 2, 10);
|
||||
}
|
||||
EOF
|
||||
then :
|
||||
else
|
||||
ac_ign ac_yesno "for sys/select.h" ac_have SYS_SELECT_H ac_cpp <<EOF
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
EOF
|
||||
fi
|
||||
|
||||
ac_config_h
|
||||
ac_output Makefile
|
||||
ac_msg "creating config.status"
|
||||
rm -f config.status
|
||||
{
|
||||
echo "# automatically generated by configure to hold command-line options"
|
||||
echo
|
||||
found=
|
||||
for opt in $options; do
|
||||
eval val=\$enable_$opt
|
||||
if [ -n "$val" ]; then
|
||||
echo enable_$opt=$val
|
||||
found=y
|
||||
fi
|
||||
done
|
||||
if [ ! "$found" ]; then
|
||||
echo "# (no options encountered)"
|
||||
fi
|
||||
} > config.status
|
||||
ac_result ok
|
||||
|
||||
ac_result "all done."
|
||||
exit 0
|
||||
268
3rdparty/udns/configure.lib
vendored
Normal file
268
3rdparty/udns/configure.lib
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
# configure.lib
|
||||
# a library of shell routines for simple autoconf system
|
||||
#
|
||||
|
||||
set -e
|
||||
ac_substitutes=
|
||||
rm -f conftest* config.log
|
||||
exec 5>config.log
|
||||
cat <<EOF >&5
|
||||
This file contains any messages produced by compilers etc while
|
||||
running configure, to aid debugging if configure script makes a mistake.
|
||||
|
||||
EOF
|
||||
|
||||
case `echo "a\c"` in
|
||||
*c*) ac_en=-n ac_ec= ;;
|
||||
*) ac_en= ac_ec='\c' ;;
|
||||
esac
|
||||
|
||||
##### Messages
|
||||
ac_msg() {
|
||||
echo $ac_en "$*... $ac_ec"
|
||||
echo ">>> $*" >&5
|
||||
}
|
||||
ac_checking() {
|
||||
echo $ac_en "checking $*... $ac_ec"
|
||||
echo ">>> checking $*" >&5
|
||||
}
|
||||
ac_result() {
|
||||
echo "$1"
|
||||
echo "=== $1" >&5
|
||||
}
|
||||
ac_fatal() {
|
||||
echo "configure: fatal: $*" >&2
|
||||
echo "=== FATAL: $*" >&5
|
||||
exit 1
|
||||
}
|
||||
ac_warning() {
|
||||
echo "configure: warning: $*" >&2
|
||||
echo "=== WARNING: $*" >&5
|
||||
}
|
||||
ac_ign() {
|
||||
"$@" || :
|
||||
}
|
||||
|
||||
# ac_run command...
|
||||
# captures output in conftest.out
|
||||
ac_run() {
|
||||
# apparently UnixWare (for one) /bin/sh optimizes the following "if"
|
||||
# "away", by checking if there's such a command BEFORE redirecting
|
||||
# output. So error message (like "gcc: command not found") goes
|
||||
# to stderr instead of to conftest.out, and `cat conftest.out' below
|
||||
# fails.
|
||||
if "$@" >conftest.out 2>&1; then
|
||||
return 0
|
||||
else
|
||||
echo "==== Command invocation failed. Command line was:" >&5
|
||||
echo "$*" >&5
|
||||
echo "==== compiler input was:" >&5
|
||||
cat conftest.c >&5
|
||||
echo "==== output was:" >&5
|
||||
cat conftest.out >&5
|
||||
echo "====" >&5
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# common case for ac_verbose: yes/no result
|
||||
ac_yesno() {
|
||||
ac_checking "$1"
|
||||
shift
|
||||
if "$@"; then
|
||||
ac_result yes
|
||||
return 0
|
||||
else
|
||||
ac_result no
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
ac_subst() {
|
||||
ac_substitutes="$ac_substitutes $*"
|
||||
}
|
||||
|
||||
ac_define() {
|
||||
CDEFS="$CDEFS -D$1=${2:-1}"
|
||||
}
|
||||
|
||||
ac_have() {
|
||||
ac_what=$1; shift
|
||||
if "$@"; then
|
||||
ac_define HAVE_$ac_what
|
||||
eval ac_have_$ac_what=yes
|
||||
return 0
|
||||
else
|
||||
eval ac_have_$ac_what=no
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
##### Compiling, linking
|
||||
|
||||
# run a compiler
|
||||
ac_run_compiler() {
|
||||
rm -f conftest*; cat >conftest.c
|
||||
ac_run $CC $CFLAGS $CDEFS "$@" conftest.c
|
||||
}
|
||||
|
||||
ac_compile() {
|
||||
ac_run_compiler -c
|
||||
}
|
||||
|
||||
ac_link() {
|
||||
ac_run_compiler -o conftest $LIBS "$@"
|
||||
}
|
||||
|
||||
ac_cpp() {
|
||||
ac_run_compiler -E "$@"
|
||||
}
|
||||
|
||||
### check for C compiler. Set $CC, $CFLAGS etc
|
||||
ac_prog_c_compiler_v() {
|
||||
ac_checking "for C compiler"
|
||||
rm -f conftest*
|
||||
echo 'int main(int argc, char **argv) { return 0; }' >conftest.c
|
||||
|
||||
if [ -n "$CC" ]; then
|
||||
if ac_run $CC -o conftest conftest.c && ac_run ./conftest; then
|
||||
ac_result "\$CC ($CC)"
|
||||
else
|
||||
ac_result no
|
||||
ac_fatal "\$CC ($CC) is not a working compiler"
|
||||
fi
|
||||
else
|
||||
for cc in gcc cc ; do
|
||||
if ac_run $cc -o conftest conftest.c && ac_run ./conftest; then
|
||||
ac_result "$cc"
|
||||
CC=$cc
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -z "$CC" ]; then
|
||||
ac_result no
|
||||
ac_fatal "no working C compiler found in \$PATH. please set \$CC variable"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$CFLAGS" ]; then
|
||||
if ac_yesno "whenever C compiler ($CC) is GNU CC" \
|
||||
ac_grep_cpp yEs_mAsTeR <<EOF
|
||||
#ifdef __GNUC__
|
||||
yEs_mAsTeR;
|
||||
#endif
|
||||
EOF
|
||||
then
|
||||
CFLAGS="-Wall -W -O2 -pipe"
|
||||
else
|
||||
CFLAGS=-O
|
||||
fi
|
||||
fi
|
||||
cc="$CC $CFLAGS"
|
||||
ccld="$cc"
|
||||
if [ -n "$LDFLAGS" ]; then ccld="$ccld $LDFLAGS"; fi
|
||||
if [ -n "$LIBS" ]; then ccld="$ccld $LIBS"; fi
|
||||
if ac_yesno "whenever the C compiler ($ccld)
|
||||
can produce executables" \
|
||||
ac_compile_run <<EOF
|
||||
int main() { return 0; }
|
||||
EOF
|
||||
then :
|
||||
else
|
||||
ac_fatal "no working C compiler found"
|
||||
fi
|
||||
LD='$(CC)'
|
||||
[ -n "$AR" ] || AR=ar
|
||||
[ -n "$ARFLAGS" ] || ARFLAGS=rv
|
||||
[ -n "$AWK" ] || AWK=awk
|
||||
ac_substitutes="$ac_substitutes CC CFLAGS CDEFS LD LDFLAGS LIBS AR ARFLAGS AWK"
|
||||
}
|
||||
|
||||
|
||||
ac_prog_ranlib_v() {
|
||||
ac_checking "for ranlib"
|
||||
if [ -n "$RANLIB" ]; then
|
||||
ac_result "\$RANLIB ($RANLIB)"
|
||||
else
|
||||
ifs="$IFS"
|
||||
IFS=:
|
||||
for dir in $PATH; do
|
||||
[ -n "$dir" ] || dir=.
|
||||
if [ -f $dir/ranlib ]; then
|
||||
RANLIB=ranlib
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS="$ifs"
|
||||
if [ -z "$RANLIB" ]; then ac_result no; RANLIB=:
|
||||
else ac_result "$RANLIB"
|
||||
fi
|
||||
fi
|
||||
ac_substitutes="$ac_substitutes RANLIB"
|
||||
}
|
||||
|
||||
ac_library_find_v() {
|
||||
ac_checking "for libraries needed for $1"
|
||||
shift
|
||||
fond=
|
||||
rm -f conftest*; cat >conftest.c
|
||||
for lib in "$@"; do
|
||||
if ac_run $CC $CFLAGS $LDFLAGS conftest.c -o conftest $LIBS $lib; then
|
||||
found=y
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ ! "$found" ]; then
|
||||
ac_result "not found"
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$lib" ]; then
|
||||
ac_result "ok (none needed)"
|
||||
else
|
||||
ac_result "ok ($lib)"
|
||||
LIBS="$LIBS $lib"
|
||||
fi
|
||||
}
|
||||
|
||||
ac_compile_run() {
|
||||
ac_link "$@" && ac_run ./conftest
|
||||
}
|
||||
|
||||
ac_grep_cpp() {
|
||||
pattern="$1"; shift
|
||||
ac_cpp "$@" && grep "$pattern" conftest.out >/dev/null
|
||||
}
|
||||
|
||||
ac_output() {
|
||||
for var in $ac_substitutes; do
|
||||
eval echo "\"s|@$var@|\$$var|\""
|
||||
done >conftest.sed
|
||||
for file in "$@"; do
|
||||
ac_msg "creating $file"
|
||||
if [ -f $file.in ]; then
|
||||
sed -f conftest.sed $file.in > $file.tmp
|
||||
mv -f $file.tmp $file
|
||||
ac_result ok
|
||||
else
|
||||
ac_result failed
|
||||
ac_fatal "$file.in not found"
|
||||
fi
|
||||
done
|
||||
rm -f conftest*
|
||||
}
|
||||
|
||||
ac_config_h() {
|
||||
h=${1:-config.h}
|
||||
ac_msg "creating $h"
|
||||
rm -f $1.tmp
|
||||
echo "/* automatically generated by configure. */" > $h.tmp
|
||||
echo "$CDEFS" | tr ' ' '
|
||||
' | sed -e 's/^-D/#define /' -e 's/=/ /' >> $h.tmp
|
||||
if [ -f $h ] && cmp -s $h.tmp $h ; then
|
||||
rm -f $h.tmp
|
||||
ac_result unchanged
|
||||
else
|
||||
mv -f $h.tmp $h
|
||||
ac_result ok
|
||||
fi
|
||||
CDEFS=-DHAVE_CONFIG_H
|
||||
}
|
||||
195
3rdparty/udns/dnsget.1
vendored
Normal file
195
3rdparty/udns/dnsget.1
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
.\" dnsget.1: dnsget manpage
|
||||
.\"
|
||||
.\" Copyright (C) 2005-2014 Michael Tokarev <mjt+udns@tls.msk.ru>
|
||||
.\" This file is part of UDNS library, an async DNS stub resolver.
|
||||
.\"
|
||||
.\" This library is free software; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU Lesser General Public
|
||||
.\" License as published by the Free Software Foundation; either
|
||||
.\" version 2.1 of the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" This library 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. See the GNU
|
||||
.\" Lesser General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU Lesser General Public
|
||||
.\" License along with this library, in file named COPYING.LGPL; if not,
|
||||
.\" write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
.\" Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
.TH dnsget 1 "Jan 2014" "User Utilities"
|
||||
|
||||
.SH NAME
|
||||
dnsget \- DNS lookup utility
|
||||
|
||||
.SH SYNOPSYS
|
||||
.B dnsget
|
||||
.RB [\| \-v \||\| \-q \|]
|
||||
.RB [\| \-c
|
||||
.IR class \|]
|
||||
.RB [\| \-t
|
||||
.IR type \|]
|
||||
.RB [\| \-o
|
||||
.IR opt , opt ,...]
|
||||
.IR name \|.\|.\|.
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dnsget
|
||||
is a simple command-line to perform DNS lookups, similar to
|
||||
.BR host (1)
|
||||
and
|
||||
.BR dig (1).
|
||||
It is useable for both interactive/debugging scenarious and
|
||||
in scripts.
|
||||
The program is implemented using
|
||||
.BR udns (3)
|
||||
library.
|
||||
|
||||
.PP
|
||||
By default,
|
||||
.B dnsget
|
||||
produces a human-readable output, similar to
|
||||
.RS
|
||||
.nf
|
||||
alias.example.com. CNAME www.example.com.
|
||||
www.example.com. A 192.168.1.1
|
||||
www.example.com. MX 10 mx.example.com.
|
||||
.fi
|
||||
.RE
|
||||
which is just sufficient to see how a given name resolves.
|
||||
Output format is controllable with
|
||||
.B \-v
|
||||
and
|
||||
.B \-q
|
||||
options -- the former increases verbosity level up to printing
|
||||
the whole DNS contents of all packets sent and received, which
|
||||
is suitable for debugging DNS problems, while the latter reduces
|
||||
the level, making output more quiet, up to bare result with no
|
||||
error messages, which is good for scripts.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
The following options are recognized by
|
||||
.BR dnsget :
|
||||
|
||||
.TP
|
||||
.B \-v
|
||||
produce more detailed output. More
|
||||
.BR \-v 's
|
||||
means more details will be produced. With single
|
||||
.BR \-v , dnsget
|
||||
will print contents of all received DNS packets (in a readable format),
|
||||
while with
|
||||
.BR \-vv ,
|
||||
it will output all outgoing DNS packets too.
|
||||
|
||||
.TP
|
||||
.B \-q
|
||||
the opposite for \fB\-v\fR -- produce less detailed output.
|
||||
With single
|
||||
.BR \-q , dnsget
|
||||
will only show (decoded) data from final DNS resource records (RR),
|
||||
while
|
||||
.B \-qq
|
||||
also suppresses error messages.
|
||||
|
||||
.TP
|
||||
\fB\-t \fItype\fR
|
||||
request record(s) of the given type \fItype\fR. By default,
|
||||
.B dnsget
|
||||
will ask for IPv4 address (A) record, or for PTR record if the
|
||||
argument in question is an IPv4 or IPv6 address. Recognized
|
||||
types include A, AAAA, MX, TXT, CNAME, PTR, NS, SOA, ANY and
|
||||
others.
|
||||
|
||||
.TP
|
||||
\fB\-c \fIclass\fR
|
||||
request DNS record(s) of the given class \fIclass\fR. By
|
||||
default
|
||||
.B dnsget
|
||||
uses IN class. Valid classes include IN, CH, HS, ANY.
|
||||
|
||||
.TP
|
||||
.B \-a
|
||||
(compatibility option). Equivalent to setting query type to
|
||||
.B ANY
|
||||
and increasing verbosity level
|
||||
.RB ( \-v ).
|
||||
|
||||
.TP
|
||||
.B \-C
|
||||
(planned)
|
||||
|
||||
.TP
|
||||
.B \-x
|
||||
(planned)
|
||||
|
||||
.TP
|
||||
\fB\-o \fIopt\fR,\fIopt\fR,...
|
||||
(may be specified several times).
|
||||
Set resolver options (in a form \fIoption\fR:\fIvalue\fR) as if they
|
||||
were set in
|
||||
.RB $ RES_OPTIONS
|
||||
environment variable, or set query flags:
|
||||
.RS
|
||||
.TP
|
||||
\fBtimeout\fR:\fIsec\fR
|
||||
Set initial query timeout to \fIsec\fR.
|
||||
.TP
|
||||
\fBattempts\fR:\fInum\fR
|
||||
(re)try every query \fInum\fR times before failing.
|
||||
.TP
|
||||
\fBudpbuf\fR:\fIbytes\fR
|
||||
set DNS UDP buffer size to \fIbytes\fR bytes. Valid values
|
||||
are from 512 to 65535. If \fIbytes\fR is greather than 512,
|
||||
EDNS0 (RFC 2671) extensions will be used.
|
||||
.TP
|
||||
\fBport\fR:\fInum\fR
|
||||
Use given UDP port number \fInum\fR instead of the default port 53 (domain).
|
||||
.TP
|
||||
\fBaa\fR
|
||||
set AA (auth only) query bit.
|
||||
.TP
|
||||
\fBnord\fR
|
||||
do not set RD (recursion desired) query bit (set by default).
|
||||
.TP
|
||||
\fBdnssec\fR or \fBdo\fR
|
||||
set DNSSEC OK (DO) query flag (\fBdnsget\fR does not verify DNSSEC signatures,
|
||||
only displays them; this is set in EDNS RR).
|
||||
.TP
|
||||
\fBcd\fR
|
||||
set CD (checking disabled) query bit.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
\fB\-n \fInameserver\fR
|
||||
Use the given nameserver(s) (may be specified more than once)
|
||||
instead of the default. Using this option has the same same effect as
|
||||
.RB $ NSCACHEIP
|
||||
or
|
||||
.RB $ NAMESERVERS
|
||||
environment variables, with the only difference that only IPv4 addresses
|
||||
are recognized for now, and it is possible to specify names (which will
|
||||
be resolved using default settings) instead of IP addresses.
|
||||
|
||||
.TP
|
||||
.B \-h
|
||||
print short help and exit.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
When all names where resovled successefully,
|
||||
.B dnsget
|
||||
exits with zero exit status. If at least one name was not found,
|
||||
.B dnsget
|
||||
will exit with return code 100. If some other error occured during
|
||||
name resolution, it will exit with code 99. In case of usage or
|
||||
initialization error,
|
||||
.B dnsget
|
||||
will return 1.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR host (1)
|
||||
.BR dig (1)
|
||||
.BR resolv.conf (5)
|
||||
.BR udns (3).
|
||||
759
3rdparty/udns/dnsget.c
vendored
Normal file
759
3rdparty/udns/dnsget.c
vendored
Normal file
@@ -0,0 +1,759 @@
|
||||
/* dnsget.c
|
||||
simple host/dig-like application using UDNS library
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "udns.h"
|
||||
|
||||
#ifndef HAVE_GETOPT
|
||||
# include "getopt.c"
|
||||
#endif
|
||||
|
||||
#ifndef AF_INET6
|
||||
# define AF_INET6 10
|
||||
#endif
|
||||
|
||||
static char *progname;
|
||||
static int verbose = 1;
|
||||
static int errors;
|
||||
static int notfound;
|
||||
|
||||
/* verbosity level:
|
||||
* <0 - bare result
|
||||
* 0 - bare result and error messages
|
||||
* 1 - readable result
|
||||
* 2 - received packet contents and `trying ...' stuff
|
||||
* 3 - sent and received packet contents
|
||||
*/
|
||||
|
||||
static void die(int errnum, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
fprintf(stderr, "%s: ", progname);
|
||||
va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);
|
||||
if (errnum) fprintf(stderr, ": %s\n", strerror(errnum));
|
||||
else putc('\n', stderr);
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static const char *dns_xntop(int af, const void *src) {
|
||||
static char buf[6*5+4*4];
|
||||
return dns_ntop(af, src, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
struct query {
|
||||
const char *name; /* original query string */
|
||||
unsigned char *dn; /* the DN being looked up */
|
||||
enum dns_type qtyp; /* type of the query */
|
||||
};
|
||||
|
||||
static void query_free(struct query *q) {
|
||||
free(q->dn);
|
||||
free(q);
|
||||
}
|
||||
|
||||
static struct query *
|
||||
query_new(const char *name, const unsigned char *dn, enum dns_type qtyp) {
|
||||
struct query *q = malloc(sizeof(*q));
|
||||
unsigned l = dns_dnlen(dn);
|
||||
unsigned char *cdn = malloc(l);
|
||||
if (!q || !cdn) die(0, "out of memory");
|
||||
memcpy(cdn, dn, l);
|
||||
q->name = name;
|
||||
q->dn = cdn;
|
||||
q->qtyp = qtyp;
|
||||
return q;
|
||||
}
|
||||
|
||||
static enum dns_class qcls = DNS_C_IN;
|
||||
|
||||
static void
|
||||
dnserror(struct query *q, int errnum) {
|
||||
if (verbose >= 0)
|
||||
fprintf(stderr, "%s: unable to lookup %s record for %s: %s\n", progname,
|
||||
dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum));
|
||||
if (errnum == DNS_E_NXDOMAIN || errnum == DNS_E_NODATA)
|
||||
++notfound;
|
||||
else
|
||||
++errors;
|
||||
query_free(q);
|
||||
}
|
||||
|
||||
static const unsigned char *
|
||||
printtxt(const unsigned char *c) {
|
||||
unsigned n = *c++;
|
||||
const unsigned char *e = c + n;
|
||||
if (verbose > 0) while(c < e) {
|
||||
if (*c < ' ' || *c >= 127) printf("\\%03u", *c);
|
||||
else if (*c == '\\' || *c == '"') printf("\\%c", *c);
|
||||
else putchar(*c);
|
||||
++c;
|
||||
}
|
||||
else
|
||||
fwrite(c, n, 1, stdout);
|
||||
return e;
|
||||
}
|
||||
|
||||
static void
|
||||
printhex(const unsigned char *c, const unsigned char *e) {
|
||||
while(c < e)
|
||||
printf("%02x", *c++);
|
||||
}
|
||||
|
||||
static unsigned char to_b64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static void
|
||||
printb64(const unsigned char *c, const unsigned char *e) {
|
||||
while(c < e) {
|
||||
putchar(to_b64[c[0] >> 2]);
|
||||
if (c+1 < e) {
|
||||
putchar(to_b64[(c[0] & 0x3) << 4 | c[1] >> 4]);
|
||||
if (c+2 < e) {
|
||||
putchar(to_b64[(c[1] & 0xf) << 2 | c[2] >> 6]);
|
||||
putchar(to_b64[c[2] & 0x3f]);
|
||||
}
|
||||
else {
|
||||
putchar(to_b64[(c[1] & 0xf) << 2]);
|
||||
putchar('=');
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
putchar(to_b64[(c[0] & 0x3) << 4]);
|
||||
putchar('=');
|
||||
putchar('=');
|
||||
break;
|
||||
}
|
||||
c += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
printdate(time_t time) {
|
||||
struct tm *tm = gmtime(&time);
|
||||
printf("%04d%02d%02d%02d%02d%02d",
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
}
|
||||
|
||||
static void
|
||||
printrr(const struct dns_parse *p, struct dns_rr *rr) {
|
||||
const unsigned char *pkt = p->dnsp_pkt;
|
||||
const unsigned char *end = p->dnsp_end;
|
||||
const unsigned char *dptr = rr->dnsrr_dptr;
|
||||
const unsigned char *dend = rr->dnsrr_dend;
|
||||
unsigned char *dn = rr->dnsrr_dn;
|
||||
const unsigned char *c;
|
||||
unsigned n;
|
||||
|
||||
if (verbose > 0) {
|
||||
if (verbose > 1) {
|
||||
if (!p->dnsp_rrl && !rr->dnsrr_dn[0] && rr->dnsrr_typ == DNS_T_OPT) {
|
||||
printf(";EDNS%d OPT record (UDPsize: %d, ERcode: %d, Flags: 0x%02x): %d bytes\n",
|
||||
(rr->dnsrr_ttl>>16) & 0xff, /* version */
|
||||
rr->dnsrr_cls, /* udp size */
|
||||
(rr->dnsrr_ttl>>24) & 0xff, /* extended rcode */
|
||||
rr->dnsrr_ttl & 0xffff, /* flags */
|
||||
rr->dnsrr_dsz);
|
||||
return;
|
||||
}
|
||||
n = printf("%s.", dns_dntosp(rr->dnsrr_dn));
|
||||
printf("%s%u\t%s\t%s\t",
|
||||
n > 15 ? "\t" : n > 7 ? "\t\t" : "\t\t\t",
|
||||
rr->dnsrr_ttl,
|
||||
dns_classname(rr->dnsrr_cls),
|
||||
dns_typename(rr->dnsrr_typ));
|
||||
}
|
||||
else
|
||||
printf("%s. %s ", dns_dntosp(rr->dnsrr_dn), dns_typename(rr->dnsrr_typ));
|
||||
}
|
||||
|
||||
switch(rr->dnsrr_typ) {
|
||||
|
||||
case DNS_T_CNAME:
|
||||
case DNS_T_PTR:
|
||||
case DNS_T_NS:
|
||||
case DNS_T_MB:
|
||||
case DNS_T_MD:
|
||||
case DNS_T_MF:
|
||||
case DNS_T_MG:
|
||||
case DNS_T_MR:
|
||||
if (dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto xperr;
|
||||
printf("%s.", dns_dntosp(dn));
|
||||
break;
|
||||
|
||||
case DNS_T_A:
|
||||
if (rr->dnsrr_dsz != 4) goto xperr;
|
||||
printf("%d.%d.%d.%d", dptr[0], dptr[1], dptr[2], dptr[3]);
|
||||
break;
|
||||
|
||||
case DNS_T_AAAA:
|
||||
if (rr->dnsrr_dsz != 16) goto xperr;
|
||||
printf("%s", dns_xntop(AF_INET6, dptr));
|
||||
break;
|
||||
|
||||
case DNS_T_MX:
|
||||
c = dptr + 2;
|
||||
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
|
||||
printf("%d %s.", dns_get16(dptr), dns_dntosp(dn));
|
||||
break;
|
||||
|
||||
case DNS_T_TXT:
|
||||
/* first verify it */
|
||||
for(c = dptr; c < dend; c += n) {
|
||||
n = *c++;
|
||||
if (c + n > dend) goto xperr;
|
||||
}
|
||||
c = dptr; n = 0;
|
||||
while (c < dend) {
|
||||
if (verbose > 0) printf(n++ ? "\" \"":"\"");
|
||||
c = printtxt(c);
|
||||
}
|
||||
if (verbose > 0) putchar('"');
|
||||
break;
|
||||
|
||||
case DNS_T_HINFO: /* CPU, OS */
|
||||
c = dptr;
|
||||
n = *c++; if ((c += n) >= dend) goto xperr;
|
||||
n = *c++; if ((c += n) != dend) goto xperr;
|
||||
c = dptr;
|
||||
if (verbose > 0) putchar('"');
|
||||
c = printtxt(c);
|
||||
if (verbose > 0) printf("\" \""); else putchar(' ');
|
||||
printtxt(c);
|
||||
if (verbose > 0) putchar('"');
|
||||
break;
|
||||
|
||||
case DNS_T_WKS:
|
||||
c = dptr;
|
||||
if (dptr + 4 + 2 >= end) goto xperr;
|
||||
printf("%s %d", dns_xntop(AF_INET, dptr), dptr[4]);
|
||||
c = dptr + 5;
|
||||
for (n = 0; c < dend; ++c, n += 8) {
|
||||
if (*c) {
|
||||
unsigned b;
|
||||
for (b = 0; b < 8; ++b)
|
||||
if (*c & (1 << (7-b))) printf(" %d", n + b);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DNS_T_SRV: /* prio weight port targetDN */
|
||||
c = dptr;
|
||||
c += 2 + 2 + 2;
|
||||
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
|
||||
c = dptr;
|
||||
printf("%d %d %d %s.",
|
||||
dns_get16(c+0), dns_get16(c+2), dns_get16(c+4),
|
||||
dns_dntosp(dn));
|
||||
break;
|
||||
|
||||
case DNS_T_NAPTR: /* order pref flags serv regexp repl */
|
||||
c = dptr;
|
||||
c += 4; /* order, pref */
|
||||
for (n = 0; n < 3; ++n)
|
||||
if (c >= dend) goto xperr;
|
||||
else c += *c + 1;
|
||||
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
|
||||
c = dptr;
|
||||
printf("%u %u", dns_get16(c+0), dns_get16(c+2));
|
||||
c += 4;
|
||||
for(n = 0; n < 3; ++n) {
|
||||
putchar(' ');
|
||||
if (verbose > 0) putchar('"');
|
||||
c = printtxt(c);
|
||||
if (verbose > 0) putchar('"');
|
||||
}
|
||||
printf(" %s.", dns_dntosp(dn));
|
||||
break;
|
||||
|
||||
case DNS_T_KEY:
|
||||
case DNS_T_DNSKEY:
|
||||
/* flags(2) proto(1) algo(1) pubkey */
|
||||
case DNS_T_DS:
|
||||
case DNS_T_DLV:
|
||||
/* ktag(2) proto(1) algo(1) pubkey */
|
||||
c = dptr;
|
||||
if (c + 2 + 1 + 1 > dend) goto xperr;
|
||||
printf("%d %d %d", dns_get16(c), c[2], c[3]);
|
||||
c += 2 + 1 + 1;
|
||||
if (c < dend) {
|
||||
putchar(' ');
|
||||
printb64(c, dend);
|
||||
}
|
||||
break;
|
||||
|
||||
case DNS_T_SIG:
|
||||
case DNS_T_RRSIG:
|
||||
/* type(2) algo(1) labels(1) ottl(4) sexp(4) sinc(4) tag(2) sdn sig */
|
||||
c = dptr;
|
||||
c += 2 + 1 + 1 + 4 + 4 + 4 + 2;
|
||||
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr;
|
||||
printf("%s %u %u %u ",
|
||||
dns_typename(dns_get16(dptr)), dptr[2], dptr[3], dns_get32(dptr+4));
|
||||
printdate(dns_get32(dptr+8));
|
||||
putchar(' ');
|
||||
printdate(dns_get32(dptr+12));
|
||||
printf(" %d %s. ", dns_get16(dptr+10), dns_dntosp(dn));
|
||||
printb64(c, dend);
|
||||
break;
|
||||
|
||||
case DNS_T_SSHFP: /* algo(1), fp type(1), fp... */
|
||||
if (dend < dptr + 3) goto xperr;
|
||||
printf("%u %u ", dptr[0], dptr[1]); /* algo, fp type */
|
||||
printhex(dptr + 2, dend);
|
||||
break;
|
||||
|
||||
#if 0 /* unused RR types? */
|
||||
case DNS_T_NSEC: /* nextDN bitmaps */
|
||||
c = dptr;
|
||||
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr;
|
||||
printf("%s.", dns_dntosp(dn));
|
||||
unfinished.
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
case DNS_T_SOA:
|
||||
c = dptr;
|
||||
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
|
||||
dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
|
||||
c + 4*5 != dend)
|
||||
goto xperr;
|
||||
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
|
||||
printf("%s. ", dns_dntosp(dn));
|
||||
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
|
||||
printf("%s. ", dns_dntosp(dn));
|
||||
printf("%u %u %u %u %u",
|
||||
dns_get32(dptr), dns_get32(dptr+4), dns_get32(dptr+8),
|
||||
dns_get32(dptr+12), dns_get32(dptr+16));
|
||||
break;
|
||||
|
||||
case DNS_T_MINFO:
|
||||
c = dptr;
|
||||
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
|
||||
dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 ||
|
||||
c != dend)
|
||||
goto xperr;
|
||||
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
|
||||
printf("%s. ", dns_dntosp(dn));
|
||||
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN);
|
||||
printf("%s.", dns_dntosp(dn));
|
||||
break;
|
||||
|
||||
case DNS_T_NULL:
|
||||
default:
|
||||
printhex(dptr, dend);
|
||||
break;
|
||||
}
|
||||
putchar('\n');
|
||||
return;
|
||||
|
||||
xperr:
|
||||
printf("<parse error>\n");
|
||||
++errors;
|
||||
}
|
||||
|
||||
static int
|
||||
printsection(struct dns_parse *p, int nrr, const char *sname) {
|
||||
struct dns_rr rr;
|
||||
int r;
|
||||
if (!nrr) return 0;
|
||||
if (verbose > 1) printf("\n;; %s section (%d):\n", sname, nrr);
|
||||
|
||||
p->dnsp_rrl = nrr;
|
||||
while((r = dns_nextrr(p, &rr)) > 0)
|
||||
printrr(p, &rr);
|
||||
if (r < 0) printf("<<ERROR>>\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
/* dbgcb will only be called if verbose > 1 */
|
||||
static void
|
||||
dbgcb(int code, const struct sockaddr *sa, unsigned slen,
|
||||
const unsigned char *pkt, int r,
|
||||
const struct dns_query *unused_q, void *unused_data) {
|
||||
struct dns_parse p;
|
||||
const unsigned char *cur, *end;
|
||||
int numqd;
|
||||
|
||||
if (code > 0) {
|
||||
printf(";; trying %s.\n", dns_dntosp(dns_payload(pkt)));
|
||||
printf(";; sending %d bytes query to ", r);
|
||||
}
|
||||
else
|
||||
printf(";; received %d bytes response from ", r);
|
||||
if (sa->sa_family == AF_INET && slen >= sizeof(struct sockaddr_in))
|
||||
printf("%s port %d\n",
|
||||
dns_xntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr),
|
||||
htons(((struct sockaddr_in*)sa)->sin_port));
|
||||
#ifdef HAVE_IPv6
|
||||
else if (sa->sa_family == AF_INET6 && slen >= sizeof(struct sockaddr_in6))
|
||||
printf("%s port %d\n",
|
||||
dns_xntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr),
|
||||
htons(((struct sockaddr_in6*)sa)->sin6_port));
|
||||
#endif
|
||||
else
|
||||
printf("<<unknown socket type %d>>\n", sa->sa_family);
|
||||
if (code > 0 && verbose < 3) {
|
||||
putchar('\n');
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == -2) printf(";; reply from unexpected source\n");
|
||||
if (code == -5) printf(";; reply to a query we didn't sent (or old)\n");
|
||||
if (r < DNS_HSIZE) {
|
||||
printf(";; short packet (%d bytes)\n", r);
|
||||
return;
|
||||
}
|
||||
if (dns_opcode(pkt) != 0)
|
||||
printf(";; unexpected opcode %d\n", dns_opcode(pkt));
|
||||
if (dns_tc(pkt) != 0)
|
||||
printf(";; warning: TC bit set, probably incomplete reply\n");
|
||||
|
||||
printf(";; ->>HEADER<<- opcode: ");
|
||||
switch(dns_opcode(pkt)) {
|
||||
case 0: printf("QUERY"); break;
|
||||
case 1: printf("IQUERY"); break;
|
||||
case 2: printf("STATUS"); break;
|
||||
default: printf("UNKNOWN(%u)", dns_opcode(pkt)); break;
|
||||
}
|
||||
printf(", status: %s, id: %d, size: %d\n;; flags:",
|
||||
dns_rcodename(dns_rcode(pkt)), dns_qid(pkt), r);
|
||||
if (dns_qr(pkt)) printf(" qr");
|
||||
if (dns_aa(pkt)) printf(" aa");
|
||||
if (dns_tc(pkt)) printf(" tc");
|
||||
if (dns_rd(pkt)) printf(" rd");
|
||||
if (dns_ra(pkt)) printf(" ra");
|
||||
/* if (dns_z(pkt)) printf(" z"); only one reserved bit left */
|
||||
if (dns_ad(pkt)) printf(" ad");
|
||||
if (dns_cd(pkt)) printf(" cd");
|
||||
numqd = dns_numqd(pkt);
|
||||
printf("; QUERY: %d, ANSWER: %d, AUTHORITY: %d, ADDITIONAL: %d\n",
|
||||
numqd, dns_numan(pkt), dns_numns(pkt), dns_numar(pkt));
|
||||
if (numqd != 1)
|
||||
printf(";; unexpected number of entries in QUERY section: %d\n",
|
||||
numqd);
|
||||
printf("\n;; QUERY SECTION (%d):\n", numqd);
|
||||
cur = dns_payload(pkt);
|
||||
end = pkt + r;
|
||||
while(numqd--) {
|
||||
if (dns_getdn(pkt, &cur, end, p.dnsp_dnbuf, DNS_MAXDN) <= 0 ||
|
||||
cur + 4 > end) {
|
||||
printf("; invalid query section\n");
|
||||
return;
|
||||
}
|
||||
r = printf(";%s.", dns_dntosp(p.dnsp_dnbuf));
|
||||
printf("%s%s\t%s\n",
|
||||
r > 23 ? "\t" : r > 15 ? "\t\t" : r > 7 ? "\t\t\t" : "\t\t\t\t",
|
||||
dns_classname(dns_get16(cur+2)), dns_typename(dns_get16(cur)));
|
||||
cur += 4;
|
||||
}
|
||||
|
||||
p.dnsp_pkt = pkt;
|
||||
p.dnsp_cur = p.dnsp_ans = cur;
|
||||
p.dnsp_end = end;
|
||||
p.dnsp_qdn = NULL;
|
||||
p.dnsp_qcls = p.dnsp_qtyp = 0;
|
||||
p.dnsp_ttl = 0xffffffffu;
|
||||
p.dnsp_nrr = 0;
|
||||
|
||||
r = printsection(&p, dns_numan(pkt), "ANSWER");
|
||||
if (r == 0)
|
||||
r = printsection(&p, dns_numns(pkt), "AUTHORITY");
|
||||
if (r == 0)
|
||||
r = printsection(&p, dns_numar(pkt), "ADDITIONAL");
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void dnscb(struct dns_ctx *ctx, void *result, void *data) {
|
||||
int r = dns_status(ctx);
|
||||
struct query *q = data;
|
||||
struct dns_parse p;
|
||||
struct dns_rr rr;
|
||||
unsigned nrr;
|
||||
unsigned char dn[DNS_MAXDN];
|
||||
const unsigned char *pkt, *cur, *end;
|
||||
if (!result) {
|
||||
dnserror(q, r);
|
||||
return;
|
||||
}
|
||||
pkt = result; end = pkt + r; cur = dns_payload(pkt);
|
||||
dns_getdn(pkt, &cur, end, dn, sizeof(dn));
|
||||
dns_initparse(&p, NULL, pkt, cur, end);
|
||||
p.dnsp_qcls = p.dnsp_qtyp = 0;
|
||||
nrr = 0;
|
||||
while((r = dns_nextrr(&p, &rr)) > 0) {
|
||||
if (!dns_dnequal(dn, rr.dnsrr_dn)) continue;
|
||||
if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) &&
|
||||
(q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
|
||||
++nrr;
|
||||
else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
|
||||
if (dns_getdn(pkt, &rr.dnsrr_dptr, end,
|
||||
p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 ||
|
||||
rr.dnsrr_dptr != rr.dnsrr_dend) {
|
||||
r = DNS_E_PROTOCOL;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (verbose == 1) {
|
||||
printf("%s.", dns_dntosp(dn));
|
||||
printf(" CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf));
|
||||
}
|
||||
dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!r && !nrr)
|
||||
r = DNS_E_NODATA;
|
||||
if (r < 0) {
|
||||
dnserror(q, r);
|
||||
free(result);
|
||||
return;
|
||||
}
|
||||
if (verbose < 2) { /* else it is already printed by dbgfn */
|
||||
dns_rewind(&p, NULL);
|
||||
p.dnsp_qtyp = q->qtyp == DNS_T_ANY ? 0 : q->qtyp;
|
||||
p.dnsp_qcls = qcls == DNS_C_ANY ? 0 : qcls;
|
||||
while(dns_nextrr(&p, &rr))
|
||||
printrr(&p, &rr);
|
||||
}
|
||||
free(result);
|
||||
query_free(q);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
int fd;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
time_t now;
|
||||
char *ns[DNS_MAXSERV];
|
||||
int nns = 0;
|
||||
struct query *q;
|
||||
enum dns_type qtyp = 0;
|
||||
struct dns_ctx *nctx = NULL;
|
||||
int flags = 0;
|
||||
|
||||
if (!(progname = strrchr(argv[0], '/'))) progname = argv[0];
|
||||
else argv[0] = ++progname;
|
||||
|
||||
if (argc <= 1)
|
||||
die(0, "try `%s -h' for help", progname);
|
||||
|
||||
if (dns_init(NULL, 0) < 0 || !(nctx = dns_new(NULL)))
|
||||
die(errno, "unable to initialize dns library");
|
||||
/* we keep two dns contexts: one may be needed to resolve
|
||||
* nameservers if given as names, using default options.
|
||||
*/
|
||||
|
||||
while((i = getopt(argc, argv, "vqt:c:an:o:f:h")) != EOF) switch(i) {
|
||||
case 'v': ++verbose; break;
|
||||
case 'q': --verbose; break;
|
||||
case 't':
|
||||
if (optarg[0] == '*' && !optarg[1])
|
||||
i = DNS_T_ANY;
|
||||
else if ((i = dns_findtypename(optarg)) <= 0)
|
||||
die(0, "unrecognized query type `%s'", optarg);
|
||||
qtyp = i;
|
||||
break;
|
||||
case 'c':
|
||||
if (optarg[0] == '*' && !optarg[1])
|
||||
i = DNS_C_ANY;
|
||||
else if ((i = dns_findclassname(optarg)) < 0)
|
||||
die(0, "unrecognized query class `%s'", optarg);
|
||||
qcls = i;
|
||||
break;
|
||||
case 'a':
|
||||
qtyp = DNS_T_ANY;
|
||||
++verbose;
|
||||
break;
|
||||
case 'n':
|
||||
if (nns >= DNS_MAXSERV)
|
||||
die(0, "too many nameservers, %d max", DNS_MAXSERV);
|
||||
ns[nns++] = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
case 'f': {
|
||||
char *opt;
|
||||
const char *const delim = " \t,;";
|
||||
for(opt = strtok(optarg, delim); opt != NULL; opt = strtok(NULL, delim)) {
|
||||
if (dns_set_opts(NULL, optarg) == 0)
|
||||
;
|
||||
else if (strcmp(opt, "aa") == 0) flags |= DNS_AAONLY;
|
||||
else if (strcmp(optarg, "nord") == 0) flags |= DNS_NORD;
|
||||
else if (strcmp(optarg, "dnssec") == 0) flags |= DNS_SET_DO;
|
||||
else if (strcmp(optarg, "do") == 0) flags |= DNS_SET_DO;
|
||||
else if (strcmp(optarg, "cd") == 0) flags |= DNS_SET_CD;
|
||||
else
|
||||
die(0, "invalid option: `%s'", opt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
printf(
|
||||
"%s: simple DNS query tool (using udns version %s)\n"
|
||||
"Usage: %s [options] domain-name...\n"
|
||||
"where options are:\n"
|
||||
" -h - print this help and exit\n"
|
||||
" -v - be more verbose\n"
|
||||
" -q - be less verbose\n"
|
||||
" -t type - set query type (A, AAA, PTR etc)\n"
|
||||
" -c class - set query class (IN (default), CH, HS, *)\n"
|
||||
" -a - equivalent to -t ANY -v\n"
|
||||
" -n ns - use given nameserver(s) instead of default\n"
|
||||
" (may be specified multiple times)\n"
|
||||
" -o opt,opt,... (comma- or space-separated list,\n"
|
||||
" may be specified more than once):\n"
|
||||
" set resovler options (the same as setting $RES_OPTIONS):\n"
|
||||
" timeout:sec - initial query timeout\n"
|
||||
" attempts:num - number of attempt to resovle a query\n"
|
||||
" ndots:num - if name has more than num dots, lookup it before search\n"
|
||||
" port:num - port number for queries instead of default 53\n"
|
||||
" udpbuf:num - size of UDP buffer (use EDNS0 if >512)\n"
|
||||
" or query flags:\n"
|
||||
" aa,nord,dnssec,do,cd - set query flag (auth-only, no recursion,\n"
|
||||
" enable DNSSEC (DNSSEC Ok), check disabled)\n"
|
||||
, progname, dns_version(), progname);
|
||||
return 0;
|
||||
default:
|
||||
die(0, "try `%s -h' for help", progname);
|
||||
}
|
||||
|
||||
argc -= optind; argv += optind;
|
||||
if (!argc)
|
||||
die(0, "no name(s) to query specified");
|
||||
|
||||
if (nns) {
|
||||
/* if nameservers given as names, resolve them.
|
||||
* We only allow IPv4 nameservers as names for now.
|
||||
* Ok, it is easy enouth to try both AAAA and A,
|
||||
* but the question is what to do by default.
|
||||
*/
|
||||
struct sockaddr_in sin;
|
||||
int j, r = 0, opened = 0;
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(dns_set_opt(NULL, DNS_OPT_PORT, -1));
|
||||
dns_add_serv(NULL, NULL);
|
||||
for(i = 0; i < nns; ++i) {
|
||||
if (dns_pton(AF_INET, ns[i], &sin.sin_addr) <= 0) {
|
||||
struct dns_rr_a4 *rr;
|
||||
if (!opened) {
|
||||
if (dns_open(nctx) < 0)
|
||||
die(errno, "unable to initialize dns context");
|
||||
opened = 1;
|
||||
}
|
||||
rr = dns_resolve_a4(nctx, ns[i], 0);
|
||||
if (!rr)
|
||||
die(0, "unable to resolve nameserver %s: %s",
|
||||
ns[i], dns_strerror(dns_status(nctx)));
|
||||
for(j = 0; j < rr->dnsa4_nrr; ++j) {
|
||||
sin.sin_addr = rr->dnsa4_addr[j];
|
||||
if ((r = dns_add_serv_s(NULL, (struct sockaddr *)&sin)) < 0)
|
||||
break;
|
||||
}
|
||||
free(rr);
|
||||
}
|
||||
else
|
||||
r = dns_add_serv_s(NULL, (struct sockaddr *)&sin);
|
||||
if (r < 0)
|
||||
die(errno, "unable to add nameserver %s",
|
||||
dns_xntop(AF_INET, &sin.sin_addr));
|
||||
}
|
||||
}
|
||||
dns_free(nctx);
|
||||
|
||||
fd = dns_open(NULL);
|
||||
if (fd < 0)
|
||||
die(errno, "unable to initialize dns context");
|
||||
|
||||
if (verbose > 1)
|
||||
dns_set_dbgfn(NULL, dbgcb);
|
||||
|
||||
if (flags)
|
||||
dns_set_opt(NULL, DNS_OPT_FLAGS, flags);
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
char *name = argv[i];
|
||||
union {
|
||||
struct in_addr addr;
|
||||
struct in6_addr addr6;
|
||||
} a;
|
||||
unsigned char dn[DNS_MAXDN];
|
||||
enum dns_type l_qtyp = 0;
|
||||
int abs;
|
||||
if (dns_pton(AF_INET, name, &a.addr) > 0) {
|
||||
dns_a4todn(&a.addr, 0, dn, sizeof(dn));
|
||||
l_qtyp = DNS_T_PTR;
|
||||
abs = 1;
|
||||
}
|
||||
#ifdef HAVE_IPv6
|
||||
else if (dns_pton(AF_INET6, name, &a.addr6) > 0) {
|
||||
dns_a6todn(&a.addr6, 0, dn, sizeof(dn));
|
||||
l_qtyp = DNS_T_PTR;
|
||||
abs = 1;
|
||||
}
|
||||
#endif
|
||||
else if (!dns_ptodn(name, strlen(name), dn, sizeof(dn), &abs))
|
||||
die(0, "invalid name `%s'\n", name);
|
||||
else
|
||||
l_qtyp = DNS_T_A;
|
||||
if (qtyp) l_qtyp = qtyp;
|
||||
q = query_new(name, dn, l_qtyp);
|
||||
if (abs) abs = DNS_NOSRCH;
|
||||
if (!dns_submit_dn(NULL, dn, qcls, l_qtyp, abs, 0, dnscb, q))
|
||||
dnserror(q, dns_status(NULL));
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
now = 0;
|
||||
while((i = dns_timeouts(NULL, -1, now)) > 0) {
|
||||
FD_SET(fd, &fds);
|
||||
tv.tv_sec = i;
|
||||
tv.tv_usec = 0;
|
||||
i = select(fd+1, &fds, 0, 0, &tv);
|
||||
now = time(NULL);
|
||||
if (i > 0) dns_ioevent(NULL, now);
|
||||
}
|
||||
|
||||
return errors ? 1 : notfound ? 100 : 0;
|
||||
}
|
||||
114
3rdparty/udns/ex-rdns.c
vendored
Normal file
114
3rdparty/udns/ex-rdns.c
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
/* ex-rdns.c
|
||||
parallel rDNS resolver example - read IP addresses from stdin,
|
||||
write domain names to stdout
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/poll.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "udns.h"
|
||||
|
||||
static int curq;
|
||||
|
||||
static const char *n2ip(const unsigned char *c) {
|
||||
static char b[sizeof("255.255.255.255")];
|
||||
sprintf(b, "%u.%u.%u.%u", c[0], c[1], c[2], c[3]);
|
||||
return b;
|
||||
}
|
||||
static void dnscb(struct dns_ctx *ctx, struct dns_rr_ptr *rr, void *data) {
|
||||
const char *ip = n2ip((unsigned char *)&data);
|
||||
int i;
|
||||
--curq;
|
||||
if (rr) {
|
||||
printf("%s", ip);
|
||||
for(i = 0; i < rr->dnsptr_nrr; ++i)
|
||||
printf(" %s", rr->dnsptr_ptr[i]);
|
||||
putchar('\n');
|
||||
free(rr);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "%s: %s\n", ip, dns_strerror(dns_status(ctx)));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int c;
|
||||
time_t now;
|
||||
int maxq = 10;
|
||||
struct pollfd pfd;
|
||||
char linebuf[1024];
|
||||
char *eol;
|
||||
int eof;
|
||||
|
||||
if (dns_init(NULL, 1) < 0) {
|
||||
fprintf(stderr, "unable to initialize dns library\n");
|
||||
return 1;
|
||||
}
|
||||
while((c = getopt(argc, argv, "m:r")) != EOF) switch(c) {
|
||||
case 'm': maxq = atoi(optarg); break;
|
||||
case 'r':
|
||||
dns_set_opt(0, DNS_OPT_FLAGS,
|
||||
dns_set_opt(0, DNS_OPT_FLAGS, -1) | DNS_NORD);
|
||||
break;
|
||||
default: return 1;
|
||||
}
|
||||
if (argc != optind) return 1;
|
||||
|
||||
pfd.fd = dns_sock(0);
|
||||
pfd.events = POLLIN;
|
||||
now = time(NULL);
|
||||
c = optind;
|
||||
eof = 0;
|
||||
while(curq || !eof) {
|
||||
if (!eof && curq < maxq) {
|
||||
union { struct in_addr a; void *p; } pa;
|
||||
if (!fgets(linebuf, sizeof(linebuf), stdin)) {
|
||||
eof = 1;
|
||||
continue;
|
||||
}
|
||||
eol = strchr(linebuf, '\n');
|
||||
if (eol) *eol = '\0';
|
||||
if (!linebuf[0]) continue;
|
||||
if (dns_pton(AF_INET, linebuf, &pa.a) <= 0)
|
||||
fprintf(stderr, "%s: invalid address\n", linebuf);
|
||||
else if (dns_submit_a4ptr(0, &pa.a, dnscb, pa.p) == 0)
|
||||
fprintf(stderr, "%s: unable to submit query: %s\n",
|
||||
linebuf, dns_strerror(dns_status(0)));
|
||||
else
|
||||
++curq;
|
||||
continue;
|
||||
}
|
||||
if (curq) {
|
||||
c = dns_timeouts(0, -1, now);
|
||||
c = poll(&pfd, 1, c < 0 ? -1 : c * 1000);
|
||||
now = time(NULL);
|
||||
if (c)
|
||||
dns_ioevent(0, now);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
165
3rdparty/udns/getopt.c
vendored
Normal file
165
3rdparty/udns/getopt.c
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
/* getopt.c
|
||||
* Simple getopt() implementation.
|
||||
*
|
||||
* Standard interface:
|
||||
* extern int getopt(int argc, char *const *argv, const char *opts);
|
||||
* extern int optind; current index in argv[]
|
||||
* extern char *optarg; argument for the current option
|
||||
* extern int optopt; the current option
|
||||
* extern int opterr; to control error printing
|
||||
*
|
||||
* Some minor extensions:
|
||||
* ignores leading `+' sign in opts[] (unemplemented GNU extension)
|
||||
* handles optional arguments, in form "x::" in opts[]
|
||||
* if opts[] starts with `:', will return `:' in case of missing required
|
||||
* argument, instead of '?'.
|
||||
*
|
||||
* Compile with -DGETOPT_NO_OPTERR to never print errors internally.
|
||||
* Compile with -DGETOPT_NO_STDIO to use write() calls instead of fprintf() for
|
||||
* error reporting (ignored with -DGETOPT_NO_OPTERR).
|
||||
* Compile with -DGETOPT_CLASS=static to get static linkage.
|
||||
* Compile with -DGETOPT_MY to redefine all visible symbols to be prefixed
|
||||
* with "my_", like my_getopt instead of getopt.
|
||||
* Compile with -DTEST to get a test executable.
|
||||
*
|
||||
* Written by Michael Tokarev. Public domain.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef GETOPT_CLASS
|
||||
# define GETOPT_CLASS
|
||||
#endif
|
||||
#ifdef GETOPT_MY
|
||||
# define optarg my_optarg
|
||||
# define optind my_optind
|
||||
# define opterr my_opterr
|
||||
# define optopt my_optopt
|
||||
# define getopt my_getopt
|
||||
#endif
|
||||
|
||||
GETOPT_CLASS char *optarg /* = NULL */;
|
||||
GETOPT_CLASS int optind = 1;
|
||||
GETOPT_CLASS int opterr = 1;
|
||||
GETOPT_CLASS int optopt;
|
||||
|
||||
static char *nextc /* = NULL */;
|
||||
|
||||
#if defined(GETOPT_NO_OPTERR)
|
||||
|
||||
#define printerr(argv, msg)
|
||||
|
||||
#elif defined(GETOPT_NO_STDIO)
|
||||
|
||||
extern int write(int, void *, int);
|
||||
|
||||
static void printerr(char *const *argv, const char *msg) {
|
||||
if (opterr) {
|
||||
char buf[64];
|
||||
unsigned pl = strlen(argv[0]);
|
||||
unsigned ml = strlen(msg);
|
||||
char *p;
|
||||
if (pl + /*": "*/2 + ml + /*" -- c\n"*/6 > sizeof(buf)) {
|
||||
write(2, argv[0], pl);
|
||||
p = buf;
|
||||
}
|
||||
else {
|
||||
memcpy(buf, argv[0], ml);
|
||||
p = buf + pl;
|
||||
}
|
||||
*p++ = ':'; *p++ = ' ';
|
||||
memcpy(p, msg, ml); p += ml;
|
||||
*p++ = ' '; *p++ = '-'; *p++ = '-'; *p++ = ' ';
|
||||
*p++ = optopt;
|
||||
*p++ = '\n';
|
||||
write(2, buf, p - buf);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <stdio.h>
|
||||
static void printerr(char *const *argv, const char *msg) {
|
||||
if (opterr)
|
||||
fprintf(stderr, "%s: %s -- %c\n", argv[0], msg, optopt);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
GETOPT_CLASS int getopt(int argc, char *const *argv, const char *opts) {
|
||||
char *p;
|
||||
|
||||
optarg = 0;
|
||||
if (*opts == '+') /* GNU extension (permutation) - isn't supported */
|
||||
++opts;
|
||||
|
||||
if (!optind) { /* a way to reset things */
|
||||
nextc = 0;
|
||||
optind = 1;
|
||||
}
|
||||
|
||||
if (!nextc || !*nextc) { /* advance to the next argv element */
|
||||
/* done scanning? */
|
||||
if (optind >= argc)
|
||||
return -1;
|
||||
/* not an optional argument */
|
||||
if (argv[optind][0] != '-')
|
||||
return -1;
|
||||
/* bare `-' */
|
||||
if (argv[optind][1] == '\0')
|
||||
return -1;
|
||||
/* special case `--' argument */
|
||||
if (argv[optind][1] == '-' && argv[optind][2] == '\0') {
|
||||
++optind;
|
||||
return -1;
|
||||
}
|
||||
nextc = argv[optind] + 1;
|
||||
}
|
||||
|
||||
optopt = *nextc++;
|
||||
if (!*nextc)
|
||||
++optind;
|
||||
p = strchr(opts, optopt);
|
||||
if (!p || optopt == ':') {
|
||||
printerr(argv, "illegal option");
|
||||
return '?';
|
||||
}
|
||||
if (p[1] == ':') {
|
||||
if (*nextc) {
|
||||
optarg = nextc;
|
||||
nextc = NULL;
|
||||
++optind;
|
||||
}
|
||||
else if (p[2] != ':') { /* required argument */
|
||||
if (optind >= argc) {
|
||||
printerr(argv, "option requires an argument");
|
||||
return *opts == ':' ? ':' : '?';
|
||||
}
|
||||
else
|
||||
optarg = argv[optind++];
|
||||
}
|
||||
}
|
||||
return optopt;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int c;
|
||||
while((c = getopt(argc, argv, "ab:c::")) != -1) switch(c) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
printf("option %c %s\n", c, optarg ? optarg : "(none)");
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
for(c = optind; c < argc; ++c)
|
||||
printf("non-opt: %s\n", argv[c]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
327
3rdparty/udns/inet_XtoX.c
vendored
Normal file
327
3rdparty/udns/inet_XtoX.c
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
/* inet_XtoX.c
|
||||
* Simple implementation of the following functions:
|
||||
* inet_ntop(), inet_ntoa(), inet_pton(), inet_aton().
|
||||
*
|
||||
* Differences from traditional implementaitons:
|
||||
* o modifies destination buffers even on error return.
|
||||
* o no fancy (hex, or 1.2) input support in inet_aton()
|
||||
* o inet_aton() does not accept junk after an IP address.
|
||||
* o inet_ntop(AF_INET) requires at least 16 bytes in dest,
|
||||
* and inet_ntop(AF_INET6) at least 40 bytes
|
||||
* (traditional inet_ntop() will try to fit anyway)
|
||||
*
|
||||
* Compile with -Dinet_XtoX_prefix=pfx_ to have pfx_*() instead of inet_*()
|
||||
* Compile with -Dinet_XtoX_no_ntop or -Dinet_XtoX_no_pton
|
||||
* to disable net2str or str2net conversions.
|
||||
*
|
||||
* #define inet_XtoX_prototypes and #include "this_file.c"
|
||||
* to get function prototypes only (but not for inet_ntoa()).
|
||||
* #define inet_XtoX_decl to be `static' for static visibility,
|
||||
* or use __declspec(dllexport) or somesuch...
|
||||
*
|
||||
* Compile with -DTEST to test against stock implementation.
|
||||
*
|
||||
* Written by Michael Tokarev. Public domain.
|
||||
*/
|
||||
|
||||
#ifdef inet_XtoX_prototypes
|
||||
|
||||
struct in_addr;
|
||||
|
||||
#else
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <unistd.h>
|
||||
# include <string.h>
|
||||
# undef inet_XtoX_prefix
|
||||
# define inet_XtoX_prefix mjt_inet_
|
||||
# undef inet_XtoX_no_ntop
|
||||
# undef inet_XtoX_no_pton
|
||||
|
||||
#else /* !TEST */
|
||||
|
||||
struct in_addr { /* declare it here to avoid messing with headers */
|
||||
unsigned char x[4];
|
||||
};
|
||||
|
||||
#endif /* TEST */
|
||||
|
||||
#endif /* inet_XtoX_prototypes */
|
||||
|
||||
#ifndef inet_XtoX_prefix
|
||||
# define inet_XtoX_prefix inet_
|
||||
#endif
|
||||
#ifndef inet_XtoX_decl
|
||||
# define inet_XtoX_decl /*empty*/
|
||||
#endif
|
||||
|
||||
#define cc2_(x,y) cc2__(x,y)
|
||||
#define cc2__(x,y) x##y
|
||||
#define fn(x) cc2_(inet_XtoX_prefix,x)
|
||||
|
||||
#ifndef inet_XtoX_no_ntop
|
||||
|
||||
inet_XtoX_decl const char *
|
||||
fn(ntop)(int af, const void *src, char *dst, unsigned size);
|
||||
|
||||
#ifndef inet_XtoX_prototypes
|
||||
|
||||
static int mjt_ntop4(const void *_src, char *dst, int size) {
|
||||
unsigned i, x, r;
|
||||
char *p;
|
||||
const unsigned char *s = _src;
|
||||
if (size < 4*4) /* for simplicity, disallow non-max-size buffer */
|
||||
return 0;
|
||||
for (i = 0, p = dst; i < 4; ++i) {
|
||||
if (i) *p++ = '.';
|
||||
x = r = s[i];
|
||||
if (x > 99) { *p++ = (char)(r / 100 + '0'); r %= 100; }
|
||||
if (x > 9) { *p++ = (char)(r / 10 + '0'); r %= 10; }
|
||||
*p++ = (char)(r + '0');
|
||||
}
|
||||
*p = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *hexc(char *p, unsigned x) {
|
||||
static char hex[16] = "0123456789abcdef";
|
||||
if (x > 0x0fff) *p++ = hex[(x >>12) & 15];
|
||||
if (x > 0x00ff) *p++ = hex[(x >> 8) & 15];
|
||||
if (x > 0x000f) *p++ = hex[(x >> 4) & 15];
|
||||
*p++ = hex[x & 15];
|
||||
return p;
|
||||
}
|
||||
|
||||
static int mjt_ntop6(const void *_src, char *dst, int size) {
|
||||
unsigned i;
|
||||
unsigned short w[8];
|
||||
unsigned bs = 0, cs = 0;
|
||||
unsigned bl = 0, cl = 0;
|
||||
char *p;
|
||||
const unsigned char *s = _src;
|
||||
|
||||
if (size < 40) /* for simplicity, disallow non-max-size buffer */
|
||||
return 0;
|
||||
|
||||
for(i = 0; i < 8; ++i, s += 2) {
|
||||
w[i] = (((unsigned short)(s[0])) << 8) | s[1];
|
||||
if (!w[i]) {
|
||||
if (!cl++) cs = i;
|
||||
}
|
||||
else {
|
||||
if (cl > bl) bl = cl, bs = cs;
|
||||
}
|
||||
}
|
||||
if (cl > bl) bl = cl, bs = cs;
|
||||
p = dst;
|
||||
if (bl == 1)
|
||||
bl = 0;
|
||||
if (bl) {
|
||||
for(i = 0; i < bs; ++i) {
|
||||
if (i) *p++ = ':';
|
||||
p = hexc(p, w[i]);
|
||||
}
|
||||
*p++ = ':';
|
||||
i += bl;
|
||||
if (i == 8)
|
||||
*p++ = ':';
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
for(; i < 8; ++i) {
|
||||
if (i) *p++ = ':';
|
||||
if (i == 6 && !bs && (bl == 6 || (bl == 5 && w[5] == 0xffff)))
|
||||
return mjt_ntop4(s - 4, p, size - (p - dst));
|
||||
p = hexc(p, w[i]);
|
||||
}
|
||||
*p = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
inet_XtoX_decl const char *
|
||||
fn(ntop)(int af, const void *src, char *dst, unsigned size) {
|
||||
switch(af) {
|
||||
/* don't use AF_*: don't mess with headers */
|
||||
case 2: /* AF_INET */ if (mjt_ntop4(src, dst, size)) return dst; break;
|
||||
case 10: /* AF_INET6 */ if (mjt_ntop6(src, dst, size)) return dst; break;
|
||||
default: errno = EAFNOSUPPORT; return (char*)0;
|
||||
}
|
||||
errno = ENOSPC;
|
||||
return (char*)0;
|
||||
}
|
||||
|
||||
inet_XtoX_decl const char *
|
||||
fn(ntoa)(struct in_addr addr) {
|
||||
static char buf[4*4];
|
||||
mjt_ntop4(&addr, buf, sizeof(buf));
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* inet_XtoX_prototypes */
|
||||
#endif /* inet_XtoX_no_ntop */
|
||||
|
||||
#ifndef inet_XtoX_no_pton
|
||||
|
||||
inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst);
|
||||
inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr);
|
||||
|
||||
#ifndef inet_XtoX_prototypes
|
||||
|
||||
static int mjt_pton4(const char *c, void *dst) {
|
||||
unsigned char *a = dst;
|
||||
unsigned n, o;
|
||||
for (n = 0; n < 4; ++n) {
|
||||
if (*c < '0' || *c > '9')
|
||||
return 0;
|
||||
o = *c++ - '0';
|
||||
while(*c >= '0' && *c <= '9')
|
||||
if ((o = o * 10 + (*c++ - '0')) > 255)
|
||||
return 0;
|
||||
if (*c++ != (n == 3 ? '\0' : '.'))
|
||||
return 0;
|
||||
*a++ = (unsigned char)o;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mjt_pton6(const char *c, void *dst) {
|
||||
unsigned short w[8], *a = w, *z, *i;
|
||||
unsigned v, o;
|
||||
const char *sc;
|
||||
unsigned char *d = dst;
|
||||
if (*c != ':') z = (unsigned short*)0;
|
||||
else if (*++c != ':') return 0;
|
||||
else ++c, z = a;
|
||||
i = 0;
|
||||
for(;;) {
|
||||
v = 0;
|
||||
sc = c;
|
||||
for(;;) {
|
||||
if (*c >= '0' && *c <= '9') o = *c - '0';
|
||||
else if (*c >= 'a' && *c <= 'f') o = *c - 'a' + 10;
|
||||
else if (*c >= 'A' && *c <= 'F') o = *c - 'A' + 10;
|
||||
else break;
|
||||
v = (v << 4) | o;
|
||||
if (v > 0xffff) return 0;
|
||||
++c;
|
||||
}
|
||||
if (sc == c) {
|
||||
if (z == a && !*c)
|
||||
break;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (*c == ':') {
|
||||
if (a >= w + 8)
|
||||
return 0;
|
||||
*a++ = v;
|
||||
if (*++c == ':') {
|
||||
if (z)
|
||||
return 0;
|
||||
z = a;
|
||||
if (!*++c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!*c) {
|
||||
if (a >= w + 8)
|
||||
return 0;
|
||||
*a++ = v;
|
||||
break;
|
||||
}
|
||||
else if (*c == '.') {
|
||||
if (a > w + 6)
|
||||
return 0;
|
||||
if (!mjt_pton4(sc, d))
|
||||
return 0;
|
||||
*a++ = ((unsigned)(d[0]) << 8) | d[1];
|
||||
*a++ = ((unsigned)(d[2]) << 8) | d[3];
|
||||
break;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
v = w + 8 - a;
|
||||
if ((v && !z) || (!v && z))
|
||||
return 0;
|
||||
for(i = w; ; ++i) {
|
||||
if (i == z)
|
||||
while(v--) { *d++ = '\0'; *d++ = '\0'; }
|
||||
if (i >= a)
|
||||
break;
|
||||
*d++ = (unsigned char)((*i >> 8) & 255);
|
||||
*d++ = (unsigned char)(*i & 255);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst) {
|
||||
switch(af) {
|
||||
/* don't use AF_*: don't mess with headers */
|
||||
case 2 /* AF_INET */: return mjt_pton4(src, dst);
|
||||
case 10 /* AF_INET6 */: return mjt_pton6(src, dst);
|
||||
default: errno = EAFNOSUPPORT; return -1;
|
||||
}
|
||||
}
|
||||
|
||||
inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr) {
|
||||
return mjt_pton4(src, addr);
|
||||
}
|
||||
|
||||
#endif /* inet_XtoX_prototypes */
|
||||
|
||||
#endif /* inet_XtoX_no_pton */
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
char n0[16], n1[16];
|
||||
char p0[64], p1[64];
|
||||
int af = AF_INET;
|
||||
int pl = sizeof(p0);
|
||||
int r0, r1;
|
||||
const char *s0, *s1;
|
||||
|
||||
while((i = getopt(argc, argv, "46a:p:")) != EOF) switch(i) {
|
||||
case '4': af = AF_INET; break;
|
||||
case '6': af = AF_INET6; break;
|
||||
case 'a': case 'p': pl = atoi(optarg); break;
|
||||
default: return 1;
|
||||
}
|
||||
for(i = optind; i < argc; ++i) {
|
||||
char *a = argv[i];
|
||||
|
||||
printf("%s:\n", a);
|
||||
r0 = inet_pton(af, a, n0);
|
||||
printf(" p2n stock: %s\n",
|
||||
(r0 < 0 ? "(notsupp)" : !r0 ? "(inval)" : fn(ntop)(af,n0,p0,sizeof(p0))));
|
||||
r1 = fn(pton)(af, a, n1);
|
||||
printf(" p2n this : %s\n",
|
||||
(r1 < 0 ? "(notsupp)" : !r1 ? "(inval)" : fn(ntop)(af,n1,p1,sizeof(p1))));
|
||||
|
||||
if ((r0 > 0) != (r1 > 0) ||
|
||||
(r0 > 0 && r1 > 0 && memcmp(n0, n1, af == AF_INET ? 4 : 16) != 0))
|
||||
printf(" DIFFER!\n");
|
||||
|
||||
s0 = inet_ntop(af, n1, p0, pl);
|
||||
printf(" n2p stock: %s\n", s0 ? s0 : "(inval)");
|
||||
s1 = fn(ntop)(af, n1, p1, pl);
|
||||
printf(" n2p this : %s\n", s1 ? s1 : "(inval)");
|
||||
if ((s0 != 0) != (s1 != 0) ||
|
||||
(s0 && s1 && strcmp(s0, s1) != 0))
|
||||
printf(" DIFFER!\n");
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
||||
151
3rdparty/udns/rblcheck.1
vendored
Normal file
151
3rdparty/udns/rblcheck.1
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
.\" rblcheck.1
|
||||
.\" rblckeck manpage
|
||||
.\"
|
||||
.\" Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
.\" This file is part of UDNS library, an async DNS stub resolver.
|
||||
.\"
|
||||
.\" This library is free software; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU Lesser General Public
|
||||
.\" License as published by the Free Software Foundation; either
|
||||
.\" version 2.1 of the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" This library 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. See the GNU
|
||||
.\" Lesser General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU Lesser General Public
|
||||
.\" License along with this library, in file named COPYING.LGPL; if not,
|
||||
.\" write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
.\" Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
.TH rblckeck 1 "Apr 2005" "User Utilities"
|
||||
|
||||
.SH NAME
|
||||
rblckeck \- DNSBL lookup utility
|
||||
|
||||
.SH SYNOPSYS
|
||||
.B rblcheck
|
||||
.RB [\| \-s
|
||||
.IR zone \|]
|
||||
.RB [\| \-S
|
||||
.IR zone\-file \|]
|
||||
.RB [\| \-c \|]
|
||||
.RB [\| \-tmvq \|]
|
||||
.RB [\| \-n
|
||||
.IR nsaddr \|]
|
||||
.IR address \|.\|.\|.
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B rblcheck
|
||||
is a simple command-line to perform DNSBL (DNS-based blocklists) lookups.
|
||||
For every IP address (or a name, in which case it will be resolved to an
|
||||
address first), the utility verifies whenever it is listed in a (list of)
|
||||
DNS blocklists specified with
|
||||
.B \-s
|
||||
or
|
||||
.B \-S
|
||||
options, optionally obtains text assotiated with the listing (usually it
|
||||
is either some description about the reason of the listing or an URL
|
||||
referring to such a description), and displays results on standard output.
|
||||
.PP
|
||||
The program is implemented on top of
|
||||
.BR udns (3)
|
||||
library.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
The following options are recognized by
|
||||
.BR rblcheck :
|
||||
|
||||
.TP
|
||||
.B \-s \fIzone\fR
|
||||
add the given \fIzone\fR DNSBL name to the list of active zones.
|
||||
.TP
|
||||
.B \-S \fIzone-file\fR
|
||||
add list of zones from the named \fIzone-file\fR to the list of
|
||||
active zones (the file specifies one zone as the first word on a
|
||||
line, empty lines and lines starting with `#' character are ignored).
|
||||
.TP
|
||||
.B \-c
|
||||
reset active zone list.
|
||||
.TP
|
||||
.B \-v
|
||||
be more verbose, produce more detailed output.
|
||||
.TP
|
||||
.B \-q
|
||||
the opposite for \fB\-v\fR -- produce less detailed output.
|
||||
.TP
|
||||
.B \-t
|
||||
obtain text for listed addresses.
|
||||
.TP
|
||||
.B \-n \fInsaddr\fR
|
||||
Use the given nameserver (given as IPv4 or IPv6 address) instead of the
|
||||
default. The same effect may be achieved by setting $NSCACHEIP environment
|
||||
variable.
|
||||
.TP
|
||||
.B \-m
|
||||
stop after first hit, ie after the first address which is found to be
|
||||
listed.
|
||||
|
||||
.TP
|
||||
.B \-h
|
||||
print short help and exit.
|
||||
|
||||
.PP
|
||||
If no
|
||||
.BR \-s ,
|
||||
.BR \-S
|
||||
and
|
||||
.B \-c
|
||||
options are given,
|
||||
.B rblcheck
|
||||
will try to obtain list of zones using $RBLCHECK_ZONES environment variable,
|
||||
or ~/.rblcheckrc, or /etc/rblckechrc files, in that order. If no zones are
|
||||
found, it will exit unsuccessefully.
|
||||
|
||||
.SH "RETURN VALUE"
|
||||
When no addresses given are listed and no errors occured,
|
||||
.B rblcheck
|
||||
exits with code 0. If at least one address is listed,
|
||||
.B rblcheck
|
||||
returns 100. In case of DNS errors,
|
||||
.B rblcheck
|
||||
returns 2.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
|
||||
.TP
|
||||
.B $RBLCHECK_ZONES
|
||||
if no
|
||||
.BR \-s ,
|
||||
.B \-S
|
||||
or
|
||||
.B \-c
|
||||
option is given,
|
||||
.B rblcheck
|
||||
tries this variable to obtain list of DNSBL zones to check against.
|
||||
|
||||
.SH FILES
|
||||
|
||||
.TP
|
||||
$HOME/.rblcheckrc and /etc/rblcheckrc
|
||||
if no
|
||||
.BR \-s ,
|
||||
.B \-S
|
||||
or
|
||||
.B \-c
|
||||
option is given, and no $RBLCHECK_ZONES environment variable is set,
|
||||
.B rblcheck
|
||||
will try the two files (the first one that exists) to obtain list of
|
||||
DNSBL zones to check against.
|
||||
Each line specifies one zone (only first word in each line is used).
|
||||
Empty lines and lines starting with `#' character are ignored.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR dnsget (1)
|
||||
.BR resolv.conf (5)
|
||||
.BR udns (3).
|
||||
|
||||
.SH AUTHOR
|
||||
This program and manual pages are written by Michael Tokarev.
|
||||
378
3rdparty/udns/rblcheck.c
vendored
Normal file
378
3rdparty/udns/rblcheck.c
vendored
Normal file
@@ -0,0 +1,378 @@
|
||||
/* rblcheck.c
|
||||
dnsbl (rbl) checker application
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef WINDOWS
|
||||
# include <winsock2.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include "udns.h"
|
||||
|
||||
#ifndef HAVE_GETOPT
|
||||
# include "getopt.c"
|
||||
#endif
|
||||
|
||||
static const char *version = "udns-rblcheck 0.4";
|
||||
static char *progname;
|
||||
|
||||
static void error(int die, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
fprintf(stderr, "%s: ", progname);
|
||||
va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);
|
||||
putc('\n', stderr);
|
||||
fflush(stderr);
|
||||
if (die)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct rblookup {
|
||||
struct ipcheck *parent;
|
||||
struct in_addr key;
|
||||
const char *zone;
|
||||
struct dns_rr_a4 *addr;
|
||||
struct dns_rr_txt *txt;
|
||||
};
|
||||
|
||||
struct ipcheck {
|
||||
const char *name;
|
||||
int naddr;
|
||||
int listed;
|
||||
struct rblookup *lookup;
|
||||
};
|
||||
|
||||
#define notlisted ((void*)1)
|
||||
|
||||
static int nzones, nzalloc;
|
||||
static const char **zones;
|
||||
|
||||
static int do_txt;
|
||||
static int stopfirst;
|
||||
static int verbose = 1;
|
||||
/* verbosity level:
|
||||
* <0 - only bare As/TXTs
|
||||
* 0 - what RBL result
|
||||
* 1(default) - what is listed by RBL: result
|
||||
* 2 - what is[not ]listed by RBL: result, name lookups
|
||||
*/
|
||||
|
||||
static int listed;
|
||||
static int failures;
|
||||
|
||||
static void *ecalloc(int size, int cnt) {
|
||||
void *t = calloc(size, cnt);
|
||||
if (!t)
|
||||
error(1, "out of memory");
|
||||
return t;
|
||||
}
|
||||
|
||||
static void addzone(const char *zone) {
|
||||
if (nzones >= nzalloc) {
|
||||
const char **zs = (const char**)ecalloc(sizeof(char*), (nzalloc += 16));
|
||||
if (zones) {
|
||||
memcpy(zs, zones, nzones * sizeof(char*));
|
||||
free(zones);
|
||||
}
|
||||
zones = zs;
|
||||
}
|
||||
zones[nzones++] = zone;
|
||||
}
|
||||
|
||||
static int addzonefile(const char *fname) {
|
||||
FILE *f = fopen(fname, "r");
|
||||
char linebuf[2048];
|
||||
if (!f)
|
||||
return 0;
|
||||
while(fgets(linebuf, sizeof(linebuf), f)) {
|
||||
char *p = linebuf, *e;
|
||||
while(*p == ' ' || *p == '\t') ++p;
|
||||
if (*p == '#' || *p == '\n') continue;
|
||||
e = p;
|
||||
while(*e && *e != ' ' && *e != '\t' && *e != '\n')
|
||||
++e;
|
||||
*e++ = '\0';
|
||||
p = memcpy(ecalloc(e - p, 1), p, e - p); // strdup
|
||||
addzone(p);
|
||||
}
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dnserror(struct rblookup *ipl, const char *what) {
|
||||
char buf[4*4];
|
||||
error(0, "unable to %s for %s (%s): %s",
|
||||
what, dns_ntop(AF_INET, &ipl->key, buf, sizeof(buf)),
|
||||
ipl->zone, dns_strerror(dns_status(0)));
|
||||
++failures;
|
||||
}
|
||||
|
||||
static void display_result(struct ipcheck *ipc) {
|
||||
int j;
|
||||
struct rblookup *l, *le;
|
||||
char buf[4*4];
|
||||
if (!ipc->naddr) return;
|
||||
for (l = ipc->lookup, le = l + nzones * ipc->naddr; l < le; ++l) {
|
||||
if (!l->addr) continue;
|
||||
if (verbose < 2 && l->addr == notlisted) continue;
|
||||
if (verbose >= 0) {
|
||||
dns_ntop(AF_INET, &l->key, buf, sizeof(buf));
|
||||
if (ipc->name) printf("%s[%s]", ipc->name, buf);
|
||||
else printf("%s", buf);
|
||||
}
|
||||
if (l->addr == notlisted) {
|
||||
printf(" is NOT listed by %s\n", l->zone);
|
||||
continue;
|
||||
}
|
||||
else if (verbose >= 1)
|
||||
printf(" is listed by %s: ", l->zone);
|
||||
else if (verbose >= 0)
|
||||
printf(" %s ", l->zone);
|
||||
if (verbose >= 1 || !do_txt)
|
||||
for (j = 0; j < l->addr->dnsa4_nrr; ++j)
|
||||
printf("%s%s", j ? " " : "",
|
||||
dns_ntop(AF_INET, &l->addr->dnsa4_addr[j], buf, sizeof(buf)));
|
||||
if (!do_txt) ;
|
||||
else if (l->txt) {
|
||||
for(j = 0; j < l->txt->dnstxt_nrr; ++j) {
|
||||
unsigned char *t = l->txt->dnstxt_txt[j].txt;
|
||||
unsigned char *e = t + l->txt->dnstxt_txt[j].len;
|
||||
printf("%s\"", verbose > 0 ? "\n\t" : j ? " " : "");
|
||||
while(t < e) {
|
||||
if (*t < ' ' || *t >= 127) printf("\\x%02x", *t);
|
||||
else if (*t == '\\' || *t == '"') printf("\\%c", *t);
|
||||
else putchar(*t);
|
||||
++t;
|
||||
}
|
||||
putchar('"');
|
||||
}
|
||||
free(l->txt);
|
||||
}
|
||||
else
|
||||
printf("%s<no text available>", verbose > 0 ? "\n\t" : "");
|
||||
free(l->addr);
|
||||
putchar('\n');
|
||||
}
|
||||
free(ipc->lookup);
|
||||
}
|
||||
|
||||
static void txtcb(struct dns_ctx *ctx, struct dns_rr_txt *r, void *data) {
|
||||
struct rblookup *ipl = data;
|
||||
if (r) {
|
||||
ipl->txt = r;
|
||||
++ipl->parent->listed;
|
||||
}
|
||||
else if (dns_status(ctx) != DNS_E_NXDOMAIN)
|
||||
dnserror(ipl, "lookup DNSBL TXT record");
|
||||
}
|
||||
|
||||
static void a4cb(struct dns_ctx *ctx, struct dns_rr_a4 *r, void *data) {
|
||||
struct rblookup *ipl = data;
|
||||
if (r) {
|
||||
ipl->addr = r;
|
||||
++listed;
|
||||
if (do_txt) {
|
||||
if (dns_submit_a4dnsbl_txt(0, &ipl->key, ipl->zone, txtcb, ipl))
|
||||
return;
|
||||
dnserror(ipl, "submit DNSBL TXT record");
|
||||
}
|
||||
++ipl->parent->listed;
|
||||
}
|
||||
else if (dns_status(ctx) != DNS_E_NXDOMAIN)
|
||||
dnserror(ipl, "lookup DNSBL A record");
|
||||
else
|
||||
ipl->addr = notlisted;
|
||||
}
|
||||
|
||||
static int
|
||||
submit_a_queries(struct ipcheck *ipc,
|
||||
int naddr, const struct in_addr *addr) {
|
||||
int z, a;
|
||||
struct rblookup *rl = ecalloc(sizeof(*rl), nzones * naddr);
|
||||
ipc->lookup = rl;
|
||||
ipc->naddr = naddr;
|
||||
for(a = 0; a < naddr; ++a) {
|
||||
for(z = 0; z < nzones; ++z) {
|
||||
rl->key = addr[a];
|
||||
rl->zone = zones[z];
|
||||
rl->parent = ipc;
|
||||
if (!dns_submit_a4dnsbl(0, &rl->key, rl->zone, a4cb, rl))
|
||||
dnserror(rl, "submit DNSBL A query");
|
||||
++rl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void namecb(struct dns_ctx *ctx, struct dns_rr_a4 *rr, void *data) {
|
||||
struct ipcheck *ipc = data;
|
||||
if (rr) {
|
||||
submit_a_queries(ipc, rr->dnsa4_nrr, rr->dnsa4_addr);
|
||||
free(rr);
|
||||
}
|
||||
else {
|
||||
error(0, "unable to lookup `%s': %s",
|
||||
ipc->name, dns_strerror(dns_status(ctx)));
|
||||
++failures;
|
||||
}
|
||||
}
|
||||
|
||||
static int submit(struct ipcheck *ipc) {
|
||||
struct in_addr addr;
|
||||
if (dns_pton(AF_INET, ipc->name, &addr) > 0) {
|
||||
submit_a_queries(ipc, 1, &addr);
|
||||
ipc->name = NULL;
|
||||
}
|
||||
else if (!dns_submit_a4(0, ipc->name, 0, namecb, ipc)) {
|
||||
error(0, "unable to submit name query for %s: %s\n",
|
||||
ipc->name, dns_strerror(dns_status(0)));
|
||||
++failures;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void waitdns(struct ipcheck *ipc) {
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
int c;
|
||||
int fd = dns_sock(NULL);
|
||||
time_t now = 0;
|
||||
FD_ZERO(&fds);
|
||||
while((c = dns_timeouts(NULL, -1, now)) > 0) {
|
||||
FD_SET(fd, &fds);
|
||||
tv.tv_sec = c;
|
||||
tv.tv_usec = 0;
|
||||
c = select(fd+1, &fds, NULL, NULL, &tv);
|
||||
now = time(NULL);
|
||||
if (c > 0)
|
||||
dns_ioevent(NULL, now);
|
||||
if (stopfirst && ipc->listed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int c;
|
||||
struct ipcheck ipc;
|
||||
char *nameserver = NULL;
|
||||
int zgiven = 0;
|
||||
|
||||
if (!(progname = strrchr(argv[0], '/'))) progname = argv[0];
|
||||
else argv[0] = ++progname;
|
||||
|
||||
while((c = getopt(argc, argv, "hqtvms:S:cn:")) != EOF) switch(c) {
|
||||
case 's': ++zgiven; addzone(optarg); break;
|
||||
case 'S':
|
||||
++zgiven;
|
||||
if (addzonefile(optarg)) break;
|
||||
error(1, "unable to read zonefile `%s'", optarg);
|
||||
case 'c': ++zgiven; nzones = 0; break;
|
||||
case 'q': --verbose; break;
|
||||
case 'v': ++verbose; break;
|
||||
case 't': do_txt = 1; break;
|
||||
case 'n': nameserver = optarg; break;
|
||||
case 'm': ++stopfirst; break;
|
||||
case 'h':
|
||||
printf("%s: %s (udns library version %s).\n",
|
||||
progname, version, dns_version());
|
||||
printf("Usage is: %s [options] address..\n", progname);
|
||||
printf(
|
||||
"Where options are:\n"
|
||||
" -h - print this help and exit\n"
|
||||
" -s service - add the service (DNSBL zone) to the serice list\n"
|
||||
" -S service-file - add the DNSBL zone(s) read from the given file\n"
|
||||
" -c - clear service list\n"
|
||||
" -v - increase verbosity level (more -vs => more verbose)\n"
|
||||
" -q - decrease verbosity level (opposite of -v)\n"
|
||||
" -t - obtain and print TXT records if any\n"
|
||||
" -m - stop checking after first address match in any list\n"
|
||||
" -n ipaddr - use the given nameserver instead of the default\n"
|
||||
"(if no -s or -S option is given, use $RBLCHECK_ZONES, ~/.rblcheckrc\n"
|
||||
"or /etc/rblcheckrc in that order)\n"
|
||||
);
|
||||
return 0;
|
||||
default:
|
||||
error(1, "use `%s -h' for help", progname);
|
||||
}
|
||||
|
||||
if (!zgiven) {
|
||||
char *s = getenv("RBLCHECK_ZONES");
|
||||
if (s) {
|
||||
char *k;
|
||||
s = strdup(s);
|
||||
for(k = strtok(s, " \t"); k; k = strtok(NULL, " \t"))
|
||||
addzone(k);
|
||||
free(s);
|
||||
}
|
||||
else { /* probably worthless on windows? */
|
||||
char *path;
|
||||
char *home = getenv("HOME");
|
||||
if (!home) home = ".";
|
||||
path = malloc(strlen(home) + 1 + sizeof(".rblcheckrc"));
|
||||
sprintf(path, "%s/.rblcheckrc", home);
|
||||
if (!addzonefile(path))
|
||||
addzonefile("/etc/rblcheckrc");
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
if (!nzones)
|
||||
error(1, "no service (zone) list specified (-s or -S option)");
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (!argc)
|
||||
return 0;
|
||||
|
||||
if (dns_init(NULL, 0) < 0)
|
||||
error(1, "unable to initialize DNS library: %s", strerror(errno));
|
||||
if (nameserver) {
|
||||
dns_add_serv(NULL, NULL);
|
||||
if (dns_add_serv(NULL, nameserver) < 0)
|
||||
error(1, "wrong IP address for a nameserver: `%s'", nameserver);
|
||||
}
|
||||
if (dns_open(NULL) < 0)
|
||||
error(1, "unable to initialize DNS library: %s", strerror(errno));
|
||||
|
||||
for (c = 0; c < argc; ++c) {
|
||||
if (c && (verbose > 1 || (verbose == 1 && do_txt))) putchar('\n');
|
||||
memset(&ipc, 0, sizeof(ipc));
|
||||
ipc.name = argv[c];
|
||||
submit(&ipc);
|
||||
waitdns(&ipc);
|
||||
display_result(&ipc);
|
||||
if (stopfirst > 1 && listed) break;
|
||||
}
|
||||
|
||||
return listed ? 100 : failures ? 2 : 0;
|
||||
}
|
||||
1352
3rdparty/udns/udns.3
vendored
Normal file
1352
3rdparty/udns/udns.3
vendored
Normal file
File diff suppressed because it is too large
Load Diff
778
3rdparty/udns/udns.h
vendored
Normal file
778
3rdparty/udns/udns.h
vendored
Normal file
@@ -0,0 +1,778 @@
|
||||
/* udns.h
|
||||
header file for the UDNS library.
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef UDNS_VERSION /* include guard */
|
||||
|
||||
#define UDNS_VERSION "0.4"
|
||||
|
||||
#ifdef WINDOWS
|
||||
# ifdef UDNS_DYNAMIC_LIBRARY
|
||||
# ifdef DNS_LIBRARY_BUILD
|
||||
# define UDNS_API __declspec(dllexport)
|
||||
# define UDNS_DATA_API __declspec(dllexport)
|
||||
# else
|
||||
# define UDNS_API __declspec(dllimport)
|
||||
# define UDNS_DATA_API __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef UDNS_API
|
||||
# define UDNS_API
|
||||
#endif
|
||||
#ifndef UDNS_DATA_API
|
||||
# define UDNS_DATA_API
|
||||
#endif
|
||||
|
||||
#include <sys/types.h> /* for time_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* forward declarations if sockets stuff isn't #include'd */
|
||||
struct in_addr;
|
||||
struct in6_addr;
|
||||
struct sockaddr;
|
||||
|
||||
/**************************************************************************/
|
||||
/**************** Common definitions **************************************/
|
||||
|
||||
UDNS_API const char *
|
||||
dns_version(void);
|
||||
|
||||
struct dns_ctx;
|
||||
struct dns_query;
|
||||
|
||||
/* shorthand for [const] unsigned char */
|
||||
typedef unsigned char dnsc_t;
|
||||
typedef const unsigned char dnscc_t;
|
||||
|
||||
#define DNS_MAXDN 255 /* max DN length */
|
||||
#define DNS_DNPAD 1 /* padding for DN buffers */
|
||||
#define DNS_MAXLABEL 63 /* max DN label length */
|
||||
#define DNS_MAXNAME 1024 /* max asciiz domain name length */
|
||||
#define DNS_HSIZE 12 /* DNS packet header size */
|
||||
#define DNS_PORT 53 /* default domain port */
|
||||
#define DNS_MAXSERV 6 /* max servers to consult */
|
||||
#define DNS_MAXPACKET 512 /* max traditional-DNS UDP packet size */
|
||||
#define DNS_EDNS0PACKET 4096 /* EDNS0 packet size to use */
|
||||
|
||||
enum dns_class { /* DNS RR Classes */
|
||||
DNS_C_INVALID = 0, /* invalid class */
|
||||
DNS_C_IN = 1, /* Internet */
|
||||
DNS_C_CH = 3, /* CHAOS */
|
||||
DNS_C_HS = 4, /* HESIOD */
|
||||
DNS_C_ANY = 255 /* wildcard */
|
||||
};
|
||||
|
||||
enum dns_type { /* DNS RR Types */
|
||||
DNS_T_INVALID = 0, /* Cookie. */
|
||||
DNS_T_A = 1, /* Host address. */
|
||||
DNS_T_NS = 2, /* Authoritative server. */
|
||||
DNS_T_MD = 3, /* Mail destination. */
|
||||
DNS_T_MF = 4, /* Mail forwarder. */
|
||||
DNS_T_CNAME = 5, /* Canonical name. */
|
||||
DNS_T_SOA = 6, /* Start of authority zone. */
|
||||
DNS_T_MB = 7, /* Mailbox domain name. */
|
||||
DNS_T_MG = 8, /* Mail group member. */
|
||||
DNS_T_MR = 9, /* Mail rename name. */
|
||||
DNS_T_NULL = 10, /* Null resource record. */
|
||||
DNS_T_WKS = 11, /* Well known service. */
|
||||
DNS_T_PTR = 12, /* Domain name pointer. */
|
||||
DNS_T_HINFO = 13, /* Host information. */
|
||||
DNS_T_MINFO = 14, /* Mailbox information. */
|
||||
DNS_T_MX = 15, /* Mail routing information. */
|
||||
DNS_T_TXT = 16, /* Text strings. */
|
||||
DNS_T_RP = 17, /* Responsible person. */
|
||||
DNS_T_AFSDB = 18, /* AFS cell database. */
|
||||
DNS_T_X25 = 19, /* X_25 calling address. */
|
||||
DNS_T_ISDN = 20, /* ISDN calling address. */
|
||||
DNS_T_RT = 21, /* Router. */
|
||||
DNS_T_NSAP = 22, /* NSAP address. */
|
||||
DNS_T_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */
|
||||
DNS_T_SIG = 24, /* Security signature. */
|
||||
DNS_T_KEY = 25, /* Security key. */
|
||||
DNS_T_PX = 26, /* X.400 mail mapping. */
|
||||
DNS_T_GPOS = 27, /* Geographical position (withdrawn). */
|
||||
DNS_T_AAAA = 28, /* Ip6 Address. */
|
||||
DNS_T_LOC = 29, /* Location Information. */
|
||||
DNS_T_NXT = 30, /* Next domain (security). */
|
||||
DNS_T_EID = 31, /* Endpoint identifier. */
|
||||
DNS_T_NIMLOC = 32, /* Nimrod Locator. */
|
||||
DNS_T_SRV = 33, /* Server Selection. */
|
||||
DNS_T_ATMA = 34, /* ATM Address */
|
||||
DNS_T_NAPTR = 35, /* Naming Authority PoinTeR */
|
||||
DNS_T_KX = 36, /* Key Exchange */
|
||||
DNS_T_CERT = 37, /* Certification record */
|
||||
DNS_T_A6 = 38, /* IPv6 address (deprecates AAAA) */
|
||||
DNS_T_DNAME = 39, /* Non-terminal DNAME (for IPv6) */
|
||||
DNS_T_SINK = 40, /* Kitchen sink (experimentatl) */
|
||||
DNS_T_OPT = 41, /* EDNS0 option (meta-RR) */
|
||||
DNS_T_DS = 43, /* DNSSEC */
|
||||
DNS_T_SSHFP = 44,
|
||||
DNS_T_IPSECKEY = 45,
|
||||
DNS_T_RRSIG = 46, /* DNSSEC */
|
||||
DNS_T_NSEC = 47, /* DNSSEC */
|
||||
DNS_T_DNSKEY = 48,
|
||||
DNS_T_DHCID = 49,
|
||||
DNS_T_NSEC3 = 50,
|
||||
DNS_T_NSEC3PARAMS = 51,
|
||||
DNS_T_TALINK = 58, /* draft-ietf-dnsop-trust-history */
|
||||
DNS_T_SPF = 99,
|
||||
DNS_T_UINFO = 100,
|
||||
DNS_T_UID = 101,
|
||||
DNS_T_GID = 102,
|
||||
DNS_T_UNSPEC = 103,
|
||||
DNS_T_TSIG = 250, /* Transaction signature. */
|
||||
DNS_T_IXFR = 251, /* Incremental zone transfer. */
|
||||
DNS_T_AXFR = 252, /* Transfer zone of authority. */
|
||||
DNS_T_MAILB = 253, /* Transfer mailbox records. */
|
||||
DNS_T_MAILA = 254, /* Transfer mail agent records. */
|
||||
DNS_T_ANY = 255, /* Wildcard match. */
|
||||
DNS_T_ZXFR = 256, /* BIND-specific, nonstandard. */
|
||||
DNS_T_DLV = 32769, /* RFC 4431, 5074, DNSSEC Lookaside Validation */
|
||||
DNS_T_MAX = 65536
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/**************** Domain Names (DNs) **************************************/
|
||||
|
||||
/* return length of the DN */
|
||||
UDNS_API unsigned
|
||||
dns_dnlen(dnscc_t *dn);
|
||||
|
||||
/* return #of labels in a DN */
|
||||
UDNS_API unsigned
|
||||
dns_dnlabels(dnscc_t *dn);
|
||||
|
||||
/* lower- and uppercase single DN char */
|
||||
#define DNS_DNLC(c) ((c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 'a' : (c))
|
||||
#define DNS_DNUC(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
/* compare the DNs, return dnlen of equal or 0 if not */
|
||||
UDNS_API unsigned
|
||||
dns_dnequal(dnscc_t *dn1, dnscc_t *dn2);
|
||||
|
||||
/* copy one DN to another, size checking */
|
||||
UDNS_API unsigned
|
||||
dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz);
|
||||
|
||||
/* convert asciiz string of length namelen (0 to use strlen) to DN */
|
||||
UDNS_API int
|
||||
dns_ptodn(const char *name, unsigned namelen,
|
||||
dnsc_t *dn, unsigned dnsiz, int *isabs);
|
||||
|
||||
/* simpler form of dns_ptodn() */
|
||||
#define dns_sptodn(name,dn,dnsiz) dns_ptodn((name),0,(dn),(dnsiz),0)
|
||||
|
||||
UDNS_DATA_API extern dnscc_t dns_inaddr_arpa_dn[14];
|
||||
#define DNS_A4RSIZE 30
|
||||
UDNS_API int
|
||||
dns_a4todn(const struct in_addr *addr, dnscc_t *tdn,
|
||||
dnsc_t *dn, unsigned dnsiz);
|
||||
UDNS_API int
|
||||
dns_a4ptodn(const struct in_addr *addr, const char *tname,
|
||||
dnsc_t *dn, unsigned dnsiz);
|
||||
UDNS_API dnsc_t *
|
||||
dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne);
|
||||
|
||||
UDNS_DATA_API extern dnscc_t dns_ip6_arpa_dn[10];
|
||||
#define DNS_A6RSIZE 74
|
||||
UDNS_API int
|
||||
dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn,
|
||||
dnsc_t *dn, unsigned dnsiz);
|
||||
UDNS_API int
|
||||
dns_a6ptodn(const struct in6_addr *addr, const char *tname,
|
||||
dnsc_t *dn, unsigned dnsiz);
|
||||
UDNS_API dnsc_t *
|
||||
dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne);
|
||||
|
||||
/* convert DN into asciiz string */
|
||||
UDNS_API int
|
||||
dns_dntop(dnscc_t *dn, char *name, unsigned namesiz);
|
||||
|
||||
/* convert DN into asciiz string, using static buffer (NOT thread-safe!) */
|
||||
UDNS_API const char *
|
||||
dns_dntosp(dnscc_t *dn);
|
||||
|
||||
/* return buffer size (incl. null byte) required for asciiz form of a DN */
|
||||
UDNS_API unsigned
|
||||
dns_dntop_size(dnscc_t *dn);
|
||||
|
||||
/* either wrappers or reimplementations for inet_ntop() and inet_pton() */
|
||||
UDNS_API const char *dns_ntop(int af, const void *src, char *dst, int size);
|
||||
UDNS_API int dns_pton(int af, const char *src, void *dst);
|
||||
|
||||
/**************************************************************************/
|
||||
/**************** DNS raw packet layout ***********************************/
|
||||
|
||||
enum dns_rcode { /* reply codes */
|
||||
DNS_R_NOERROR = 0, /* ok, no error */
|
||||
DNS_R_FORMERR = 1, /* format error */
|
||||
DNS_R_SERVFAIL = 2, /* server failed */
|
||||
DNS_R_NXDOMAIN = 3, /* domain does not exists */
|
||||
DNS_R_NOTIMPL = 4, /* not implemented */
|
||||
DNS_R_REFUSED = 5, /* query refused */
|
||||
/* these are for BIND_UPDATE */
|
||||
DNS_R_YXDOMAIN = 6, /* Name exists */
|
||||
DNS_R_YXRRSET = 7, /* RRset exists */
|
||||
DNS_R_NXRRSET = 8, /* RRset does not exist */
|
||||
DNS_R_NOTAUTH = 9, /* Not authoritative for zone */
|
||||
DNS_R_NOTZONE = 10, /* Zone of record different from zone section */
|
||||
/*ns_r_max = 11,*/
|
||||
/* The following are TSIG extended errors */
|
||||
DNS_R_BADSIG = 16,
|
||||
DNS_R_BADKEY = 17,
|
||||
DNS_R_BADTIME = 18
|
||||
};
|
||||
|
||||
static __inline unsigned dns_get16(dnscc_t *s) {
|
||||
return ((unsigned)s[0]<<8) | s[1];
|
||||
}
|
||||
static __inline unsigned dns_get32(dnscc_t *s) {
|
||||
return ((unsigned)s[0]<<24) | ((unsigned)s[1]<<16)
|
||||
| ((unsigned)s[2]<<8) | s[3];
|
||||
}
|
||||
static __inline dnsc_t *dns_put16(dnsc_t *d, unsigned n) {
|
||||
*d++ = (dnsc_t)((n >> 8) & 255); *d++ = (dnsc_t)(n & 255); return d;
|
||||
}
|
||||
static __inline dnsc_t *dns_put32(dnsc_t *d, unsigned n) {
|
||||
*d++ = (dnsc_t)((n >> 24) & 255); *d++ = (dnsc_t)((n >> 16) & 255);
|
||||
*d++ = (dnsc_t)((n >> 8) & 255); *d++ = (dnsc_t)(n & 255);
|
||||
return d;
|
||||
}
|
||||
|
||||
/* DNS Header layout */
|
||||
enum {
|
||||
/* bytes 0:1 - query ID */
|
||||
DNS_H_QID1 = 0,
|
||||
DNS_H_QID2 = 1,
|
||||
DNS_H_QID = DNS_H_QID1,
|
||||
#define dns_qid(pkt) dns_get16((pkt)+DNS_H_QID)
|
||||
/* byte 2: flags1 */
|
||||
DNS_H_F1 = 2,
|
||||
DNS_HF1_QR = 0x80, /* query response flag */
|
||||
#define dns_qr(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_QR)
|
||||
DNS_HF1_OPCODE = 0x78, /* opcode, 0 = query */
|
||||
#define dns_opcode(pkt) (((pkt)[DNS_H_F1]&DNS_HF1_OPCODE)>>3)
|
||||
DNS_HF1_AA = 0x04, /* auth answer */
|
||||
#define dns_aa(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_AA)
|
||||
DNS_HF1_TC = 0x02, /* truncation flag */
|
||||
#define dns_tc(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_TC)
|
||||
DNS_HF1_RD = 0x01, /* recursion desired (may be set in query) */
|
||||
#define dns_rd(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_RD)
|
||||
/* byte 3: flags2 */
|
||||
DNS_H_F2 = 3,
|
||||
DNS_HF2_RA = 0x80, /* recursion available */
|
||||
#define dns_ra(pkt) ((pkt)[DNS_H_F2]&DNS_HF2_RA)
|
||||
DNS_HF2_Z = 0x40, /* reserved */
|
||||
DNS_HF2_AD = 0x20, /* DNSSEC: authentic data */
|
||||
#define dns_ad(pkt) ((pkt)[DNS_H_F2]&DNS_HF2_AD)
|
||||
DNS_HF2_CD = 0x10, /* DNSSEC: checking disabled */
|
||||
#define dns_cd(pkt) ((pkt)[DNS_H_F2]&DNS_HF2_CD)
|
||||
DNS_HF2_RCODE = 0x0f, /* response code, DNS_R_XXX above */
|
||||
#define dns_rcode(pkt) ((pkt)[DNS_H_F2]&DNS_HF2_RCODE)
|
||||
/* bytes 4:5: qdcount, numqueries */
|
||||
DNS_H_QDCNT1 = 4,
|
||||
DNS_H_QDCNT2 = 5,
|
||||
DNS_H_QDCNT = DNS_H_QDCNT1,
|
||||
#define dns_numqd(pkt) dns_get16((pkt)+4)
|
||||
/* bytes 6:7: ancount, numanswers */
|
||||
DNS_H_ANCNT1 = 6,
|
||||
DNS_H_ANCNT2 = 7,
|
||||
DNS_H_ANCNT = DNS_H_ANCNT1,
|
||||
#define dns_numan(pkt) dns_get16((pkt)+6)
|
||||
/* bytes 8:9: nscount, numauthority */
|
||||
DNS_H_NSCNT1 = 8,
|
||||
DNS_H_NSCNT2 = 9,
|
||||
DNS_H_NSCNT = DNS_H_NSCNT1,
|
||||
#define dns_numns(pkt) dns_get16((pkt)+8)
|
||||
/* bytes 10:11: arcount, numadditional */
|
||||
DNS_H_ARCNT1 = 10,
|
||||
DNS_H_ARCNT2 = 11,
|
||||
DNS_H_ARCNT = DNS_H_ARCNT1,
|
||||
#define dns_numar(pkt) dns_get16((pkt)+10)
|
||||
#define dns_payload(pkt) ((pkt)+DNS_HSIZE)
|
||||
/* EDNS0 (OPT RR) flags (Ext. Flags) */
|
||||
DNS_EF1_DO = 0x80, /* DNSSEC OK */
|
||||
};
|
||||
|
||||
/* packet buffer: start at pkt, end before pkte, current pos *curp.
|
||||
* extract a DN and set *curp to the next byte after DN in packet.
|
||||
* return -1 on error, 0 if dnsiz is too small, or dnlen on ok.
|
||||
*/
|
||||
UDNS_API int
|
||||
dns_getdn(dnscc_t *pkt, dnscc_t **curp, dnscc_t *end,
|
||||
dnsc_t *dn, unsigned dnsiz);
|
||||
|
||||
/* skip the DN at position cur in packet ending before pkte,
|
||||
* return pointer to the next byte after the DN or NULL on error */
|
||||
UDNS_API dnscc_t *
|
||||
dns_skipdn(dnscc_t *end, dnscc_t *cur);
|
||||
|
||||
struct dns_rr { /* DNS Resource Record */
|
||||
dnsc_t dnsrr_dn[DNS_MAXDN]; /* the DN of the RR */
|
||||
enum dns_class dnsrr_cls; /* Class */
|
||||
enum dns_type dnsrr_typ; /* Type */
|
||||
unsigned dnsrr_ttl; /* Time-To-Live (TTL) */
|
||||
unsigned dnsrr_dsz; /* data size */
|
||||
dnscc_t *dnsrr_dptr; /* pointer to start of data */
|
||||
dnscc_t *dnsrr_dend; /* past end of data */
|
||||
};
|
||||
|
||||
struct dns_parse { /* RR/packet parsing state */
|
||||
dnscc_t *dnsp_pkt; /* start of the packet */
|
||||
dnscc_t *dnsp_end; /* end of the packet */
|
||||
dnscc_t *dnsp_cur; /* current packet position */
|
||||
dnscc_t *dnsp_ans; /* start of answer section */
|
||||
int dnsp_rrl; /* number of RRs left to go */
|
||||
int dnsp_nrr; /* RR count so far */
|
||||
unsigned dnsp_ttl; /* TTL value so far */
|
||||
dnscc_t *dnsp_qdn; /* the RR DN we're looking for */
|
||||
enum dns_class dnsp_qcls; /* RR class we're looking for or 0 */
|
||||
enum dns_type dnsp_qtyp; /* RR type we're looking for or 0 */
|
||||
dnsc_t dnsp_dnbuf[DNS_MAXDN]; /* domain buffer */
|
||||
};
|
||||
|
||||
/* initialize the parse structure */
|
||||
UDNS_API void
|
||||
dns_initparse(struct dns_parse *p, dnscc_t *qdn,
|
||||
dnscc_t *pkt, dnscc_t *cur, dnscc_t *end);
|
||||
|
||||
/* search next RR, <0=error, 0=no more RRs, >0 = found. */
|
||||
UDNS_API int
|
||||
dns_nextrr(struct dns_parse *p, struct dns_rr *rr);
|
||||
|
||||
UDNS_API void
|
||||
dns_rewind(struct dns_parse *p, dnscc_t *qdn);
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************** Resolver Context ****************************************/
|
||||
|
||||
/* default resolver context */
|
||||
UDNS_DATA_API extern struct dns_ctx dns_defctx;
|
||||
|
||||
/* reset resolver context to default state, close it if open, drop queries */
|
||||
UDNS_API void
|
||||
dns_reset(struct dns_ctx *ctx);
|
||||
|
||||
/* reset resolver context and read in system configuration */
|
||||
UDNS_API int
|
||||
dns_init(struct dns_ctx *ctx, int do_open);
|
||||
|
||||
/* return new resolver context with the same settings as copy */
|
||||
UDNS_API struct dns_ctx *
|
||||
dns_new(const struct dns_ctx *copy);
|
||||
|
||||
/* free resolver context returned by dns_new(); all queries are dropped */
|
||||
UDNS_API void
|
||||
dns_free(struct dns_ctx *ctx);
|
||||
|
||||
/* add nameserver for a resolver context (or reset nslist if serv==NULL) */
|
||||
UDNS_API int
|
||||
dns_add_serv(struct dns_ctx *ctx, const char *serv);
|
||||
|
||||
/* add nameserver using struct sockaddr structure (with ports) */
|
||||
UDNS_API int
|
||||
dns_add_serv_s(struct dns_ctx *ctx, const struct sockaddr *sa);
|
||||
|
||||
/* add search list element for a resolver context (or reset it if srch==NULL) */
|
||||
UDNS_API int
|
||||
dns_add_srch(struct dns_ctx *ctx, const char *srch);
|
||||
|
||||
/* set options for a resolver context */
|
||||
UDNS_API int
|
||||
dns_set_opts(struct dns_ctx *ctx, const char *opts);
|
||||
|
||||
enum dns_opt { /* options */
|
||||
DNS_OPT_FLAGS, /* flags, DNS_F_XXX */
|
||||
DNS_OPT_TIMEOUT, /* timeout in secounds */
|
||||
DNS_OPT_NTRIES, /* number of retries */
|
||||
DNS_OPT_NDOTS, /* ndots */
|
||||
DNS_OPT_UDPSIZE, /* EDNS0 UDP size */
|
||||
DNS_OPT_PORT, /* port to use */
|
||||
};
|
||||
|
||||
/* set or get (if val<0) an option */
|
||||
UDNS_API int
|
||||
dns_set_opt(struct dns_ctx *ctx, enum dns_opt opt, int val);
|
||||
|
||||
enum dns_flags {
|
||||
DNS_NOSRCH = 0x00010000, /* do not perform search */
|
||||
DNS_NORD = 0x00020000, /* request no recursion */
|
||||
DNS_AAONLY = 0x00040000, /* set AA flag in queries */
|
||||
DNS_SET_DO = 0x00080000, /* set EDNS0 "DO" bit (DNSSEC OK) */
|
||||
DNS_SET_CD = 0x00100000, /* set CD bit (DNSSEC: checking disabled) */
|
||||
};
|
||||
|
||||
/* set the debug function pointer */
|
||||
typedef void
|
||||
(dns_dbgfn)(int code, const struct sockaddr *sa, unsigned salen,
|
||||
dnscc_t *pkt, int plen,
|
||||
const struct dns_query *q, void *data);
|
||||
UDNS_API void
|
||||
dns_set_dbgfn(struct dns_ctx *ctx, dns_dbgfn *dbgfn);
|
||||
|
||||
/* open and return UDP socket */
|
||||
UDNS_API int
|
||||
dns_open(struct dns_ctx *ctx);
|
||||
|
||||
/* return UDP socket or -1 if not open */
|
||||
UDNS_API int
|
||||
dns_sock(const struct dns_ctx *ctx);
|
||||
|
||||
/* close the UDP socket */
|
||||
UDNS_API void
|
||||
dns_close(struct dns_ctx *ctx);
|
||||
|
||||
/* return number of requests queued */
|
||||
UDNS_API int
|
||||
dns_active(const struct dns_ctx *ctx);
|
||||
|
||||
/* return status of the last operation */
|
||||
UDNS_API int
|
||||
dns_status(const struct dns_ctx *ctx);
|
||||
UDNS_API void
|
||||
dns_setstatus(struct dns_ctx *ctx, int status);
|
||||
|
||||
/* handle I/O event on UDP socket */
|
||||
UDNS_API void
|
||||
dns_ioevent(struct dns_ctx *ctx, time_t now);
|
||||
|
||||
/* process any timeouts, return time in secounds to the
|
||||
* next timeout (or -1 if none) but not greather than maxwait */
|
||||
UDNS_API int
|
||||
dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now);
|
||||
|
||||
/* define timer requesting routine to use */
|
||||
typedef void dns_utm_fn(struct dns_ctx *ctx, int timeout, void *data);
|
||||
UDNS_API void
|
||||
dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data);
|
||||
|
||||
/**************************************************************************/
|
||||
/**************** Making Queries ******************************************/
|
||||
|
||||
/* query callback routine */
|
||||
typedef void dns_query_fn(struct dns_ctx *ctx, void *result, void *data);
|
||||
|
||||
/* query parse routine: raw DNS => application structure */
|
||||
typedef int
|
||||
dns_parse_fn(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
|
||||
void **res);
|
||||
|
||||
enum dns_status {
|
||||
DNS_E_NOERROR = 0, /* ok, not an error */
|
||||
DNS_E_TEMPFAIL = -1, /* timeout, SERVFAIL or similar */
|
||||
DNS_E_PROTOCOL = -2, /* got garbled reply */
|
||||
DNS_E_NXDOMAIN = -3, /* domain does not exists */
|
||||
DNS_E_NODATA = -4, /* domain exists but no data of reqd type */
|
||||
DNS_E_NOMEM = -5, /* out of memory while processing */
|
||||
DNS_E_BADQUERY = -6 /* the query is malformed */
|
||||
};
|
||||
|
||||
/* submit generic DN query */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_dn(struct dns_ctx *ctx,
|
||||
dnscc_t *dn, int qcls, int qtyp, int flags,
|
||||
dns_parse_fn *parse, dns_query_fn *cbck, void *data);
|
||||
/* submit generic name query */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_p(struct dns_ctx *ctx,
|
||||
const char *name, int qcls, int qtyp, int flags,
|
||||
dns_parse_fn *parse, dns_query_fn *cbck, void *data);
|
||||
|
||||
/* cancel the given async query in progress */
|
||||
UDNS_API int
|
||||
dns_cancel(struct dns_ctx *ctx, struct dns_query *q);
|
||||
|
||||
/* resolve a generic query, return the answer */
|
||||
UDNS_API void *
|
||||
dns_resolve_dn(struct dns_ctx *ctx,
|
||||
dnscc_t *qdn, int qcls, int qtyp, int flags,
|
||||
dns_parse_fn *parse);
|
||||
UDNS_API void *
|
||||
dns_resolve_p(struct dns_ctx *ctx,
|
||||
const char *qname, int qcls, int qtyp, int flags,
|
||||
dns_parse_fn *parse);
|
||||
UDNS_API void *
|
||||
dns_resolve(struct dns_ctx *ctx, struct dns_query *q);
|
||||
|
||||
|
||||
/* Specific RR handlers */
|
||||
|
||||
#define dns_rr_common(prefix) \
|
||||
char *prefix##_cname; /* canonical name */ \
|
||||
char *prefix##_qname; /* original query name */ \
|
||||
unsigned prefix##_ttl; /* TTL value */ \
|
||||
int prefix##_nrr /* number of records */
|
||||
|
||||
struct dns_rr_null { /* NULL RRset, aka RRset template */
|
||||
dns_rr_common(dnsn);
|
||||
};
|
||||
|
||||
UDNS_API int
|
||||
dns_stdrr_size(const struct dns_parse *p);
|
||||
UDNS_API void *
|
||||
dns_stdrr_finish(struct dns_rr_null *ret, char *cp, const struct dns_parse *p);
|
||||
|
||||
struct dns_rr_a4 { /* the A RRset */
|
||||
dns_rr_common(dnsa4);
|
||||
struct in_addr *dnsa4_addr; /* array of addresses, naddr elements */
|
||||
};
|
||||
|
||||
UDNS_API dns_parse_fn dns_parse_a4; /* A RR parsing routine */
|
||||
typedef void /* A query callback routine */
|
||||
dns_query_a4_fn(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data);
|
||||
|
||||
/* submit A IN query */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags,
|
||||
dns_query_a4_fn *cbck, void *data);
|
||||
|
||||
/* resolve A IN query */
|
||||
UDNS_API struct dns_rr_a4 *
|
||||
dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags);
|
||||
|
||||
|
||||
struct dns_rr_a6 { /* the AAAA RRset */
|
||||
dns_rr_common(dnsa6);
|
||||
struct in6_addr *dnsa6_addr; /* array of addresses, naddr elements */
|
||||
};
|
||||
|
||||
UDNS_API dns_parse_fn dns_parse_a6; /* A RR parsing routine */
|
||||
typedef void /* A query callback routine */
|
||||
dns_query_a6_fn(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data);
|
||||
|
||||
/* submit AAAA IN query */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags,
|
||||
dns_query_a6_fn *cbck, void *data);
|
||||
|
||||
/* resolve AAAA IN query */
|
||||
UDNS_API struct dns_rr_a6 *
|
||||
dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags);
|
||||
|
||||
|
||||
struct dns_rr_ptr { /* the PTR RRset */
|
||||
dns_rr_common(dnsptr);
|
||||
char **dnsptr_ptr; /* array of PTRs */
|
||||
};
|
||||
|
||||
UDNS_API dns_parse_fn dns_parse_ptr; /* PTR RR parsing routine */
|
||||
typedef void /* PTR query callback */
|
||||
dns_query_ptr_fn(struct dns_ctx *ctx, struct dns_rr_ptr *result, void *data);
|
||||
/* submit PTR IN in-addr.arpa query */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr,
|
||||
dns_query_ptr_fn *cbck, void *data);
|
||||
/* resolve PTR IN in-addr.arpa query */
|
||||
UDNS_API struct dns_rr_ptr *
|
||||
dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr);
|
||||
|
||||
/* the same as above, but for ip6.arpa */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr,
|
||||
dns_query_ptr_fn *cbck, void *data);
|
||||
UDNS_API struct dns_rr_ptr *
|
||||
dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr);
|
||||
|
||||
|
||||
struct dns_mx { /* single MX RR */
|
||||
int priority; /* MX priority */
|
||||
char *name; /* MX name */
|
||||
};
|
||||
struct dns_rr_mx { /* the MX RRset */
|
||||
dns_rr_common(dnsmx);
|
||||
struct dns_mx *dnsmx_mx; /* array of MXes */
|
||||
};
|
||||
UDNS_API dns_parse_fn dns_parse_mx; /* MX RR parsing routine */
|
||||
typedef void /* MX RR callback */
|
||||
dns_query_mx_fn(struct dns_ctx *ctx, struct dns_rr_mx *result, void *data);
|
||||
/* submit MX IN query */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags,
|
||||
dns_query_mx_fn *cbck, void *data);
|
||||
/* resolve MX IN query */
|
||||
UDNS_API struct dns_rr_mx *
|
||||
dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags);
|
||||
|
||||
|
||||
struct dns_txt { /* single TXT record */
|
||||
int len; /* length of the text */
|
||||
dnsc_t *txt; /* pointer to text buffer. May contain nulls. */
|
||||
};
|
||||
struct dns_rr_txt { /* the TXT RRset */
|
||||
dns_rr_common(dnstxt);
|
||||
struct dns_txt *dnstxt_txt; /* array of TXT records */
|
||||
};
|
||||
UDNS_API dns_parse_fn dns_parse_txt; /* TXT RR parsing routine */
|
||||
typedef void /* TXT RR callback */
|
||||
dns_query_txt_fn(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data);
|
||||
/* submit TXT query */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags,
|
||||
dns_query_txt_fn *cbck, void *data);
|
||||
/* resolve TXT query */
|
||||
UDNS_API struct dns_rr_txt *
|
||||
dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags);
|
||||
|
||||
|
||||
struct dns_srv { /* single SRV RR */
|
||||
int priority; /* SRV priority */
|
||||
int weight; /* SRV weight */
|
||||
int port; /* SRV port */
|
||||
char *name; /* SRV name */
|
||||
};
|
||||
struct dns_rr_srv { /* the SRV RRset */
|
||||
dns_rr_common(dnssrv);
|
||||
struct dns_srv *dnssrv_srv; /* array of SRVes */
|
||||
};
|
||||
UDNS_API dns_parse_fn dns_parse_srv; /* SRV RR parsing routine */
|
||||
typedef void /* SRV RR callback */
|
||||
dns_query_srv_fn(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data);
|
||||
/* submit SRV IN query */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_srv(struct dns_ctx *ctx,
|
||||
const char *name, const char *srv, const char *proto,
|
||||
int flags, dns_query_srv_fn *cbck, void *data);
|
||||
/* resolve SRV IN query */
|
||||
UDNS_API struct dns_rr_srv *
|
||||
dns_resolve_srv(struct dns_ctx *ctx,
|
||||
const char *name, const char *srv, const char *proto,
|
||||
int flags);
|
||||
|
||||
/* NAPTR (RFC3403) RR type */
|
||||
struct dns_naptr { /* single NAPTR RR */
|
||||
int order; /* NAPTR order */
|
||||
int preference; /* NAPTR preference */
|
||||
char *flags; /* NAPTR flags */
|
||||
char *service; /* NAPTR service */
|
||||
char *regexp; /* NAPTR regexp */
|
||||
char *replacement; /* NAPTR replacement */
|
||||
};
|
||||
|
||||
struct dns_rr_naptr { /* the NAPTR RRset */
|
||||
dns_rr_common(dnsnaptr);
|
||||
struct dns_naptr *dnsnaptr_naptr; /* array of NAPTRes */
|
||||
};
|
||||
UDNS_API dns_parse_fn dns_parse_naptr; /* NAPTR RR parsing routine */
|
||||
typedef void /* NAPTR RR callback */
|
||||
dns_query_naptr_fn(struct dns_ctx *ctx,
|
||||
struct dns_rr_naptr *result, void *data);
|
||||
/* submit NAPTR IN query */
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags,
|
||||
dns_query_naptr_fn *cbck, void *data);
|
||||
/* resolve NAPTR IN query */
|
||||
UDNS_API struct dns_rr_naptr *
|
||||
dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags);
|
||||
|
||||
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_a4dnsbl(struct dns_ctx *ctx,
|
||||
const struct in_addr *addr, const char *dnsbl,
|
||||
dns_query_a4_fn *cbck, void *data);
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_a4dnsbl_txt(struct dns_ctx *ctx,
|
||||
const struct in_addr *addr, const char *dnsbl,
|
||||
dns_query_txt_fn *cbck, void *data);
|
||||
UDNS_API struct dns_rr_a4 *
|
||||
dns_resolve_a4dnsbl(struct dns_ctx *ctx,
|
||||
const struct in_addr *addr, const char *dnsbl);
|
||||
UDNS_API struct dns_rr_txt *
|
||||
dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx,
|
||||
const struct in_addr *addr, const char *dnsbl);
|
||||
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_a6dnsbl(struct dns_ctx *ctx,
|
||||
const struct in6_addr *addr, const char *dnsbl,
|
||||
dns_query_a4_fn *cbck, void *data);
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_a6dnsbl_txt(struct dns_ctx *ctx,
|
||||
const struct in6_addr *addr, const char *dnsbl,
|
||||
dns_query_txt_fn *cbck, void *data);
|
||||
UDNS_API struct dns_rr_a4 *
|
||||
dns_resolve_a6dnsbl(struct dns_ctx *ctx,
|
||||
const struct in6_addr *addr, const char *dnsbl);
|
||||
UDNS_API struct dns_rr_txt *
|
||||
dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx,
|
||||
const struct in6_addr *addr, const char *dnsbl);
|
||||
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_rhsbl(struct dns_ctx *ctx,
|
||||
const char *name, const char *rhsbl,
|
||||
dns_query_a4_fn *cbck, void *data);
|
||||
UDNS_API struct dns_query *
|
||||
dns_submit_rhsbl_txt(struct dns_ctx *ctx,
|
||||
const char *name, const char *rhsbl,
|
||||
dns_query_txt_fn *cbck, void *data);
|
||||
UDNS_API struct dns_rr_a4 *
|
||||
dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl);
|
||||
UDNS_API struct dns_rr_txt *
|
||||
dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl);
|
||||
|
||||
/**************************************************************************/
|
||||
/**************** Names, Names ********************************************/
|
||||
|
||||
struct dns_nameval {
|
||||
int val;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
UDNS_DATA_API extern const struct dns_nameval dns_classtab[];
|
||||
UDNS_DATA_API extern const struct dns_nameval dns_typetab[];
|
||||
UDNS_DATA_API extern const struct dns_nameval dns_rcodetab[];
|
||||
UDNS_API int
|
||||
dns_findname(const struct dns_nameval *nv, const char *name);
|
||||
#define dns_findclassname(cls) dns_findname(dns_classtab, (cls))
|
||||
#define dns_findtypename(type) dns_findname(dns_typetab, (type))
|
||||
#define dns_findrcodename(rcode) dns_findname(dns_rcodetab, (rcode))
|
||||
|
||||
UDNS_API const char *dns_classname(enum dns_class cls);
|
||||
UDNS_API const char *dns_typename(enum dns_type type);
|
||||
UDNS_API const char *dns_rcodename(enum dns_rcode rcode);
|
||||
const char *_dns_format_code(char *buf, const char *prefix, int code);
|
||||
|
||||
UDNS_API const char *dns_strerror(int errnum);
|
||||
|
||||
/* simple pseudo-random number generator, code by Bob Jenkins */
|
||||
|
||||
struct udns_jranctx { /* the context */
|
||||
unsigned a, b, c, d;
|
||||
};
|
||||
|
||||
/* initialize the RNG with a given seed */
|
||||
UDNS_API void
|
||||
udns_jraninit(struct udns_jranctx *x, unsigned seed);
|
||||
|
||||
/* return next random number. 32bits on most platforms so far. */
|
||||
UDNS_API unsigned
|
||||
udns_jranval(struct udns_jranctx *x);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* include guard */
|
||||
50
3rdparty/udns/udns_XtoX.c
vendored
Normal file
50
3rdparty/udns/udns_XtoX.c
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/* udns_XtoX.c
|
||||
udns_ntop() and udns_pton() routines, which are either
|
||||
- wrappers for inet_ntop() and inet_pton() or
|
||||
- reimplementations of those routines.
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#include "udns.h"
|
||||
|
||||
#ifdef HAVE_INET_PTON_NTOP
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
const char *dns_ntop(int af, const void *src, char *dst, int size) {
|
||||
return inet_ntop(af, src, dst, size);
|
||||
}
|
||||
|
||||
int dns_pton(int af, const char *src, void *dst) {
|
||||
return inet_pton(af, src, dst);
|
||||
}
|
||||
|
||||
#else
|
||||
#define inet_XtoX_no_ntop
|
||||
#define inet_XtoX_prefix dns_
|
||||
#include "inet_XtoX.c"
|
||||
|
||||
#endif
|
||||
160
3rdparty/udns/udns_bl.c
vendored
Normal file
160
3rdparty/udns/udns_bl.c
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
/* udns_bl.c
|
||||
DNSBL stuff
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "udns.h"
|
||||
#ifndef NULL
|
||||
# define NULL 0
|
||||
#endif
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_a4dnsbl(struct dns_ctx *ctx,
|
||||
const struct in_addr *addr, const char *dnsbl,
|
||||
dns_query_a4_fn *cbck, void *data) {
|
||||
dnsc_t dn[DNS_MAXDN];
|
||||
if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
|
||||
dns_setstatus(ctx, DNS_E_BADQUERY);
|
||||
return NULL;
|
||||
}
|
||||
return
|
||||
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH,
|
||||
dns_parse_a4, (dns_query_fn*)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_a4dnsbl_txt(struct dns_ctx *ctx,
|
||||
const struct in_addr *addr, const char *dnsbl,
|
||||
dns_query_txt_fn *cbck, void *data) {
|
||||
dnsc_t dn[DNS_MAXDN];
|
||||
if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
|
||||
dns_setstatus(ctx, DNS_E_BADQUERY);
|
||||
return NULL;
|
||||
}
|
||||
return
|
||||
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH,
|
||||
dns_parse_txt, (dns_query_fn*)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_a4 *
|
||||
dns_resolve_a4dnsbl(struct dns_ctx *ctx,
|
||||
const struct in_addr *addr, const char *dnsbl) {
|
||||
return (struct dns_rr_a4 *)
|
||||
dns_resolve(ctx, dns_submit_a4dnsbl(ctx, addr, dnsbl, 0, 0));
|
||||
}
|
||||
|
||||
struct dns_rr_txt *
|
||||
dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx,
|
||||
const struct in_addr *addr, const char *dnsbl) {
|
||||
return (struct dns_rr_txt *)
|
||||
dns_resolve(ctx, dns_submit_a4dnsbl_txt(ctx, addr, dnsbl, 0, 0));
|
||||
}
|
||||
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_a6dnsbl(struct dns_ctx *ctx,
|
||||
const struct in6_addr *addr, const char *dnsbl,
|
||||
dns_query_a4_fn *cbck, void *data) {
|
||||
dnsc_t dn[DNS_MAXDN];
|
||||
if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
|
||||
dns_setstatus(ctx, DNS_E_BADQUERY);
|
||||
return NULL;
|
||||
}
|
||||
return
|
||||
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH,
|
||||
dns_parse_a4, (dns_query_fn*)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_a6dnsbl_txt(struct dns_ctx *ctx,
|
||||
const struct in6_addr *addr, const char *dnsbl,
|
||||
dns_query_txt_fn *cbck, void *data) {
|
||||
dnsc_t dn[DNS_MAXDN];
|
||||
if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
|
||||
dns_setstatus(ctx, DNS_E_BADQUERY);
|
||||
return NULL;
|
||||
}
|
||||
return
|
||||
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH,
|
||||
dns_parse_txt, (dns_query_fn*)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_a4 *
|
||||
dns_resolve_a6dnsbl(struct dns_ctx *ctx,
|
||||
const struct in6_addr *addr, const char *dnsbl) {
|
||||
return (struct dns_rr_a4 *)
|
||||
dns_resolve(ctx, dns_submit_a6dnsbl(ctx, addr, dnsbl, 0, 0));
|
||||
}
|
||||
|
||||
struct dns_rr_txt *
|
||||
dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx,
|
||||
const struct in6_addr *addr, const char *dnsbl) {
|
||||
return (struct dns_rr_txt *)
|
||||
dns_resolve(ctx, dns_submit_a6dnsbl_txt(ctx, addr, dnsbl, 0, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
dns_rhsbltodn(const char *name, const char *rhsbl, dnsc_t dn[DNS_MAXDN])
|
||||
{
|
||||
int l = dns_sptodn(name, dn, DNS_MAXDN);
|
||||
if (l <= 0) return 0;
|
||||
l = dns_sptodn(rhsbl, dn+l-1, DNS_MAXDN-l+1);
|
||||
if (l <= 0) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl,
|
||||
dns_query_a4_fn *cbck, void *data) {
|
||||
dnsc_t dn[DNS_MAXDN];
|
||||
if (!dns_rhsbltodn(name, rhsbl, dn)) {
|
||||
dns_setstatus(ctx, DNS_E_BADQUERY);
|
||||
return NULL;
|
||||
}
|
||||
return
|
||||
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH,
|
||||
dns_parse_a4, (dns_query_fn*)cbck, data);
|
||||
}
|
||||
struct dns_query *
|
||||
dns_submit_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl,
|
||||
dns_query_txt_fn *cbck, void *data) {
|
||||
dnsc_t dn[DNS_MAXDN];
|
||||
if (!dns_rhsbltodn(name, rhsbl, dn)) {
|
||||
dns_setstatus(ctx, DNS_E_BADQUERY);
|
||||
return NULL;
|
||||
}
|
||||
return
|
||||
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH,
|
||||
dns_parse_txt, (dns_query_fn*)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_a4 *
|
||||
dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl) {
|
||||
return (struct dns_rr_a4*)
|
||||
dns_resolve(ctx, dns_submit_rhsbl(ctx, name, rhsbl, 0, 0));
|
||||
}
|
||||
|
||||
struct dns_rr_txt *
|
||||
dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl)
|
||||
{
|
||||
return (struct dns_rr_txt*)
|
||||
dns_resolve(ctx, dns_submit_rhsbl_txt(ctx, name, rhsbl, 0, 0));
|
||||
}
|
||||
199
3rdparty/udns/udns_codes.c
vendored
Normal file
199
3rdparty/udns/udns_codes.c
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
/* Automatically generated. */
|
||||
#include "udns.h"
|
||||
|
||||
const struct dns_nameval dns_typetab[] = {
|
||||
{DNS_T_INVALID,"INVALID"},
|
||||
{DNS_T_A,"A"},
|
||||
{DNS_T_NS,"NS"},
|
||||
{DNS_T_MD,"MD"},
|
||||
{DNS_T_MF,"MF"},
|
||||
{DNS_T_CNAME,"CNAME"},
|
||||
{DNS_T_SOA,"SOA"},
|
||||
{DNS_T_MB,"MB"},
|
||||
{DNS_T_MG,"MG"},
|
||||
{DNS_T_MR,"MR"},
|
||||
{DNS_T_NULL,"NULL"},
|
||||
{DNS_T_WKS,"WKS"},
|
||||
{DNS_T_PTR,"PTR"},
|
||||
{DNS_T_HINFO,"HINFO"},
|
||||
{DNS_T_MINFO,"MINFO"},
|
||||
{DNS_T_MX,"MX"},
|
||||
{DNS_T_TXT,"TXT"},
|
||||
{DNS_T_RP,"RP"},
|
||||
{DNS_T_AFSDB,"AFSDB"},
|
||||
{DNS_T_X25,"X25"},
|
||||
{DNS_T_ISDN,"ISDN"},
|
||||
{DNS_T_RT,"RT"},
|
||||
{DNS_T_NSAP,"NSAP"},
|
||||
{DNS_T_NSAP_PTR,"NSAP_PTR"},
|
||||
{DNS_T_SIG,"SIG"},
|
||||
{DNS_T_KEY,"KEY"},
|
||||
{DNS_T_PX,"PX"},
|
||||
{DNS_T_GPOS,"GPOS"},
|
||||
{DNS_T_AAAA,"AAAA"},
|
||||
{DNS_T_LOC,"LOC"},
|
||||
{DNS_T_NXT,"NXT"},
|
||||
{DNS_T_EID,"EID"},
|
||||
{DNS_T_NIMLOC,"NIMLOC"},
|
||||
{DNS_T_SRV,"SRV"},
|
||||
{DNS_T_ATMA,"ATMA"},
|
||||
{DNS_T_NAPTR,"NAPTR"},
|
||||
{DNS_T_KX,"KX"},
|
||||
{DNS_T_CERT,"CERT"},
|
||||
{DNS_T_A6,"A6"},
|
||||
{DNS_T_DNAME,"DNAME"},
|
||||
{DNS_T_SINK,"SINK"},
|
||||
{DNS_T_OPT,"OPT"},
|
||||
{DNS_T_DS,"DS"},
|
||||
{DNS_T_SSHFP,"SSHFP"},
|
||||
{DNS_T_IPSECKEY,"IPSECKEY"},
|
||||
{DNS_T_RRSIG,"RRSIG"},
|
||||
{DNS_T_NSEC,"NSEC"},
|
||||
{DNS_T_DNSKEY,"DNSKEY"},
|
||||
{DNS_T_DHCID,"DHCID"},
|
||||
{DNS_T_NSEC3,"NSEC3"},
|
||||
{DNS_T_NSEC3PARAMS,"NSEC3PARAMS"},
|
||||
{DNS_T_TALINK,"TALINK"},
|
||||
{DNS_T_SPF,"SPF"},
|
||||
{DNS_T_UINFO,"UINFO"},
|
||||
{DNS_T_UID,"UID"},
|
||||
{DNS_T_GID,"GID"},
|
||||
{DNS_T_UNSPEC,"UNSPEC"},
|
||||
{DNS_T_TSIG,"TSIG"},
|
||||
{DNS_T_IXFR,"IXFR"},
|
||||
{DNS_T_AXFR,"AXFR"},
|
||||
{DNS_T_MAILB,"MAILB"},
|
||||
{DNS_T_MAILA,"MAILA"},
|
||||
{DNS_T_ANY,"ANY"},
|
||||
{DNS_T_ZXFR,"ZXFR"},
|
||||
{DNS_T_DLV,"DLV"},
|
||||
{DNS_T_MAX,"MAX"},
|
||||
{0,0}};
|
||||
const char *dns_typename(enum dns_type code) {
|
||||
static char nm[20];
|
||||
switch(code) {
|
||||
case DNS_T_INVALID: return dns_typetab[0].name;
|
||||
case DNS_T_A: return dns_typetab[1].name;
|
||||
case DNS_T_NS: return dns_typetab[2].name;
|
||||
case DNS_T_MD: return dns_typetab[3].name;
|
||||
case DNS_T_MF: return dns_typetab[4].name;
|
||||
case DNS_T_CNAME: return dns_typetab[5].name;
|
||||
case DNS_T_SOA: return dns_typetab[6].name;
|
||||
case DNS_T_MB: return dns_typetab[7].name;
|
||||
case DNS_T_MG: return dns_typetab[8].name;
|
||||
case DNS_T_MR: return dns_typetab[9].name;
|
||||
case DNS_T_NULL: return dns_typetab[10].name;
|
||||
case DNS_T_WKS: return dns_typetab[11].name;
|
||||
case DNS_T_PTR: return dns_typetab[12].name;
|
||||
case DNS_T_HINFO: return dns_typetab[13].name;
|
||||
case DNS_T_MINFO: return dns_typetab[14].name;
|
||||
case DNS_T_MX: return dns_typetab[15].name;
|
||||
case DNS_T_TXT: return dns_typetab[16].name;
|
||||
case DNS_T_RP: return dns_typetab[17].name;
|
||||
case DNS_T_AFSDB: return dns_typetab[18].name;
|
||||
case DNS_T_X25: return dns_typetab[19].name;
|
||||
case DNS_T_ISDN: return dns_typetab[20].name;
|
||||
case DNS_T_RT: return dns_typetab[21].name;
|
||||
case DNS_T_NSAP: return dns_typetab[22].name;
|
||||
case DNS_T_NSAP_PTR: return dns_typetab[23].name;
|
||||
case DNS_T_SIG: return dns_typetab[24].name;
|
||||
case DNS_T_KEY: return dns_typetab[25].name;
|
||||
case DNS_T_PX: return dns_typetab[26].name;
|
||||
case DNS_T_GPOS: return dns_typetab[27].name;
|
||||
case DNS_T_AAAA: return dns_typetab[28].name;
|
||||
case DNS_T_LOC: return dns_typetab[29].name;
|
||||
case DNS_T_NXT: return dns_typetab[30].name;
|
||||
case DNS_T_EID: return dns_typetab[31].name;
|
||||
case DNS_T_NIMLOC: return dns_typetab[32].name;
|
||||
case DNS_T_SRV: return dns_typetab[33].name;
|
||||
case DNS_T_ATMA: return dns_typetab[34].name;
|
||||
case DNS_T_NAPTR: return dns_typetab[35].name;
|
||||
case DNS_T_KX: return dns_typetab[36].name;
|
||||
case DNS_T_CERT: return dns_typetab[37].name;
|
||||
case DNS_T_A6: return dns_typetab[38].name;
|
||||
case DNS_T_DNAME: return dns_typetab[39].name;
|
||||
case DNS_T_SINK: return dns_typetab[40].name;
|
||||
case DNS_T_OPT: return dns_typetab[41].name;
|
||||
case DNS_T_DS: return dns_typetab[42].name;
|
||||
case DNS_T_SSHFP: return dns_typetab[43].name;
|
||||
case DNS_T_IPSECKEY: return dns_typetab[44].name;
|
||||
case DNS_T_RRSIG: return dns_typetab[45].name;
|
||||
case DNS_T_NSEC: return dns_typetab[46].name;
|
||||
case DNS_T_DNSKEY: return dns_typetab[47].name;
|
||||
case DNS_T_DHCID: return dns_typetab[48].name;
|
||||
case DNS_T_NSEC3: return dns_typetab[49].name;
|
||||
case DNS_T_NSEC3PARAMS: return dns_typetab[50].name;
|
||||
case DNS_T_TALINK: return dns_typetab[51].name;
|
||||
case DNS_T_SPF: return dns_typetab[52].name;
|
||||
case DNS_T_UINFO: return dns_typetab[53].name;
|
||||
case DNS_T_UID: return dns_typetab[54].name;
|
||||
case DNS_T_GID: return dns_typetab[55].name;
|
||||
case DNS_T_UNSPEC: return dns_typetab[56].name;
|
||||
case DNS_T_TSIG: return dns_typetab[57].name;
|
||||
case DNS_T_IXFR: return dns_typetab[58].name;
|
||||
case DNS_T_AXFR: return dns_typetab[59].name;
|
||||
case DNS_T_MAILB: return dns_typetab[60].name;
|
||||
case DNS_T_MAILA: return dns_typetab[61].name;
|
||||
case DNS_T_ANY: return dns_typetab[62].name;
|
||||
case DNS_T_ZXFR: return dns_typetab[63].name;
|
||||
case DNS_T_DLV: return dns_typetab[64].name;
|
||||
case DNS_T_MAX: return dns_typetab[65].name;
|
||||
}
|
||||
return _dns_format_code(nm,"type",code);
|
||||
}
|
||||
|
||||
const struct dns_nameval dns_classtab[] = {
|
||||
{DNS_C_INVALID,"INVALID"},
|
||||
{DNS_C_IN,"IN"},
|
||||
{DNS_C_CH,"CH"},
|
||||
{DNS_C_HS,"HS"},
|
||||
{DNS_C_ANY,"ANY"},
|
||||
{0,0}};
|
||||
const char *dns_classname(enum dns_class code) {
|
||||
static char nm[20];
|
||||
switch(code) {
|
||||
case DNS_C_INVALID: return dns_classtab[0].name;
|
||||
case DNS_C_IN: return dns_classtab[1].name;
|
||||
case DNS_C_CH: return dns_classtab[2].name;
|
||||
case DNS_C_HS: return dns_classtab[3].name;
|
||||
case DNS_C_ANY: return dns_classtab[4].name;
|
||||
}
|
||||
return _dns_format_code(nm,"class",code);
|
||||
}
|
||||
|
||||
const struct dns_nameval dns_rcodetab[] = {
|
||||
{DNS_R_NOERROR,"NOERROR"},
|
||||
{DNS_R_FORMERR,"FORMERR"},
|
||||
{DNS_R_SERVFAIL,"SERVFAIL"},
|
||||
{DNS_R_NXDOMAIN,"NXDOMAIN"},
|
||||
{DNS_R_NOTIMPL,"NOTIMPL"},
|
||||
{DNS_R_REFUSED,"REFUSED"},
|
||||
{DNS_R_YXDOMAIN,"YXDOMAIN"},
|
||||
{DNS_R_YXRRSET,"YXRRSET"},
|
||||
{DNS_R_NXRRSET,"NXRRSET"},
|
||||
{DNS_R_NOTAUTH,"NOTAUTH"},
|
||||
{DNS_R_NOTZONE,"NOTZONE"},
|
||||
{DNS_R_BADSIG,"BADSIG"},
|
||||
{DNS_R_BADKEY,"BADKEY"},
|
||||
{DNS_R_BADTIME,"BADTIME"},
|
||||
{0,0}};
|
||||
const char *dns_rcodename(enum dns_rcode code) {
|
||||
static char nm[20];
|
||||
switch(code) {
|
||||
case DNS_R_NOERROR: return dns_rcodetab[0].name;
|
||||
case DNS_R_FORMERR: return dns_rcodetab[1].name;
|
||||
case DNS_R_SERVFAIL: return dns_rcodetab[2].name;
|
||||
case DNS_R_NXDOMAIN: return dns_rcodetab[3].name;
|
||||
case DNS_R_NOTIMPL: return dns_rcodetab[4].name;
|
||||
case DNS_R_REFUSED: return dns_rcodetab[5].name;
|
||||
case DNS_R_YXDOMAIN: return dns_rcodetab[6].name;
|
||||
case DNS_R_YXRRSET: return dns_rcodetab[7].name;
|
||||
case DNS_R_NXRRSET: return dns_rcodetab[8].name;
|
||||
case DNS_R_NOTAUTH: return dns_rcodetab[9].name;
|
||||
case DNS_R_NOTZONE: return dns_rcodetab[10].name;
|
||||
case DNS_R_BADSIG: return dns_rcodetab[11].name;
|
||||
case DNS_R_BADKEY: return dns_rcodetab[12].name;
|
||||
case DNS_R_BADTIME: return dns_rcodetab[13].name;
|
||||
}
|
||||
return _dns_format_code(nm,"rcode",code);
|
||||
}
|
||||
379
3rdparty/udns/udns_dn.c
vendored
Normal file
379
3rdparty/udns/udns_dn.c
vendored
Normal file
@@ -0,0 +1,379 @@
|
||||
/* udns_dn.c
|
||||
domain names manipulation routines
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "udns.h"
|
||||
|
||||
unsigned dns_dnlen(dnscc_t *dn) {
|
||||
register dnscc_t *d = dn;
|
||||
while(*d)
|
||||
d += 1 + *d;
|
||||
return (unsigned)(d - dn) + 1;
|
||||
}
|
||||
|
||||
unsigned dns_dnlabels(register dnscc_t *dn) {
|
||||
register unsigned l = 0;
|
||||
while(*dn)
|
||||
++l, dn += 1 + *dn;
|
||||
return l;
|
||||
}
|
||||
|
||||
unsigned dns_dnequal(register dnscc_t *dn1, register dnscc_t *dn2) {
|
||||
register unsigned c;
|
||||
dnscc_t *dn = dn1;
|
||||
for(;;) {
|
||||
if ((c = *dn1++) != *dn2++)
|
||||
return 0;
|
||||
if (!c)
|
||||
return (unsigned)(dn1 - dn);
|
||||
while(c--) {
|
||||
if (DNS_DNLC(*dn1) != DNS_DNLC(*dn2))
|
||||
return 0;
|
||||
++dn1; ++dn2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz) {
|
||||
unsigned sdnlen = dns_dnlen(sdn);
|
||||
if (ddnsiz < sdnlen)
|
||||
return 0;
|
||||
memcpy(ddn, sdn, sdnlen);
|
||||
return sdnlen;
|
||||
}
|
||||
|
||||
int
|
||||
dns_ptodn(const char *name, unsigned namelen,
|
||||
dnsc_t *dn, unsigned dnsiz, int *isabs)
|
||||
{
|
||||
dnsc_t *dp; /* current position in dn (len byte first) */
|
||||
dnsc_t *const de /* end of dn: last byte that can be filled up */
|
||||
= dn + (dnsiz >= DNS_MAXDN ? DNS_MAXDN : dnsiz) - 1;
|
||||
dnscc_t *np = (dnscc_t *)name;
|
||||
dnscc_t *ne = np + (namelen ? namelen : strlen((char*)np));
|
||||
dnsc_t *llab; /* start of last label (llab[-1] will be length) */
|
||||
unsigned c; /* next input character, or length of last label */
|
||||
|
||||
if (!dnsiz)
|
||||
return 0;
|
||||
dp = llab = dn + 1;
|
||||
|
||||
while(np < ne) {
|
||||
|
||||
if (*np == '.') { /* label delimiter */
|
||||
c = dp - llab; /* length of the label */
|
||||
if (!c) { /* empty label */
|
||||
if (np == (dnscc_t *)name && np + 1 == ne) {
|
||||
/* special case for root dn, aka `.' */
|
||||
++np;
|
||||
break;
|
||||
}
|
||||
return -1; /* zero label */
|
||||
}
|
||||
if (c > DNS_MAXLABEL)
|
||||
return -1; /* label too long */
|
||||
llab[-1] = (dnsc_t)c; /* update len of last label */
|
||||
llab = ++dp; /* start new label, llab[-1] will be len of it */
|
||||
++np;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check whenever we may put out one more byte */
|
||||
if (dp >= de) /* too long? */
|
||||
return dnsiz >= DNS_MAXDN ? -1 : 0;
|
||||
if (*np != '\\') { /* non-escape, simple case */
|
||||
*dp++ = *np++;
|
||||
continue;
|
||||
}
|
||||
/* handle \-style escape */
|
||||
/* note that traditionally, domain names (gethostbyname etc)
|
||||
* used decimal \dd notation, not octal \ooo (RFC1035), so
|
||||
* we're following this tradition here.
|
||||
*/
|
||||
if (++np == ne)
|
||||
return -1; /* bad escape */
|
||||
else if (*np >= '0' && *np <= '9') { /* decimal number */
|
||||
/* we allow not only exactly 3 digits as per RFC1035,
|
||||
* but also 2 or 1, for better usability. */
|
||||
c = *np++ - '0';
|
||||
if (np < ne && *np >= '0' && *np <= '9') { /* 2digits */
|
||||
c = c * 10 + *np++ - '0';
|
||||
if (np < ne && *np >= '0' && *np <= '9') {
|
||||
c = c * 10 + *np++ - '0';
|
||||
if (c > 255)
|
||||
return -1; /* bad escape */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
c = *np++;
|
||||
*dp++ = (dnsc_t)c; /* place next out byte */
|
||||
}
|
||||
|
||||
if ((c = dp - llab) > DNS_MAXLABEL)
|
||||
return -1; /* label too long */
|
||||
if ((llab[-1] = (dnsc_t)c) != 0) {
|
||||
*dp++ = 0;
|
||||
if (isabs)
|
||||
*isabs = 0;
|
||||
}
|
||||
else if (isabs)
|
||||
*isabs = 1;
|
||||
|
||||
return dp - dn;
|
||||
}
|
||||
|
||||
dnscc_t dns_inaddr_arpa_dn[14] = "\07in-addr\04arpa";
|
||||
|
||||
dnsc_t *
|
||||
dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne) {
|
||||
const unsigned char *s = ((const unsigned char *)addr) + 4;
|
||||
while(s > (const unsigned char *)addr) {
|
||||
unsigned n = *--s;
|
||||
dnsc_t *p = dn + 1;
|
||||
if (n > 99) {
|
||||
if (p + 2 > dne) return 0;
|
||||
*p++ = n / 100 + '0';
|
||||
*p++ = (n % 100 / 10) + '0';
|
||||
*p = n % 10 + '0';
|
||||
}
|
||||
else if (n > 9) {
|
||||
if (p + 1 > dne) return 0;
|
||||
*p++ = n / 10 + '0';
|
||||
*p = n % 10 + '0';
|
||||
}
|
||||
else {
|
||||
if (p > dne) return 0;
|
||||
*p = n + '0';
|
||||
}
|
||||
*dn = p - dn;
|
||||
dn = p + 1;
|
||||
}
|
||||
return dn;
|
||||
}
|
||||
|
||||
int dns_a4todn(const struct in_addr *addr, dnscc_t *tdn,
|
||||
dnsc_t *dn, unsigned dnsiz) {
|
||||
dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz);
|
||||
dnsc_t *p;
|
||||
unsigned l;
|
||||
p = dns_a4todn_(addr, dn, dne);
|
||||
if (!p) return 0;
|
||||
if (!tdn)
|
||||
tdn = dns_inaddr_arpa_dn;
|
||||
l = dns_dnlen(tdn);
|
||||
if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0;
|
||||
memcpy(p, tdn, l);
|
||||
return (p + l) - dn;
|
||||
}
|
||||
|
||||
int dns_a4ptodn(const struct in_addr *addr, const char *tname,
|
||||
dnsc_t *dn, unsigned dnsiz) {
|
||||
dnsc_t *p;
|
||||
int r;
|
||||
if (!tname)
|
||||
return dns_a4todn(addr, NULL, dn, dnsiz);
|
||||
p = dns_a4todn_(addr, dn, dn + dnsiz);
|
||||
if (!p) return 0;
|
||||
r = dns_sptodn(tname, p, dnsiz - (p - dn));
|
||||
return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0;
|
||||
}
|
||||
|
||||
dnscc_t dns_ip6_arpa_dn[10] = "\03ip6\04arpa";
|
||||
|
||||
dnsc_t *
|
||||
dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne) {
|
||||
const unsigned char *s = ((const unsigned char *)addr) + 16;
|
||||
if (dn + 64 > dne) return 0;
|
||||
while(s > (const unsigned char *)addr) {
|
||||
unsigned n = *--s & 0x0f;
|
||||
*dn++ = 1;
|
||||
*dn++ = n > 9 ? n + 'a' - 10 : n + '0';
|
||||
*dn++ = 1;
|
||||
n = *s >> 4;
|
||||
*dn++ = n > 9 ? n + 'a' - 10 : n + '0';
|
||||
}
|
||||
return dn;
|
||||
}
|
||||
|
||||
int dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn,
|
||||
dnsc_t *dn, unsigned dnsiz) {
|
||||
dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz);
|
||||
dnsc_t *p;
|
||||
unsigned l;
|
||||
p = dns_a6todn_(addr, dn, dne);
|
||||
if (!p) return 0;
|
||||
if (!tdn)
|
||||
tdn = dns_ip6_arpa_dn;
|
||||
l = dns_dnlen(tdn);
|
||||
if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0;
|
||||
memcpy(p, tdn, l);
|
||||
return (p + l) - dn;
|
||||
}
|
||||
|
||||
int dns_a6ptodn(const struct in6_addr *addr, const char *tname,
|
||||
dnsc_t *dn, unsigned dnsiz) {
|
||||
dnsc_t *p;
|
||||
int r;
|
||||
if (!tname)
|
||||
return dns_a6todn(addr, NULL, dn, dnsiz);
|
||||
p = dns_a6todn_(addr, dn, dn + dnsiz);
|
||||
if (!p) return 0;
|
||||
r = dns_sptodn(tname, p, dnsiz - (p - dn));
|
||||
return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0;
|
||||
}
|
||||
|
||||
/* return size of buffer required to convert the dn into asciiz string.
|
||||
* Keep in sync with dns_dntop() below.
|
||||
*/
|
||||
unsigned dns_dntop_size(dnscc_t *dn) {
|
||||
unsigned size = 0; /* the size reqd */
|
||||
dnscc_t *le; /* label end */
|
||||
|
||||
while(*dn) {
|
||||
/* *dn is the length of the next label, non-zero */
|
||||
if (size)
|
||||
++size; /* for the dot */
|
||||
le = dn + *dn + 1;
|
||||
++dn;
|
||||
do {
|
||||
switch(*dn) {
|
||||
case '.':
|
||||
case '\\':
|
||||
/* Special modifiers in zone files. */
|
||||
case '"':
|
||||
case ';':
|
||||
case '@':
|
||||
case '$':
|
||||
size += 2;
|
||||
break;
|
||||
default:
|
||||
if (*dn <= 0x20 || *dn >= 0x7f)
|
||||
/* \ddd decimal notation */
|
||||
size += 4;
|
||||
else
|
||||
size += 1;
|
||||
}
|
||||
} while(++dn < le);
|
||||
}
|
||||
size += 1; /* zero byte at the end - string terminator */
|
||||
return size > DNS_MAXNAME ? 0 : size;
|
||||
}
|
||||
|
||||
/* Convert the dn into asciiz string.
|
||||
* Keep in sync with dns_dntop_size() above.
|
||||
*/
|
||||
int dns_dntop(dnscc_t *dn, char *name, unsigned namesiz) {
|
||||
char *np = name; /* current name ptr */
|
||||
char *const ne = name + namesiz; /* end of name */
|
||||
dnscc_t *le; /* label end */
|
||||
|
||||
while(*dn) {
|
||||
/* *dn is the length of the next label, non-zero */
|
||||
if (np != name) {
|
||||
if (np >= ne) goto toolong;
|
||||
*np++ = '.';
|
||||
}
|
||||
le = dn + *dn + 1;
|
||||
++dn;
|
||||
do {
|
||||
switch(*dn) {
|
||||
case '.':
|
||||
case '\\':
|
||||
/* Special modifiers in zone files. */
|
||||
case '"':
|
||||
case ';':
|
||||
case '@':
|
||||
case '$':
|
||||
if (np + 2 > ne) goto toolong;
|
||||
*np++ = '\\';
|
||||
*np++ = *dn;
|
||||
break;
|
||||
default:
|
||||
if (*dn <= 0x20 || *dn >= 0x7f) {
|
||||
/* \ddd decimal notation */
|
||||
if (np + 4 >= ne) goto toolong;
|
||||
*np++ = '\\';
|
||||
*np++ = '0' + (*dn / 100);
|
||||
*np++ = '0' + ((*dn % 100) / 10);
|
||||
*np++ = '0' + (*dn % 10);
|
||||
}
|
||||
else {
|
||||
if (np >= ne) goto toolong;
|
||||
*np++ = *dn;
|
||||
}
|
||||
}
|
||||
} while(++dn < le);
|
||||
}
|
||||
if (np >= ne) goto toolong;
|
||||
*np++ = '\0';
|
||||
return np - name;
|
||||
toolong:
|
||||
return namesiz >= DNS_MAXNAME ? -1 : 0;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
int sz;
|
||||
dnsc_t dn[DNS_MAXDN+10];
|
||||
dnsc_t *dl, *dp;
|
||||
int isabs;
|
||||
|
||||
sz = (argc > 1) ? atoi(argv[1]) : 0;
|
||||
|
||||
for(i = 2; i < argc; ++i) {
|
||||
int r = dns_ptodn(argv[i], 0, dn, sz, &isabs);
|
||||
printf("%s: ", argv[i]);
|
||||
if (r < 0) printf("error\n");
|
||||
else if (!r) printf("buffer too small\n");
|
||||
else {
|
||||
printf("len=%d dnlen=%d size=%d name:",
|
||||
r, dns_dnlen(dn), dns_dntop_size(dn));
|
||||
dl = dn;
|
||||
while(*dl) {
|
||||
printf(" %d=", *dl);
|
||||
dp = dl + 1;
|
||||
dl = dp + *dl;
|
||||
while(dp < dl) {
|
||||
if (*dp <= ' ' || *dp >= 0x7f)
|
||||
printf("\\%03d", *dp);
|
||||
else if (*dp == '.' || *dp == '\\')
|
||||
printf("\\%c", *dp);
|
||||
else
|
||||
putchar(*dp);
|
||||
++dp;
|
||||
}
|
||||
}
|
||||
if (isabs) putchar('.');
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
||||
30
3rdparty/udns/udns_dntosp.c
vendored
Normal file
30
3rdparty/udns/udns_dntosp.c
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/* udns_dntosp.c
|
||||
dns_dntosp() = convert DN to asciiz string using static buffer
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "udns.h"
|
||||
|
||||
static char name[DNS_MAXNAME];
|
||||
|
||||
const char *dns_dntosp(dnscc_t *dn) {
|
||||
return dns_dntop(dn, name, sizeof(name)) > 0 ? name : 0;
|
||||
}
|
||||
231
3rdparty/udns/udns_init.c
vendored
Normal file
231
3rdparty/udns/udns_init.c
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
/* udns_init.c
|
||||
resolver initialisation stuff
|
||||
|
||||
Copyright (C) 2006 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#ifdef WINDOWS
|
||||
# include <winsock2.h> /* includes <windows.h> */
|
||||
# include <iphlpapi.h> /* for dns server addresses etc */
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
# include <fcntl.h>
|
||||
#endif /* !WINDOWS */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "udns.h"
|
||||
|
||||
#define ISSPACE(x) (x == ' ' || x == '\t' || x == '\r' || x == '\n')
|
||||
|
||||
static const char space[] = " \t\r\n";
|
||||
|
||||
static void dns_set_serv_internal(struct dns_ctx *ctx, char *serv) {
|
||||
dns_add_serv(ctx, NULL);
|
||||
for(serv = strtok(serv, space); serv; serv = strtok(NULL, space))
|
||||
dns_add_serv(ctx, serv);
|
||||
}
|
||||
|
||||
static void dns_set_srch_internal(struct dns_ctx *ctx, char *srch) {
|
||||
dns_add_srch(ctx, NULL);
|
||||
for(srch = strtok(srch, space); srch; srch = strtok(NULL, space))
|
||||
dns_add_srch(ctx, srch);
|
||||
}
|
||||
|
||||
#ifdef WINDOWS
|
||||
|
||||
#ifndef NO_IPHLPAPI
|
||||
/* Apparently, some systems does not have proper headers for IPHLPAIP to work.
|
||||
* The best is to upgrade headers, but here's another, ugly workaround for
|
||||
* this: compile with -DNO_IPHLPAPI.
|
||||
*/
|
||||
|
||||
typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(
|
||||
ULONG Family, DWORD Flags, PVOID Reserved,
|
||||
PIP_ADAPTER_ADDRESSES pAdapterAddresses,
|
||||
PULONG pOutBufLen);
|
||||
|
||||
static int dns_initns_iphlpapi(struct dns_ctx *ctx) {
|
||||
HANDLE h_iphlpapi;
|
||||
GetAdaptersAddressesFunc pfnGetAdAddrs;
|
||||
PIP_ADAPTER_ADDRESSES pAddr, pAddrBuf;
|
||||
PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr;
|
||||
ULONG ulOutBufLen;
|
||||
DWORD dwRetVal;
|
||||
int ret = -1;
|
||||
|
||||
h_iphlpapi = LoadLibrary("iphlpapi.dll");
|
||||
if (!h_iphlpapi)
|
||||
return -1;
|
||||
pfnGetAdAddrs = (GetAdaptersAddressesFunc)
|
||||
GetProcAddress(h_iphlpapi, "GetAdaptersAddresses");
|
||||
if (!pfnGetAdAddrs) goto freelib;
|
||||
ulOutBufLen = 0;
|
||||
dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen);
|
||||
if (dwRetVal != ERROR_BUFFER_OVERFLOW) goto freelib;
|
||||
pAddrBuf = malloc(ulOutBufLen);
|
||||
if (!pAddrBuf) goto freelib;
|
||||
dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen);
|
||||
if (dwRetVal != ERROR_SUCCESS) goto freemem;
|
||||
for (pAddr = pAddrBuf; pAddr; pAddr = pAddr->Next)
|
||||
for (pDnsAddr = pAddr->FirstDnsServerAddress;
|
||||
pDnsAddr;
|
||||
pDnsAddr = pDnsAddr->Next)
|
||||
dns_add_serv_s(ctx, pDnsAddr->Address.lpSockaddr);
|
||||
ret = 0;
|
||||
freemem:
|
||||
free(pAddrBuf);
|
||||
freelib:
|
||||
FreeLibrary(h_iphlpapi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* NO_IPHLPAPI */
|
||||
|
||||
#define dns_initns_iphlpapi(ctx) (-1)
|
||||
|
||||
#endif /* NO_IPHLPAPI */
|
||||
|
||||
static int dns_initns_registry(struct dns_ctx *ctx) {
|
||||
LONG res;
|
||||
HKEY hk;
|
||||
DWORD type = REG_EXPAND_SZ | REG_SZ;
|
||||
DWORD len;
|
||||
char valBuf[1024];
|
||||
|
||||
#define REGKEY_WINNT "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
|
||||
#define REGKEY_WIN9x "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
|
||||
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WINNT, 0, KEY_QUERY_VALUE, &hk);
|
||||
if (res != ERROR_SUCCESS)
|
||||
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WIN9x,
|
||||
0, KEY_QUERY_VALUE, &hk);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return -1;
|
||||
len = sizeof(valBuf) - 1;
|
||||
res = RegQueryValueEx(hk, "NameServer", NULL, &type, (BYTE*)valBuf, &len);
|
||||
if (res != ERROR_SUCCESS || !len || !valBuf[0]) {
|
||||
len = sizeof(valBuf) - 1;
|
||||
res = RegQueryValueEx(hk, "DhcpNameServer", NULL, &type,
|
||||
(BYTE*)valBuf, &len);
|
||||
}
|
||||
RegCloseKey(hk);
|
||||
if (res != ERROR_SUCCESS || !len || !valBuf[0])
|
||||
return -1;
|
||||
valBuf[len] = '\0';
|
||||
/* nameservers are stored as a whitespace-seperate list:
|
||||
* "192.168.1.1 123.21.32.12" */
|
||||
dns_set_serv_internal(ctx, valBuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !WINDOWS */
|
||||
|
||||
static int dns_init_resolvconf(struct dns_ctx *ctx) {
|
||||
char *v;
|
||||
char buf[2049]; /* this buffer is used to hold /etc/resolv.conf */
|
||||
int has_srch = 0;
|
||||
|
||||
/* read resolv.conf... */
|
||||
{ int fd = open("/etc/resolv.conf", O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
int l = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
buf[l < 0 ? 0 : l] = '\0';
|
||||
}
|
||||
else
|
||||
buf[0] = '\0';
|
||||
}
|
||||
if (buf[0]) { /* ...and parse it */
|
||||
char *line, *nextline;
|
||||
line = buf;
|
||||
do {
|
||||
nextline = strchr(line, '\n');
|
||||
if (nextline) *nextline++ = '\0';
|
||||
v = line;
|
||||
while(*v && !ISSPACE(*v)) ++v;
|
||||
if (!*v) continue;
|
||||
*v++ = '\0';
|
||||
while(ISSPACE(*v)) ++v;
|
||||
if (!*v) continue;
|
||||
if (strcmp(line, "domain") == 0) {
|
||||
dns_set_srch_internal(ctx, strtok(v, space));
|
||||
has_srch = 1;
|
||||
}
|
||||
else if (strcmp(line, "search") == 0) {
|
||||
dns_set_srch_internal(ctx, v);
|
||||
has_srch = 1;
|
||||
}
|
||||
else if (strcmp(line, "nameserver") == 0)
|
||||
dns_add_serv(ctx, strtok(v, space));
|
||||
else if (strcmp(line, "options") == 0)
|
||||
dns_set_opts(ctx, v);
|
||||
} while((line = nextline) != NULL);
|
||||
}
|
||||
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
|
||||
/* get list of nameservers from env. vars. */
|
||||
if ((v = getenv("NSCACHEIP")) != NULL ||
|
||||
(v = getenv("NAMESERVERS")) != NULL) {
|
||||
strncpy(buf, v, sizeof(buf) - 1);
|
||||
dns_set_serv_internal(ctx, buf);
|
||||
}
|
||||
/* if $LOCALDOMAIN is set, use it for search list */
|
||||
if ((v = getenv("LOCALDOMAIN")) != NULL) {
|
||||
strncpy(buf, v, sizeof(buf) - 1);
|
||||
dns_set_srch_internal(ctx, buf);
|
||||
has_srch = 1;
|
||||
}
|
||||
if ((v = getenv("RES_OPTIONS")) != NULL)
|
||||
dns_set_opts(ctx, v);
|
||||
|
||||
/* if still no search list, use local domain name */
|
||||
if (has_srch &&
|
||||
gethostname(buf, sizeof(buf) - 1) == 0 &&
|
||||
(v = strchr(buf, '.')) != NULL &&
|
||||
*++v != '\0')
|
||||
dns_add_srch(ctx, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !WINDOWS */
|
||||
|
||||
int dns_init(struct dns_ctx *ctx, int do_open) {
|
||||
if (!ctx)
|
||||
ctx = &dns_defctx;
|
||||
dns_reset(ctx);
|
||||
|
||||
#ifdef WINDOWS
|
||||
if (dns_initns_iphlpapi(ctx) != 0)
|
||||
dns_initns_registry(ctx);
|
||||
/*XXX WINDOWS: probably good to get default domain and search list too...
|
||||
* And options. Something is in registry. */
|
||||
/*XXX WINDOWS: maybe environment variables are also useful? */
|
||||
#else
|
||||
dns_init_resolvconf(ctx);
|
||||
#endif
|
||||
|
||||
return do_open ? dns_open(ctx) : 0;
|
||||
}
|
||||
52
3rdparty/udns/udns_jran.c
vendored
Normal file
52
3rdparty/udns/udns_jran.c
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/* udns_jran.c: small non-cryptographic random number generator
|
||||
* taken from http://burtleburtle.net/bob/rand/smallprng.html
|
||||
* by Bob Jenkins, Public domain.
|
||||
*/
|
||||
|
||||
#include "udns.h"
|
||||
|
||||
#define rot32(x,k) (((x) << (k)) | ((x) >> (32-(k))))
|
||||
#define rot64(x,k) (((x) << (k)) | ((x) >> (64-(k))))
|
||||
#define tr32(x) ((x)&0xffffffffu)
|
||||
|
||||
unsigned udns_jranval(struct udns_jranctx *x) {
|
||||
/* This routine can be made to work with either 32 or 64bit words -
|
||||
* if JRAN_32_64 is defined when compiling the file.
|
||||
* We use if() instead of #if since there's no good
|
||||
* portable way to check sizeof() in preprocessor without
|
||||
* introducing some ugly configure-time checks.
|
||||
* Most compilers will optimize the wrong branches away anyway.
|
||||
* By default it assumes 32bit integers
|
||||
*/
|
||||
#ifdef JRAN_32_64
|
||||
if (sizeof(unsigned) == 4) {
|
||||
#endif
|
||||
unsigned e = tr32(x->a - rot32(x->b, 27));
|
||||
x->a = tr32(x->b ^ rot32(x->c, 17));
|
||||
x->b = tr32(x->c + x->d);
|
||||
x->c = tr32(x->d + e);
|
||||
x->d = tr32(e + x->a);
|
||||
#ifdef JRAN_32_64
|
||||
}
|
||||
else if (sizeof(unsigned) == 8) { /* assuming it's 64bits */
|
||||
unsigned e = x->a - rot64(x->b, 7);
|
||||
x->a = x->b ^ rot64(x->c, 13);
|
||||
x->b = x->c + rot64(x->d, 37);
|
||||
x->c = x->d + e;
|
||||
x->d = e + x->a;
|
||||
}
|
||||
else {
|
||||
unsigned e = 0;
|
||||
x->d = 1/e; /* bail */
|
||||
}
|
||||
#endif
|
||||
return x->d;
|
||||
}
|
||||
|
||||
void udns_jraninit(struct udns_jranctx *x, unsigned seed) {
|
||||
unsigned i;
|
||||
x->a = 0xf1ea5eed;
|
||||
x->b = x->c = x->d = seed;
|
||||
for (i = 0; i < 20; ++i)
|
||||
(void)udns_jranval(x);
|
||||
}
|
||||
67
3rdparty/udns/udns_misc.c
vendored
Normal file
67
3rdparty/udns/udns_misc.c
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/* udns_misc.c
|
||||
miscellaneous routines
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "udns.h"
|
||||
|
||||
int dns_findname(const struct dns_nameval *nv, const char *name) {
|
||||
register const char *a, *b;
|
||||
for(; nv->name; ++nv)
|
||||
for(a = name, b = nv->name; ; ++a, ++b)
|
||||
if (DNS_DNUC(*a) != *b) break;
|
||||
else if (!*a) return nv->val;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *_dns_format_code(char *buf, const char *prefix, int code) {
|
||||
char *bp = buf;
|
||||
unsigned c, n;
|
||||
do *bp++ = DNS_DNUC(*prefix);
|
||||
while(*++prefix);
|
||||
*bp++ = '#';
|
||||
if (code < 0) code = -code, *bp++ = '-';
|
||||
n = 0; c = code;
|
||||
do ++n;
|
||||
while((c /= 10));
|
||||
c = code;
|
||||
bp[n--] = '\0';
|
||||
do bp[n--] = c % 10 + '0';
|
||||
while((c /= 10));
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *dns_strerror(int err) {
|
||||
if (err >= 0) return "successeful completion";
|
||||
switch(err) {
|
||||
case DNS_E_TEMPFAIL: return "temporary failure in name resolution";
|
||||
case DNS_E_PROTOCOL: return "protocol error";
|
||||
case DNS_E_NXDOMAIN: return "domain name does not exist";
|
||||
case DNS_E_NODATA: return "valid domain but no data of requested type";
|
||||
case DNS_E_NOMEM: return "out of memory";
|
||||
case DNS_E_BADQUERY: return "malformed query";
|
||||
default: return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
const char *dns_version(void) {
|
||||
return UDNS_VERSION;
|
||||
}
|
||||
169
3rdparty/udns/udns_parse.c
vendored
Normal file
169
3rdparty/udns/udns_parse.c
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/* udns_parse.c
|
||||
raw DNS packet parsing routines
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "udns.h"
|
||||
|
||||
dnscc_t *dns_skipdn(dnscc_t *cur, dnscc_t *end) {
|
||||
unsigned c;
|
||||
for(;;) {
|
||||
if (cur >= end)
|
||||
return NULL;
|
||||
c = *cur++;
|
||||
if (!c)
|
||||
return cur;
|
||||
if (c & 192) /* jump */
|
||||
return cur + 1 >= end ? NULL : cur + 1;
|
||||
cur += c;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dns_getdn(dnscc_t *pkt, dnscc_t **cur, dnscc_t *end,
|
||||
register dnsc_t *dn, unsigned dnsiz) {
|
||||
unsigned c;
|
||||
dnscc_t *pp = *cur; /* current packet pointer */
|
||||
dnsc_t *dp = dn; /* current dn pointer */
|
||||
dnsc_t *const de /* end of the DN dest */
|
||||
= dn + (dnsiz < DNS_MAXDN ? dnsiz : DNS_MAXDN);
|
||||
dnscc_t *jump = NULL; /* ptr after first jump if any */
|
||||
unsigned loop = 100; /* jump loop counter */
|
||||
|
||||
for(;;) { /* loop by labels */
|
||||
if (pp >= end) /* reached end of packet? */
|
||||
return -1;
|
||||
c = *pp++; /* length of the label */
|
||||
if (!c) { /* empty label: terminate */
|
||||
if (dn >= de) /* can't fit terminator */
|
||||
goto noroom;
|
||||
*dp++ = 0;
|
||||
/* return next pos: either after the first jump or current */
|
||||
*cur = jump ? jump : pp;
|
||||
return dp - dn;
|
||||
}
|
||||
if (c & 192) { /* jump */
|
||||
if (pp >= end) /* eop instead of jump pos */
|
||||
return -1;
|
||||
if (!jump) jump = pp + 1; /* remember first jump */
|
||||
else if (!--loop) return -1; /* too many jumps */
|
||||
c = ((c & ~192) << 8) | *pp; /* new pos */
|
||||
if (c < DNS_HSIZE) /* don't allow jump into the header */
|
||||
return -1;
|
||||
pp = pkt + c;
|
||||
continue;
|
||||
}
|
||||
if (c > DNS_MAXLABEL) /* too long label? */
|
||||
return -1;
|
||||
if (pp + c > end) /* label does not fit in packet? */
|
||||
return -1;
|
||||
if (dp + c + 1 > de) /* if enouth room for the label */
|
||||
goto noroom;
|
||||
*dp++ = c; /* label length */
|
||||
memcpy(dp, pp, c); /* and the label itself */
|
||||
dp += c;
|
||||
pp += c; /* advance to the next label */
|
||||
}
|
||||
noroom:
|
||||
return dnsiz < DNS_MAXDN ? 0 : -1;
|
||||
}
|
||||
|
||||
void dns_rewind(struct dns_parse *p, dnscc_t *qdn) {
|
||||
p->dnsp_qdn = qdn;
|
||||
p->dnsp_cur = p->dnsp_ans;
|
||||
p->dnsp_rrl = dns_numan(p->dnsp_pkt);
|
||||
p->dnsp_ttl = 0xffffffffu;
|
||||
p->dnsp_nrr = 0;
|
||||
}
|
||||
|
||||
void
|
||||
dns_initparse(struct dns_parse *p, dnscc_t *qdn,
|
||||
dnscc_t *pkt, dnscc_t *cur, dnscc_t *end) {
|
||||
p->dnsp_pkt = pkt;
|
||||
p->dnsp_end = end;
|
||||
p->dnsp_rrl = dns_numan(pkt);
|
||||
p->dnsp_qdn = qdn;
|
||||
assert(cur + 4 <= end);
|
||||
if ((p->dnsp_qtyp = dns_get16(cur+0)) == DNS_T_ANY) p->dnsp_qtyp = 0;
|
||||
if ((p->dnsp_qcls = dns_get16(cur+2)) == DNS_C_ANY) p->dnsp_qcls = 0;
|
||||
p->dnsp_cur = p->dnsp_ans = cur + 4;
|
||||
p->dnsp_ttl = 0xffffffffu;
|
||||
p->dnsp_nrr = 0;
|
||||
}
|
||||
|
||||
int dns_nextrr(struct dns_parse *p, struct dns_rr *rr) {
|
||||
dnscc_t *cur = p->dnsp_cur;
|
||||
while(p->dnsp_rrl > 0) {
|
||||
--p->dnsp_rrl;
|
||||
if (dns_getdn(p->dnsp_pkt, &cur, p->dnsp_end,
|
||||
rr->dnsrr_dn, sizeof(rr->dnsrr_dn)) <= 0)
|
||||
return -1;
|
||||
if (cur + 10 > p->dnsp_end)
|
||||
return -1;
|
||||
rr->dnsrr_typ = dns_get16(cur);
|
||||
rr->dnsrr_cls = dns_get16(cur+2);
|
||||
rr->dnsrr_ttl = dns_get32(cur+4);
|
||||
rr->dnsrr_dsz = dns_get16(cur+8);
|
||||
rr->dnsrr_dptr = cur = cur + 10;
|
||||
rr->dnsrr_dend = cur = cur + rr->dnsrr_dsz;
|
||||
if (cur > p->dnsp_end)
|
||||
return -1;
|
||||
if (p->dnsp_qdn && !dns_dnequal(p->dnsp_qdn, rr->dnsrr_dn))
|
||||
continue;
|
||||
if ((!p->dnsp_qcls || p->dnsp_qcls == rr->dnsrr_cls) &&
|
||||
(!p->dnsp_qtyp || p->dnsp_qtyp == rr->dnsrr_typ)) {
|
||||
p->dnsp_cur = cur;
|
||||
++p->dnsp_nrr;
|
||||
if (p->dnsp_ttl > rr->dnsrr_ttl) p->dnsp_ttl = rr->dnsrr_ttl;
|
||||
return 1;
|
||||
}
|
||||
if (p->dnsp_qdn && rr->dnsrr_typ == DNS_T_CNAME && !p->dnsp_nrr) {
|
||||
if (dns_getdn(p->dnsp_pkt, &rr->dnsrr_dptr, p->dnsp_end,
|
||||
p->dnsp_dnbuf, sizeof(p->dnsp_dnbuf)) <= 0 ||
|
||||
rr->dnsrr_dptr != rr->dnsrr_dend)
|
||||
return -1;
|
||||
p->dnsp_qdn = p->dnsp_dnbuf;
|
||||
if (p->dnsp_ttl > rr->dnsrr_ttl) p->dnsp_ttl = rr->dnsrr_ttl;
|
||||
}
|
||||
}
|
||||
p->dnsp_cur = cur;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_stdrr_size(const struct dns_parse *p) {
|
||||
return
|
||||
dns_dntop_size(p->dnsp_qdn) +
|
||||
(p->dnsp_qdn == dns_payload(p->dnsp_pkt) ? 0 :
|
||||
dns_dntop_size(dns_payload(p->dnsp_pkt)));
|
||||
}
|
||||
|
||||
void *dns_stdrr_finish(struct dns_rr_null *ret, char *cp,
|
||||
const struct dns_parse *p) {
|
||||
cp += dns_dntop(p->dnsp_qdn, (ret->dnsn_cname = cp), DNS_MAXNAME);
|
||||
if (p->dnsp_qdn == dns_payload(p->dnsp_pkt))
|
||||
ret->dnsn_qname = ret->dnsn_cname;
|
||||
else
|
||||
dns_dntop(dns_payload(p->dnsp_pkt), (ret->dnsn_qname = cp), DNS_MAXNAME);
|
||||
ret->dnsn_ttl = p->dnsp_ttl;
|
||||
return ret;
|
||||
}
|
||||
1323
3rdparty/udns/udns_resolver.c
vendored
Normal file
1323
3rdparty/udns/udns_resolver.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
126
3rdparty/udns/udns_rr_a.c
vendored
Normal file
126
3rdparty/udns/udns_rr_a.c
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
/* udns_rr_a.c
|
||||
parse/query A/AAAA IN records
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#ifndef WINDOWS
|
||||
# include <sys/types.h>
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#include "udns.h"
|
||||
|
||||
/* here, we use common routine to parse both IPv4 and IPv6 addresses.
|
||||
*/
|
||||
|
||||
/* this structure should match dns_rr_a[46] */
|
||||
struct dns_rr_a {
|
||||
dns_rr_common(dnsa);
|
||||
unsigned char *dnsa_addr;
|
||||
};
|
||||
|
||||
static int
|
||||
dns_parse_a(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
|
||||
void **result, unsigned dsize) {
|
||||
struct dns_rr_a *ret;
|
||||
struct dns_parse p;
|
||||
struct dns_rr rr;
|
||||
int r;
|
||||
|
||||
/* first, validate and count number of addresses */
|
||||
dns_initparse(&p, qdn, pkt, cur, end);
|
||||
while((r = dns_nextrr(&p, &rr)) > 0)
|
||||
if (rr.dnsrr_dsz != dsize)
|
||||
return DNS_E_PROTOCOL;
|
||||
if (r < 0)
|
||||
return DNS_E_PROTOCOL;
|
||||
else if (!p.dnsp_nrr)
|
||||
return DNS_E_NODATA;
|
||||
|
||||
ret = malloc(sizeof(*ret) + dsize * p.dnsp_nrr + dns_stdrr_size(&p));
|
||||
if (!ret)
|
||||
return DNS_E_NOMEM;
|
||||
|
||||
ret->dnsa_nrr = p.dnsp_nrr;
|
||||
ret->dnsa_addr = (unsigned char*)(ret+1);
|
||||
|
||||
/* copy the RRs */
|
||||
for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r)
|
||||
memcpy(ret->dnsa_addr + dsize * r, rr.dnsrr_dptr, dsize);
|
||||
|
||||
dns_stdrr_finish((struct dns_rr_null *)ret,
|
||||
(char *)(ret->dnsa_addr + dsize * p.dnsp_nrr), &p);
|
||||
*result = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
dns_parse_a4(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
|
||||
void **result) {
|
||||
#ifdef AF_INET
|
||||
assert(sizeof(struct in_addr) == 4);
|
||||
#endif
|
||||
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_A);
|
||||
return dns_parse_a(qdn, pkt, cur, end, result, 4);
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags,
|
||||
dns_query_a4_fn *cbck, void *data) {
|
||||
return
|
||||
dns_submit_p(ctx, name, DNS_C_IN, DNS_T_A, flags,
|
||||
dns_parse_a4, (dns_query_fn*)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_a4 *
|
||||
dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags) {
|
||||
return (struct dns_rr_a4 *)
|
||||
dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_A, flags, dns_parse_a4);
|
||||
}
|
||||
|
||||
int
|
||||
dns_parse_a6(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
|
||||
void **result) {
|
||||
#ifdef AF_INET6
|
||||
assert(sizeof(struct in6_addr) == 16);
|
||||
#endif
|
||||
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_AAAA);
|
||||
return dns_parse_a(qdn, pkt, cur, end, result, 16);
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags,
|
||||
dns_query_a6_fn *cbck, void *data) {
|
||||
return
|
||||
dns_submit_p(ctx, name, DNS_C_IN, DNS_T_AAAA, flags,
|
||||
dns_parse_a6, (dns_query_fn*)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_a6 *
|
||||
dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags) {
|
||||
return (struct dns_rr_a6 *)
|
||||
dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_AAAA, flags, dns_parse_a6);
|
||||
}
|
||||
91
3rdparty/udns/udns_rr_mx.c
vendored
Normal file
91
3rdparty/udns/udns_rr_mx.c
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/* udns_rr_mx.c
|
||||
parse/query MX IN records
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "udns.h"
|
||||
|
||||
int
|
||||
dns_parse_mx(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
|
||||
void **result) {
|
||||
struct dns_rr_mx *ret;
|
||||
struct dns_parse p;
|
||||
struct dns_rr rr;
|
||||
int r, l;
|
||||
char *sp;
|
||||
dnsc_t mx[DNS_MAXDN];
|
||||
|
||||
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_MX);
|
||||
|
||||
/* first, validate the answer and count size of the result */
|
||||
l = 0;
|
||||
dns_initparse(&p, qdn, pkt, cur, end);
|
||||
while((r = dns_nextrr(&p, &rr)) > 0) {
|
||||
cur = rr.dnsrr_dptr + 2;
|
||||
r = dns_getdn(pkt, &cur, end, mx, sizeof(mx));
|
||||
if (r <= 0 || cur != rr.dnsrr_dend)
|
||||
return DNS_E_PROTOCOL;
|
||||
l += dns_dntop_size(mx);
|
||||
}
|
||||
if (r < 0)
|
||||
return DNS_E_PROTOCOL;
|
||||
if (!p.dnsp_nrr)
|
||||
return DNS_E_NODATA;
|
||||
|
||||
/* next, allocate and set up result */
|
||||
l += dns_stdrr_size(&p);
|
||||
ret = malloc(sizeof(*ret) + sizeof(struct dns_mx) * p.dnsp_nrr + l);
|
||||
if (!ret)
|
||||
return DNS_E_NOMEM;
|
||||
ret->dnsmx_nrr = p.dnsp_nrr;
|
||||
ret->dnsmx_mx = (struct dns_mx *)(ret+1);
|
||||
|
||||
/* and 3rd, fill in result, finally */
|
||||
sp = (char*)(ret->dnsmx_mx + p.dnsp_nrr);
|
||||
for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) {
|
||||
ret->dnsmx_mx[r].name = sp;
|
||||
cur = rr.dnsrr_dptr;
|
||||
ret->dnsmx_mx[r].priority = dns_get16(cur);
|
||||
cur += 2;
|
||||
dns_getdn(pkt, &cur, end, mx, sizeof(mx));
|
||||
sp += dns_dntop(mx, sp, DNS_MAXNAME);
|
||||
}
|
||||
dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
|
||||
*result = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags,
|
||||
dns_query_mx_fn *cbck, void *data) {
|
||||
return
|
||||
dns_submit_p(ctx, name, DNS_C_IN, DNS_T_MX, flags,
|
||||
dns_parse_mx, (dns_query_fn *)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_mx *
|
||||
dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags) {
|
||||
return (struct dns_rr_mx *)
|
||||
dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_MX, flags, dns_parse_mx);
|
||||
}
|
||||
128
3rdparty/udns/udns_rr_naptr.c
vendored
Normal file
128
3rdparty/udns/udns_rr_naptr.c
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
/* udns_rr_naptr.c
|
||||
parse/query NAPTR IN records
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
Copyright (C) 2006 Mikael Magnusson <mikma@users.sourceforge.net>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "udns.h"
|
||||
|
||||
/* Get a single string for NAPTR record, pretty much like a DN label.
|
||||
* String length is in first byte in *cur, so it can't be >255.
|
||||
*/
|
||||
static int dns_getstr(dnscc_t **cur, dnscc_t *ep, char *buf)
|
||||
{
|
||||
unsigned l;
|
||||
dnscc_t *cp = *cur;
|
||||
|
||||
l = *cp++;
|
||||
if (cp + l > ep)
|
||||
return DNS_E_PROTOCOL;
|
||||
if (buf) {
|
||||
memcpy(buf, cp, l);
|
||||
buf[l] = '\0';
|
||||
}
|
||||
cp += l;
|
||||
|
||||
*cur = cp;
|
||||
return l + 1;
|
||||
}
|
||||
|
||||
int
|
||||
dns_parse_naptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
|
||||
void **result) {
|
||||
struct dns_rr_naptr *ret;
|
||||
struct dns_parse p;
|
||||
struct dns_rr rr;
|
||||
int r, l;
|
||||
char *sp;
|
||||
dnsc_t dn[DNS_MAXDN];
|
||||
|
||||
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_NAPTR);
|
||||
|
||||
/* first, validate the answer and count size of the result */
|
||||
l = 0;
|
||||
dns_initparse(&p, qdn, pkt, cur, end);
|
||||
while((r = dns_nextrr(&p, &rr)) > 0) {
|
||||
int i;
|
||||
dnscc_t *ep = rr.dnsrr_dend;
|
||||
|
||||
/* first 4 bytes: order & preference */
|
||||
cur = rr.dnsrr_dptr + 4;
|
||||
|
||||
/* flags, services and regexp */
|
||||
for (i = 0; i < 3; i++) {
|
||||
r = dns_getstr(&cur, ep, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
l += r;
|
||||
}
|
||||
/* replacement */
|
||||
r = dns_getdn(pkt, &cur, end, dn, sizeof(dn));
|
||||
if (r <= 0 || cur != rr.dnsrr_dend)
|
||||
return DNS_E_PROTOCOL;
|
||||
l += dns_dntop_size(dn);
|
||||
}
|
||||
if (r < 0)
|
||||
return DNS_E_PROTOCOL;
|
||||
if (!p.dnsp_nrr)
|
||||
return DNS_E_NODATA;
|
||||
|
||||
/* next, allocate and set up result */
|
||||
l += dns_stdrr_size(&p);
|
||||
ret = malloc(sizeof(*ret) + sizeof(struct dns_naptr) * p.dnsp_nrr + l);
|
||||
if (!ret)
|
||||
return DNS_E_NOMEM;
|
||||
ret->dnsnaptr_nrr = p.dnsp_nrr;
|
||||
ret->dnsnaptr_naptr = (struct dns_naptr *)(ret+1);
|
||||
|
||||
/* and 3rd, fill in result, finally */
|
||||
sp = (char*)(&ret->dnsnaptr_naptr[p.dnsp_nrr]);
|
||||
for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) {
|
||||
cur = rr.dnsrr_dptr;
|
||||
ret->dnsnaptr_naptr[r].order = dns_get16(cur); cur += 2;
|
||||
ret->dnsnaptr_naptr[r].preference = dns_get16(cur); cur += 2;
|
||||
sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].flags = sp));
|
||||
sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].service = sp));
|
||||
sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].regexp = sp));
|
||||
dns_getdn(pkt, &cur, end, dn, sizeof(dn));
|
||||
sp += dns_dntop(dn, (ret->dnsnaptr_naptr[r].replacement = sp), DNS_MAXNAME);
|
||||
}
|
||||
dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
|
||||
*result = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags,
|
||||
dns_query_naptr_fn *cbck, void *data) {
|
||||
return
|
||||
dns_submit_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags,
|
||||
dns_parse_naptr, (dns_query_fn *)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_naptr *
|
||||
dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags) {
|
||||
return (struct dns_rr_naptr *)
|
||||
dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags, dns_parse_naptr);
|
||||
}
|
||||
109
3rdparty/udns/udns_rr_ptr.c
vendored
Normal file
109
3rdparty/udns/udns_rr_ptr.c
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/* udns_rr_ptr.c
|
||||
parse/query PTR records
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "udns.h"
|
||||
|
||||
int
|
||||
dns_parse_ptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
|
||||
void **result) {
|
||||
struct dns_rr_ptr *ret;
|
||||
struct dns_parse p;
|
||||
struct dns_rr rr;
|
||||
int r, l, c;
|
||||
char *sp;
|
||||
dnsc_t ptr[DNS_MAXDN];
|
||||
|
||||
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_PTR);
|
||||
|
||||
/* first, validate the answer and count size of the result */
|
||||
l = c = 0;
|
||||
dns_initparse(&p, qdn, pkt, cur, end);
|
||||
while((r = dns_nextrr(&p, &rr)) > 0) {
|
||||
cur = rr.dnsrr_dptr;
|
||||
r = dns_getdn(pkt, &cur, end, ptr, sizeof(ptr));
|
||||
if (r <= 0 || cur != rr.dnsrr_dend)
|
||||
return DNS_E_PROTOCOL;
|
||||
l += dns_dntop_size(ptr);
|
||||
++c;
|
||||
}
|
||||
if (r < 0)
|
||||
return DNS_E_PROTOCOL;
|
||||
if (!c)
|
||||
return DNS_E_NODATA;
|
||||
|
||||
/* next, allocate and set up result */
|
||||
ret = malloc(sizeof(*ret) + sizeof(char **) * c + l + dns_stdrr_size(&p));
|
||||
if (!ret)
|
||||
return DNS_E_NOMEM;
|
||||
ret->dnsptr_nrr = c;
|
||||
ret->dnsptr_ptr = (char **)(ret+1);
|
||||
|
||||
/* and 3rd, fill in result, finally */
|
||||
sp = (char*)(ret->dnsptr_ptr + c);
|
||||
c = 0;
|
||||
dns_rewind(&p, qdn);
|
||||
while((r = dns_nextrr(&p, &rr)) > 0) {
|
||||
ret->dnsptr_ptr[c] = sp;
|
||||
cur = rr.dnsrr_dptr;
|
||||
dns_getdn(pkt, &cur, end, ptr, sizeof(ptr));
|
||||
sp += dns_dntop(ptr, sp, DNS_MAXNAME);
|
||||
++c;
|
||||
}
|
||||
dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
|
||||
*result = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr,
|
||||
dns_query_ptr_fn *cbck, void *data) {
|
||||
dnsc_t dn[DNS_A4RSIZE];
|
||||
dns_a4todn(addr, 0, dn, sizeof(dn));
|
||||
return
|
||||
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_PTR, DNS_NOSRCH,
|
||||
dns_parse_ptr, (dns_query_fn *)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_ptr *
|
||||
dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr) {
|
||||
return (struct dns_rr_ptr *)
|
||||
dns_resolve(ctx, dns_submit_a4ptr(ctx, addr, NULL, NULL));
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr,
|
||||
dns_query_ptr_fn *cbck, void *data) {
|
||||
dnsc_t dn[DNS_A6RSIZE];
|
||||
dns_a6todn(addr, 0, dn, sizeof(dn));
|
||||
return
|
||||
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_PTR, DNS_NOSRCH,
|
||||
dns_parse_ptr, (dns_query_fn *)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_ptr *
|
||||
dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr) {
|
||||
return (struct dns_rr_ptr *)
|
||||
dns_resolve(ctx, dns_submit_a6ptr(ctx, addr, NULL, NULL));
|
||||
}
|
||||
155
3rdparty/udns/udns_rr_srv.c
vendored
Normal file
155
3rdparty/udns/udns_rr_srv.c
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/* udns_rr_srv.c
|
||||
parse/query SRV IN (rfc2782) records
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Copyright 2005 Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
|
||||
|
||||
2005-09-11:
|
||||
Changed MX parser file into a SRV parser file
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "udns.h"
|
||||
|
||||
int
|
||||
dns_parse_srv(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
|
||||
void **result) {
|
||||
struct dns_rr_srv *ret;
|
||||
struct dns_parse p;
|
||||
struct dns_rr rr;
|
||||
int r, l;
|
||||
char *sp;
|
||||
dnsc_t srv[DNS_MAXDN];
|
||||
|
||||
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_SRV);
|
||||
|
||||
/* first, validate the answer and count size of the result */
|
||||
l = 0;
|
||||
dns_initparse(&p, qdn, pkt, cur, end);
|
||||
while((r = dns_nextrr(&p, &rr)) > 0) {
|
||||
cur = rr.dnsrr_dptr + 6;
|
||||
r = dns_getdn(pkt, &cur, end, srv, sizeof(srv));
|
||||
if (r <= 0 || cur != rr.dnsrr_dend)
|
||||
return DNS_E_PROTOCOL;
|
||||
l += dns_dntop_size(srv);
|
||||
}
|
||||
if (r < 0)
|
||||
return DNS_E_PROTOCOL;
|
||||
if (!p.dnsp_nrr)
|
||||
return DNS_E_NODATA;
|
||||
|
||||
/* next, allocate and set up result */
|
||||
l += dns_stdrr_size(&p);
|
||||
ret = malloc(sizeof(*ret) + sizeof(struct dns_srv) * p.dnsp_nrr + l);
|
||||
if (!ret)
|
||||
return DNS_E_NOMEM;
|
||||
ret->dnssrv_nrr = p.dnsp_nrr;
|
||||
ret->dnssrv_srv = (struct dns_srv *)(ret+1);
|
||||
|
||||
/* and 3rd, fill in result, finally */
|
||||
sp = (char*)(ret->dnssrv_srv + p.dnsp_nrr);
|
||||
for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) {
|
||||
ret->dnssrv_srv[r].name = sp;
|
||||
cur = rr.dnsrr_dptr;
|
||||
ret->dnssrv_srv[r].priority = dns_get16(cur);
|
||||
ret->dnssrv_srv[r].weight = dns_get16(cur+2);
|
||||
ret->dnssrv_srv[r].port = dns_get16(cur+4);
|
||||
cur += 6;
|
||||
dns_getdn(pkt, &cur, end, srv, sizeof(srv));
|
||||
sp += dns_dntop(srv, sp, DNS_MAXNAME);
|
||||
}
|
||||
dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
|
||||
*result = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add a single service or proto name prepending an undescore (_),
|
||||
* according to rfc2782 rules.
|
||||
* Return 0 or the label length.
|
||||
* Routing assumes dn holds enouth space for a single DN label. */
|
||||
static int add_sname(dnsc_t *dn, const char *sn) {
|
||||
int l = dns_ptodn(sn, 0, dn + 1, DNS_MAXLABEL-1, NULL);
|
||||
if (l <= 1 || l - 2 != dn[1])
|
||||
/* Should we really check if sn is exactly one label? Do we care? */
|
||||
return 0;
|
||||
dn[0] = l - 1;
|
||||
dn[1] = '_';
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Construct a domain name for SRV query from the given name, service and proto.
|
||||
* The code allows any combinations of srv and proto (both are non-NULL,
|
||||
* both NULL, or either one is non-NULL). Whenever it makes any sense or not
|
||||
* is left as an exercise to programmer.
|
||||
* Return negative value on error (malformed query) or addition query flag(s).
|
||||
*/
|
||||
static int
|
||||
build_srv_dn(dnsc_t *dn, const char *name, const char *srv, const char *proto)
|
||||
{
|
||||
int p = 0, l, isabs;
|
||||
if (srv) {
|
||||
l = add_sname(dn + p, srv);
|
||||
if (!l)
|
||||
return -1;
|
||||
p += l;
|
||||
}
|
||||
if (proto) {
|
||||
l = add_sname(dn + p, proto);
|
||||
if (!l)
|
||||
return -1;
|
||||
p += l;
|
||||
}
|
||||
l = dns_ptodn(name, 0, dn + p, DNS_MAXDN - p, &isabs);
|
||||
if (l < 0)
|
||||
return -1;
|
||||
return isabs ? DNS_NOSRCH : 0;
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_srv(struct dns_ctx *ctx,
|
||||
const char *name, const char *srv, const char *proto,
|
||||
int flags, dns_query_srv_fn *cbck, void *data) {
|
||||
dnsc_t dn[DNS_MAXDN];
|
||||
int r = build_srv_dn(dn, name, srv, proto);
|
||||
if (r < 0) {
|
||||
dns_setstatus (ctx, DNS_E_BADQUERY);
|
||||
return NULL;
|
||||
}
|
||||
return
|
||||
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_SRV, flags | r,
|
||||
dns_parse_srv, (dns_query_fn *)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_srv *
|
||||
dns_resolve_srv(struct dns_ctx *ctx,
|
||||
const char *name, const char *srv, const char *proto, int flags)
|
||||
{
|
||||
dnsc_t dn[DNS_MAXDN];
|
||||
int r = build_srv_dn(dn, name, srv, proto);
|
||||
if (r < 0) {
|
||||
dns_setstatus(ctx, DNS_E_BADQUERY);
|
||||
return NULL;
|
||||
}
|
||||
return (struct dns_rr_srv *)
|
||||
dns_resolve_dn(ctx, dn, DNS_C_IN, DNS_T_SRV, flags | r, dns_parse_srv);
|
||||
}
|
||||
98
3rdparty/udns/udns_rr_txt.c
vendored
Normal file
98
3rdparty/udns/udns_rr_txt.c
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/* udns_rr_txt.c
|
||||
parse/query TXT records
|
||||
|
||||
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library, in file named COPYING.LGPL; if not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "udns.h"
|
||||
|
||||
int
|
||||
dns_parse_txt(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
|
||||
void **result) {
|
||||
struct dns_rr_txt *ret;
|
||||
struct dns_parse p;
|
||||
struct dns_rr rr;
|
||||
int r, l;
|
||||
dnsc_t *sp;
|
||||
dnscc_t *cp, *ep;
|
||||
|
||||
assert(dns_get16(cur+0) == DNS_T_TXT);
|
||||
|
||||
/* first, validate the answer and count size of the result */
|
||||
l = 0;
|
||||
dns_initparse(&p, qdn, pkt, cur, end);
|
||||
while((r = dns_nextrr(&p, &rr)) > 0) {
|
||||
cp = rr.dnsrr_dptr; ep = rr.dnsrr_dend;
|
||||
while(cp < ep) {
|
||||
r = *cp++;
|
||||
if (cp + r > ep)
|
||||
return DNS_E_PROTOCOL;
|
||||
l += r;
|
||||
cp += r;
|
||||
}
|
||||
}
|
||||
if (r < 0)
|
||||
return DNS_E_PROTOCOL;
|
||||
if (!p.dnsp_nrr)
|
||||
return DNS_E_NODATA;
|
||||
|
||||
/* next, allocate and set up result */
|
||||
l += (sizeof(struct dns_txt) + 1) * p.dnsp_nrr + dns_stdrr_size(&p);
|
||||
ret = malloc(sizeof(*ret) + l);
|
||||
if (!ret)
|
||||
return DNS_E_NOMEM;
|
||||
ret->dnstxt_nrr = p.dnsp_nrr;
|
||||
ret->dnstxt_txt = (struct dns_txt *)(ret+1);
|
||||
|
||||
/* and 3rd, fill in result, finally */
|
||||
sp = (dnsc_t*)(ret->dnstxt_txt + p.dnsp_nrr);
|
||||
for(dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr) > 0; ++r) {
|
||||
ret->dnstxt_txt[r].txt = sp;
|
||||
cp = rr.dnsrr_dptr; ep = rr.dnsrr_dend;
|
||||
while(cp < ep) {
|
||||
l = *cp++;
|
||||
memcpy(sp, cp, l);
|
||||
sp += l;
|
||||
cp += l;
|
||||
}
|
||||
ret->dnstxt_txt[r].len = sp - ret->dnstxt_txt[r].txt;
|
||||
*sp++ = '\0';
|
||||
}
|
||||
dns_stdrr_finish((struct dns_rr_null *)ret, (char*)sp, &p);
|
||||
*result = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_query *
|
||||
dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags,
|
||||
dns_query_txt_fn *cbck, void *data) {
|
||||
return
|
||||
dns_submit_p(ctx, name, qcls, DNS_T_TXT, flags,
|
||||
dns_parse_txt, (dns_query_fn *)cbck, data);
|
||||
}
|
||||
|
||||
struct dns_rr_txt *
|
||||
dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags) {
|
||||
return (struct dns_rr_txt *)
|
||||
dns_resolve_p(ctx, name, qcls, DNS_T_TXT, flags, dns_parse_txt);
|
||||
}
|
||||
17
3rdparty/utf8/CMakeLists.txt
vendored
Normal file
17
3rdparty/utf8/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
source/utf8.h
|
||||
)
|
||||
|
||||
set(HEADERS_utf8
|
||||
source/utf8/checked.h
|
||||
source/utf8/core.h
|
||||
source/utf8/unchecked.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
)
|
||||
|
||||
simgear_component(utf8 3rdparty/utf8 "${SOURCES}" "${HEADERS}")
|
||||
simgear_component(utf8-internal 3rdparty/utf8/utf8 "" "${HEADERS_utf8}")
|
||||
12
3rdparty/utf8/doc/ReleaseNotes
vendored
Normal file
12
3rdparty/utf8/doc/ReleaseNotes
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
utf8 cpp library
|
||||
Release 2.3.4
|
||||
|
||||
A minor bug fix release. Thanks to all who reported bugs.
|
||||
|
||||
Note: Version 2.3.3 contained a regression, and therefore was removed.
|
||||
|
||||
Changes from version 2.3.2
|
||||
- Bug fix [39]: checked.h Line 273 and unchecked.h Line 182 have an extra ';'
|
||||
- Bug fix [36]: replace_invalid() only works with back_inserter
|
||||
|
||||
Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes
|
||||
1789
3rdparty/utf8/doc/utf8cpp.html
vendored
Normal file
1789
3rdparty/utf8/doc/utf8cpp.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
34
3rdparty/utf8/source/utf8.h
vendored
Normal file
34
3rdparty/utf8/source/utf8.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "utf8/checked.h"
|
||||
#include "utf8/unchecked.h"
|
||||
|
||||
#endif // header guard
|
||||
327
3rdparty/utf8/source/utf8/checked.h
vendored
Normal file
327
3rdparty/utf8/source/utf8/checked.h
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "core.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
// Base for the exceptions that may be thrown from the library
|
||||
class exception : public ::std::exception {
|
||||
};
|
||||
|
||||
// Exceptions that may be thrown from the library functions.
|
||||
class invalid_code_point : public exception {
|
||||
uint32_t cp;
|
||||
public:
|
||||
invalid_code_point(uint32_t cp) : cp(cp) {}
|
||||
virtual const char* what() const throw() { return "Invalid code point"; }
|
||||
uint32_t code_point() const {return cp;}
|
||||
};
|
||||
|
||||
class invalid_utf8 : public exception {
|
||||
uint8_t u8;
|
||||
public:
|
||||
invalid_utf8 (uint8_t u) : u8(u) {}
|
||||
virtual const char* what() const throw() { return "Invalid UTF-8"; }
|
||||
uint8_t utf8_octet() const {return u8;}
|
||||
};
|
||||
|
||||
class invalid_utf16 : public exception {
|
||||
uint16_t u16;
|
||||
public:
|
||||
invalid_utf16 (uint16_t u) : u16(u) {}
|
||||
virtual const char* what() const throw() { return "Invalid UTF-16"; }
|
||||
uint16_t utf16_word() const {return u16;}
|
||||
};
|
||||
|
||||
class not_enough_room : public exception {
|
||||
public:
|
||||
virtual const char* what() const throw() { return "Not enough space"; }
|
||||
};
|
||||
|
||||
/// The library API - functions intended to be called by the users
|
||||
|
||||
template <typename octet_iterator>
|
||||
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||
{
|
||||
if (!utf8::internal::is_code_point_valid(cp))
|
||||
throw invalid_code_point(cp);
|
||||
|
||||
if (cp < 0x80) // one octet
|
||||
*(result++) = static_cast<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
|
||||
{
|
||||
while (start != end) {
|
||||
octet_iterator sequence_start = start;
|
||||
internal::utf_error err_code = utf8::internal::validate_next(start, end);
|
||||
switch (err_code) {
|
||||
case internal::UTF8_OK :
|
||||
for (octet_iterator it = sequence_start; it != start; ++it)
|
||||
*out++ = *it;
|
||||
break;
|
||||
case internal::NOT_ENOUGH_ROOM:
|
||||
throw not_enough_room();
|
||||
case internal::INVALID_LEAD:
|
||||
out = utf8::append (replacement, out);
|
||||
++start;
|
||||
break;
|
||||
case internal::INCOMPLETE_SEQUENCE:
|
||||
case internal::OVERLONG_SEQUENCE:
|
||||
case internal::INVALID_CODE_POINT:
|
||||
out = utf8::append (replacement, out);
|
||||
++start;
|
||||
// just one replacement mark for the sequence
|
||||
while (start != end && utf8::internal::is_trail(*start))
|
||||
++start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
|
||||
{
|
||||
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
|
||||
return utf8::replace_invalid(start, end, out, replacement_marker);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t next(octet_iterator& it, octet_iterator end)
|
||||
{
|
||||
uint32_t cp = 0;
|
||||
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
|
||||
switch (err_code) {
|
||||
case internal::UTF8_OK :
|
||||
break;
|
||||
case internal::NOT_ENOUGH_ROOM :
|
||||
throw not_enough_room();
|
||||
case internal::INVALID_LEAD :
|
||||
case internal::INCOMPLETE_SEQUENCE :
|
||||
case internal::OVERLONG_SEQUENCE :
|
||||
throw invalid_utf8(*it);
|
||||
case internal::INVALID_CODE_POINT :
|
||||
throw invalid_code_point(cp);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return utf8::next(it, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t prior(octet_iterator& it, octet_iterator start)
|
||||
{
|
||||
// can't do much if it == start
|
||||
if (it == start)
|
||||
throw not_enough_room();
|
||||
|
||||
octet_iterator end = it;
|
||||
// Go back until we hit either a lead octet or start
|
||||
while (utf8::internal::is_trail(*(--it)))
|
||||
if (it == start)
|
||||
throw invalid_utf8(*it); // error - no lead byte in the sequence
|
||||
return utf8::peek_next(it, end);
|
||||
}
|
||||
|
||||
/// Deprecated in versions that include "prior"
|
||||
template <typename octet_iterator>
|
||||
uint32_t previous(octet_iterator& it, octet_iterator pass_start)
|
||||
{
|
||||
octet_iterator end = it;
|
||||
while (utf8::internal::is_trail(*(--it)))
|
||||
if (it == pass_start)
|
||||
throw invalid_utf8(*it); // error - no lead byte in the sequence
|
||||
octet_iterator temp = it;
|
||||
return utf8::next(temp, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename distance_type>
|
||||
void advance (octet_iterator& it, distance_type n, octet_iterator end)
|
||||
{
|
||||
for (distance_type i = 0; i < n; ++i)
|
||||
utf8::next(it, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::next(first, last);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::internal::mask16(*start++);
|
||||
// Take care of surrogate pairs first
|
||||
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||
if (start != end) {
|
||||
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||
if (utf8::internal::is_trail_surrogate(trail_surrogate))
|
||||
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||
else
|
||||
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
|
||||
}
|
||||
else
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
}
|
||||
// Lone trail surrogate
|
||||
else if (utf8::internal::is_trail_surrogate(cp))
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
result = utf8::append(cp, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::next(start, end);
|
||||
if (cp > 0xffff) { //make a surrogate pair
|
||||
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
(*result++) = utf8::next(start, end);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The iterator class
|
||||
template <typename octet_iterator>
|
||||
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
|
||||
octet_iterator it;
|
||||
octet_iterator range_start;
|
||||
octet_iterator range_end;
|
||||
public:
|
||||
iterator () {}
|
||||
explicit iterator (const octet_iterator& octet_it,
|
||||
const octet_iterator& range_start,
|
||||
const octet_iterator& range_end) :
|
||||
it(octet_it), range_start(range_start), range_end(range_end)
|
||||
{
|
||||
if (it < range_start || it > range_end)
|
||||
throw std::out_of_range("Invalid utf-8 iterator position");
|
||||
}
|
||||
// the default "big three" are OK
|
||||
octet_iterator base () const { return it; }
|
||||
uint32_t operator * () const
|
||||
{
|
||||
octet_iterator temp = it;
|
||||
return utf8::next(temp, range_end);
|
||||
}
|
||||
bool operator == (const iterator& rhs) const
|
||||
{
|
||||
if (range_start != rhs.range_start || range_end != rhs.range_end)
|
||||
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
|
||||
return (it == rhs.it);
|
||||
}
|
||||
bool operator != (const iterator& rhs) const
|
||||
{
|
||||
return !(operator == (rhs));
|
||||
}
|
||||
iterator& operator ++ ()
|
||||
{
|
||||
utf8::next(it, range_end);
|
||||
return *this;
|
||||
}
|
||||
iterator operator ++ (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::next(it, range_end);
|
||||
return temp;
|
||||
}
|
||||
iterator& operator -- ()
|
||||
{
|
||||
utf8::prior(it, range_start);
|
||||
return *this;
|
||||
}
|
||||
iterator operator -- (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::prior(it, range_start);
|
||||
return temp;
|
||||
}
|
||||
}; // class iterator
|
||||
|
||||
} // namespace utf8
|
||||
|
||||
#endif //header guard
|
||||
|
||||
|
||||
329
3rdparty/utf8/source/utf8/core.h
vendored
Normal file
329
3rdparty/utf8/source/utf8/core.h
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
|
||||
// You may need to change them to match your system.
|
||||
// These typedefs have the same names as ones from cstdint, or boost/cstdint
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
// Helper code - not intended to be directly called by the library users. May be changed at any time
|
||||
namespace internal
|
||||
{
|
||||
// Unicode constants
|
||||
// Leading (high) surrogates: 0xd800 - 0xdbff
|
||||
// Trailing (low) surrogates: 0xdc00 - 0xdfff
|
||||
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
|
||||
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
|
||||
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
|
||||
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
|
||||
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
|
||||
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
|
||||
|
||||
// Maximum valid value for a Unicode code point
|
||||
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
|
||||
|
||||
template<typename octet_type>
|
||||
inline uint8_t mask8(octet_type oc)
|
||||
{
|
||||
return static_cast<uint8_t>(0xff & oc);
|
||||
}
|
||||
template<typename u16_type>
|
||||
inline uint16_t mask16(u16_type oc)
|
||||
{
|
||||
return static_cast<uint16_t>(0xffff & oc);
|
||||
}
|
||||
template<typename octet_type>
|
||||
inline bool is_trail(octet_type oc)
|
||||
{
|
||||
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_lead_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_trail_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u32>
|
||||
inline bool is_code_point_valid(u32 cp)
|
||||
{
|
||||
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline typename std::iterator_traits<octet_iterator>::difference_type
|
||||
sequence_length(octet_iterator lead_it)
|
||||
{
|
||||
uint8_t lead = utf8::internal::mask8(*lead_it);
|
||||
if (lead < 0x80)
|
||||
return 1;
|
||||
else if ((lead >> 5) == 0x6)
|
||||
return 2;
|
||||
else if ((lead >> 4) == 0xe)
|
||||
return 3;
|
||||
else if ((lead >> 3) == 0x1e)
|
||||
return 4;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename octet_difference_type>
|
||||
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
|
||||
{
|
||||
if (cp < 0x80) {
|
||||
if (length != 1)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x800) {
|
||||
if (length != 2)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x10000) {
|
||||
if (length != 3)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
|
||||
|
||||
/// Helper for get_sequence_x
|
||||
template <typename octet_iterator>
|
||||
utf_error increase_safely(octet_iterator& it, octet_iterator end)
|
||||
{
|
||||
if (++it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
if (!utf8::internal::is_trail(*it))
|
||||
return INCOMPLETE_SEQUENCE;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
|
||||
|
||||
/// get_sequence_x functions decode utf-8 sequences of the length x
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
// Save the original value of it so we can go back in case of failure
|
||||
// Of course, it does not make much sense with i.e. stream iterators
|
||||
octet_iterator original_it = it;
|
||||
|
||||
uint32_t cp = 0;
|
||||
// Determine the sequence length based on the lead octet
|
||||
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
|
||||
const octet_difference_type length = utf8::internal::sequence_length(it);
|
||||
|
||||
// Get trail octets and calculate the code point
|
||||
utf_error err = UTF8_OK;
|
||||
switch (length) {
|
||||
case 0:
|
||||
return INVALID_LEAD;
|
||||
case 1:
|
||||
err = utf8::internal::get_sequence_1(it, end, cp);
|
||||
break;
|
||||
case 2:
|
||||
err = utf8::internal::get_sequence_2(it, end, cp);
|
||||
break;
|
||||
case 3:
|
||||
err = utf8::internal::get_sequence_3(it, end, cp);
|
||||
break;
|
||||
case 4:
|
||||
err = utf8::internal::get_sequence_4(it, end, cp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == UTF8_OK) {
|
||||
// Decoding succeeded. Now, security checks...
|
||||
if (utf8::internal::is_code_point_valid(cp)) {
|
||||
if (!utf8::internal::is_overlong_sequence(cp, length)){
|
||||
// Passed! Return here.
|
||||
code_point = cp;
|
||||
++it;
|
||||
return UTF8_OK;
|
||||
}
|
||||
else
|
||||
err = OVERLONG_SEQUENCE;
|
||||
}
|
||||
else
|
||||
err = INVALID_CODE_POINT;
|
||||
}
|
||||
|
||||
// Failure branch - restore the original value of the iterator
|
||||
it = original_it;
|
||||
return err;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
|
||||
uint32_t ignored;
|
||||
return utf8::internal::validate_next(it, end, ignored);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// The library API - functions intended to be called by the users
|
||||
|
||||
// Byte order mark
|
||||
const uint8_t bom[] = {0xef, 0xbb, 0xbf};
|
||||
|
||||
template <typename octet_iterator>
|
||||
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
octet_iterator result = start;
|
||||
while (result != end) {
|
||||
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
|
||||
if (err_code != internal::UTF8_OK)
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool is_valid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
return (utf8::find_invalid(start, end) == end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return (
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
|
||||
);
|
||||
}
|
||||
|
||||
//Deprecated in release 2.3
|
||||
template <typename octet_iterator>
|
||||
inline bool is_bom (octet_iterator it)
|
||||
{
|
||||
return (
|
||||
(utf8::internal::mask8(*it++)) == bom[0] &&
|
||||
(utf8::internal::mask8(*it++)) == bom[1] &&
|
||||
(utf8::internal::mask8(*it)) == bom[2]
|
||||
);
|
||||
}
|
||||
} // namespace utf8
|
||||
|
||||
#endif // header guard
|
||||
|
||||
|
||||
228
3rdparty/utf8/source/utf8/unchecked.h
vendored
Normal file
228
3rdparty/utf8/source/utf8/unchecked.h
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "core.h"
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
namespace unchecked
|
||||
{
|
||||
template <typename octet_iterator>
|
||||
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||
{
|
||||
if (cp < 0x80) // one octet
|
||||
*(result++) = static_cast<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t next(octet_iterator& it)
|
||||
{
|
||||
uint32_t cp = utf8::internal::mask8(*it);
|
||||
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
|
||||
switch (length) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
it++;
|
||||
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
break;
|
||||
case 3:
|
||||
++it;
|
||||
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
++it;
|
||||
cp += (*it) & 0x3f;
|
||||
break;
|
||||
case 4:
|
||||
++it;
|
||||
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
++it;
|
||||
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
++it;
|
||||
cp += (*it) & 0x3f;
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
return cp;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it)
|
||||
{
|
||||
return utf8::unchecked::next(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t prior(octet_iterator& it)
|
||||
{
|
||||
while (utf8::internal::is_trail(*(--it))) ;
|
||||
octet_iterator temp = it;
|
||||
return utf8::unchecked::next(temp);
|
||||
}
|
||||
|
||||
// Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
|
||||
template <typename octet_iterator>
|
||||
inline uint32_t previous(octet_iterator& it)
|
||||
{
|
||||
return utf8::unchecked::prior(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename distance_type>
|
||||
void advance (octet_iterator& it, distance_type n)
|
||||
{
|
||||
for (distance_type i = 0; i < n; ++i)
|
||||
utf8::unchecked::next(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::unchecked::next(first);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::internal::mask16(*start++);
|
||||
// Take care of surrogate pairs first
|
||||
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||
}
|
||||
result = utf8::unchecked::append(cp, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||
{
|
||||
while (start < end) {
|
||||
uint32_t cp = utf8::unchecked::next(start);
|
||||
if (cp > 0xffff) { //make a surrogate pair
|
||||
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::unchecked::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||
{
|
||||
while (start < end)
|
||||
(*result++) = utf8::unchecked::next(start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The iterator class
|
||||
template <typename octet_iterator>
|
||||
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
|
||||
octet_iterator it;
|
||||
public:
|
||||
iterator () {}
|
||||
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
|
||||
// the default "big three" are OK
|
||||
octet_iterator base () const { return it; }
|
||||
uint32_t operator * () const
|
||||
{
|
||||
octet_iterator temp = it;
|
||||
return utf8::unchecked::next(temp);
|
||||
}
|
||||
bool operator == (const iterator& rhs) const
|
||||
{
|
||||
return (it == rhs.it);
|
||||
}
|
||||
bool operator != (const iterator& rhs) const
|
||||
{
|
||||
return !(operator == (rhs));
|
||||
}
|
||||
iterator& operator ++ ()
|
||||
{
|
||||
::std::advance(it, utf8::internal::sequence_length(it));
|
||||
return *this;
|
||||
}
|
||||
iterator operator ++ (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
::std::advance(it, utf8::internal::sequence_length(it));
|
||||
return temp;
|
||||
}
|
||||
iterator& operator -- ()
|
||||
{
|
||||
utf8::unchecked::prior(it);
|
||||
return *this;
|
||||
}
|
||||
iterator operator -- (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::unchecked::prior(it);
|
||||
return temp;
|
||||
}
|
||||
}; // class iterator
|
||||
|
||||
} // namespace utf8::unchecked
|
||||
} // namespace utf8
|
||||
|
||||
|
||||
#endif // header guard
|
||||
|
||||
157
CMakeLists.txt
157
CMakeLists.txt
@@ -1,8 +1,26 @@
|
||||
cmake_minimum_required (VERSION 2.6.4)
|
||||
cmake_minimum_required (VERSION 2.8.11)
|
||||
|
||||
if(COMMAND cmake_policy)
|
||||
if(POLICY CMP0054)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif()
|
||||
if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include (CheckFunctionExists)
|
||||
include (CheckIncludeFile)
|
||||
include (CheckLibraryExists)
|
||||
include (CheckCXXSourceCompiles)
|
||||
include (CheckCXXCompilerFlag)
|
||||
include (GenerateExportHeader)
|
||||
|
||||
# using 10.7 because boost requires libc++ and 10.6 doesn't include it
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
|
||||
|
||||
# only relevant for building shared libs but let's set it regardless
|
||||
set(CMAKE_OSX_RPATH 1)
|
||||
|
||||
project(SimGear)
|
||||
|
||||
@@ -34,7 +52,7 @@ SET(CPACK_INSTALL_CMAKE_PROJECTS ${CMAKE_CURRENT_BINARY_DIR};SimGear;ALL;/)
|
||||
|
||||
# split version string into components, note CMAKE_MATCH_0 is the entire regexp match
|
||||
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CPACK_PACKAGE_VERSION ${SIMGEAR_VERSION} )
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
|
||||
@@ -62,12 +80,7 @@ endif(NOT CMAKE_BUILD_TYPE)
|
||||
# Determine name of library installation directory, i.e. "lib" vs "lib64", which
|
||||
# differs between all Debian-based vs all other Linux distros.
|
||||
# See cmake bug #11964, http://cmake.org/gitweb?p=cmake.git;a=commit;h=126c993d
|
||||
# GNUInstallDirs requires CMake >= 2.8.5, use own file for older cmake
|
||||
if(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
|
||||
include(GNUInstallDirs)
|
||||
else(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
|
||||
include(OldGNUInstallDirs)
|
||||
endif(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
|
||||
include(GNUInstallDirs)
|
||||
message(STATUS "Library installation directory: ${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
#####################################################################################
|
||||
@@ -100,11 +113,11 @@ set(SYSTEM_EXPAT OFF)
|
||||
endif()
|
||||
|
||||
option(SIMGEAR_HEADLESS "Set to ON to build SimGear without GUI/graphics support" OFF)
|
||||
option(JPEG_FACTORY "Enable JPEG-factory support" OFF)
|
||||
option(ENABLE_RTI "Set to ON to build SimGear with RTI support" OFF)
|
||||
option(ENABLE_TESTS "Set to OFF to disable building SimGear's test applications" ON)
|
||||
option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support" ON)
|
||||
option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON)
|
||||
option(ENABLE_DNS "Set to ON to use udns library and DNS service resolver" ON)
|
||||
|
||||
if (MSVC)
|
||||
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
|
||||
@@ -161,11 +174,24 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
|
||||
endif (MSVC AND MSVC_3RDPARTY_ROOT)
|
||||
|
||||
if(APPLE)
|
||||
find_library(CORE_SERVICES_LIBRARY CoreServices)
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
|
||||
# this should be handled by setting CMAKE_OSX_DEPLOYMENT_TARGET
|
||||
# but it's not working reliably, so forcing it for now
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.7")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR
|
||||
${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
# Somehow this only works if included before searching for Boost...
|
||||
include(BoostTestTargets)
|
||||
|
||||
find_package(Boost REQUIRED)
|
||||
set (BOOST_CXX_FLAGS "-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION -DBOOST_BIMAP_DISABLE_SERIALIZATION")
|
||||
set (BOOST_CXX_FLAGS "-DBOOST_BIMAP_DISABLE_SERIALIZATION")
|
||||
|
||||
if(SIMGEAR_HEADLESS)
|
||||
message(STATUS "SimGear mode: HEADLESS")
|
||||
@@ -173,25 +199,17 @@ if(SIMGEAR_HEADLESS)
|
||||
else()
|
||||
message(STATUS "SimGear mode: NORMAL")
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
|
||||
if (ENABLE_SOUND)
|
||||
find_package(OpenAL REQUIRED)
|
||||
message(STATUS "Sound support: ENABLED")
|
||||
endif(ENABLE_SOUND)
|
||||
|
||||
find_package(OpenSceneGraph 3.0.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgUtil)
|
||||
|
||||
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil)
|
||||
endif(SIMGEAR_HEADLESS)
|
||||
|
||||
if(JPEG_FACTORY)
|
||||
message(STATUS "JPEG-factory: ENABLED")
|
||||
find_package(JPEG REQUIRED)
|
||||
include_directories(${JPEG_INCLUDE_DIR})
|
||||
else()
|
||||
message(STATUS "JPEG-factory: DISABLED")
|
||||
endif(JPEG_FACTORY)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(CURL REQUIRED)
|
||||
|
||||
if (SYSTEM_EXPAT)
|
||||
message(STATUS "Requested to use system Expat library, forcing SIMGEAR_SHARED to true")
|
||||
@@ -203,8 +221,8 @@ else()
|
||||
# XML_STATIC is important to avoid sg_expat_external.h
|
||||
# declaring symbols as declspec(import)
|
||||
add_definitions(-DHAVE_EXPAT_CONFIG_H -DXML_STATIC)
|
||||
set(EXPAT_INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/3rdparty/expat
|
||||
set(EXPAT_INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/3rdparty/expat
|
||||
${PROJECT_BINARY_DIR}/3rdparty/expat)
|
||||
endif(SYSTEM_EXPAT)
|
||||
|
||||
@@ -269,7 +287,9 @@ check_cxx_source_compiles(
|
||||
|
||||
if(HAVE_DLFCN_H)
|
||||
check_library_exists(dl dlerror "" HAVE_DL)
|
||||
set(DL_LIBRARY "dl")
|
||||
if(HAVE_DL)
|
||||
set(DL_LIBRARY "dl")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "add a postfix, usually 'd' on windows")
|
||||
@@ -279,13 +299,13 @@ SET(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "add a postfix, usually empty on wi
|
||||
|
||||
# isnan might not be real symbol, so can't check using function_exists
|
||||
check_cxx_source_compiles(
|
||||
"#include <cmath>
|
||||
void f() { isnan(0.0);} "
|
||||
"#include <cmath>
|
||||
int main() { return isnan(0.0);} "
|
||||
HAVE_ISNAN)
|
||||
|
||||
check_cxx_source_compiles(
|
||||
"#include <cmath>
|
||||
void f() { std::isnan(0.0);} "
|
||||
"#include <cmath>
|
||||
int main() { return std::isnan(0.0);} "
|
||||
HAVE_STD_ISNAN)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
@@ -301,8 +321,12 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual")
|
||||
set(WARNING_FLAGS_C "-Wall")
|
||||
# Boost redeclares class members
|
||||
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual -Wno-redeclared-class-member")
|
||||
set(WARNING_FLAGS_C "-Wall")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
@@ -324,16 +348,16 @@ if(WIN32)
|
||||
# foreach(warning 4244 4251 4267 4275 4290 4786 4305 4996)
|
||||
# SET(WARNING_FLAGS "${WARNING_FLAGS} /wd${warning}")
|
||||
# endforeach(warning)
|
||||
|
||||
|
||||
set(MSVC_FLAGS "-DWIN32 -DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS /wd4996 /wd4250 -Dstrdup=_strdup")
|
||||
if (${MSVC_VERSION} GREATER 1599)
|
||||
set( MSVC_LD_FLAGS "/FORCE:MULTIPLE" )
|
||||
endif (${MSVC_VERSION} GREATER 1599)
|
||||
endif(MSVC)
|
||||
|
||||
|
||||
# assumed on Windows
|
||||
set(HAVE_GETLOCALTIME 1)
|
||||
|
||||
|
||||
set( WINSOCK_LIBRARY "ws2_32.lib" )
|
||||
set( RT_LIBRARY "winmm" )
|
||||
endif(WIN32)
|
||||
@@ -342,14 +366,17 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
|
||||
include_directories(${PROJECT_BINARY_DIR}/simgear)
|
||||
# use BEFORE to ensure local directories are used first,
|
||||
# ahead of system-installed libs
|
||||
include_directories(BEFORE ${PROJECT_SOURCE_DIR})
|
||||
include_directories(BEFORE ${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
|
||||
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
|
||||
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
${CURL_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
@@ -378,7 +405,8 @@ set(TEST_LIBS_INTERNAL_CORE
|
||||
${WINSOCK_LIBRARY}
|
||||
${RT_LIBRARY}
|
||||
${DL_LIBRARY}
|
||||
${CORE_SERVICES_LIBRARY})
|
||||
${COCOA_LIBRARY}
|
||||
${CURL_LIBRARIES})
|
||||
set(TEST_LIBS SimGearCore ${TEST_LIBS_INTERNAL_CORE})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
@@ -387,9 +415,52 @@ endif()
|
||||
|
||||
install (FILES ${PROJECT_BINARY_DIR}/simgear/simgear_config.h DESTINATION include/simgear/)
|
||||
|
||||
include_directories(3rdparty/utf8/source)
|
||||
if (ENABLE_DNS)
|
||||
message(STATUS "DNS resolver: ENABLED")
|
||||
include_directories(3rdparty/udns)
|
||||
else()
|
||||
message(STATUS "DNS resolver: DISABLED")
|
||||
endif()
|
||||
|
||||
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(simgear)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
### Export stuff, see https://cmake.org/cmake/help/v3.2/manual/cmake-packages.7.html#creating-packages
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
generate_export_header(SimGearCore)
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
generate_export_header(SimGearScene)
|
||||
endif()
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
|
||||
VERSION ${SIMGEAR_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
configure_file(SimGearConfig.cmake.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
set(ConfigPackageLocation lib/cmake/SimGear)
|
||||
install(EXPORT SimGearTargets
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
### uninstall target
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -399,5 +470,3 @@ CONFIGURE_FILE(
|
||||
IMMEDIATE @ONLY)
|
||||
ADD_CUSTOM_TARGET(uninstall
|
||||
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||
|
||||
|
||||
|
||||
256
CMakeModules/BoostTestTargets.cmake
Normal file
256
CMakeModules/BoostTestTargets.cmake
Normal file
@@ -0,0 +1,256 @@
|
||||
# - Add tests using boost::test
|
||||
#
|
||||
# Add this line to your test files in place of including a basic boost test header:
|
||||
# #include <BoostTestTargetConfig.h>
|
||||
#
|
||||
# If you cannot do that and must use the included form for a given test,
|
||||
# include the line
|
||||
# // OVERRIDE_BOOST_TEST_INCLUDED_WARNING
|
||||
# in the same file with the boost test include.
|
||||
#
|
||||
# include(BoostTestTargets)
|
||||
# add_boost_test(<testdriver_name> SOURCES <source1> [<more sources...>]
|
||||
# [FAIL_REGULAR_EXPRESSION <additional fail regex>]
|
||||
# [LAUNCHER <generic launcher script>]
|
||||
# [LIBRARIES <library> [<library>...]]
|
||||
# [RESOURCES <resource> [<resource>...]]
|
||||
# [TESTS <testcasename> [<testcasename>...]])
|
||||
#
|
||||
# If for some reason you need access to the executable target created,
|
||||
# it can be found in ${${testdriver_name}_TARGET_NAME} as specified when
|
||||
# you called add_boost_test
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Requires:
|
||||
# GetForceIncludeDefinitions
|
||||
# CopyResourcesToBuildTree
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
if(__add_boost_test)
|
||||
return()
|
||||
endif()
|
||||
set(__add_boost_test YES)
|
||||
|
||||
set(BOOST_TEST_TARGET_PREFIX "test")
|
||||
|
||||
if(NOT Boost_FOUND)
|
||||
find_package(Boost 1.34.0 QUIET)
|
||||
endif()
|
||||
if("${Boost_VERSION}0" LESS "1034000")
|
||||
set(_shared_msg
|
||||
"NOTE: boost::test-based targets and tests cannot "
|
||||
"be added: boost >= 1.34.0 required but not found. "
|
||||
"(found: '${Boost_VERSION}'; want >=103400) ")
|
||||
if(ENABLE_TESTS)
|
||||
message(FATAL_ERROR
|
||||
${_shared_msg}
|
||||
"You may disable ENABLE_TESTS to continue without the "
|
||||
"tests.")
|
||||
else()
|
||||
message(STATUS
|
||||
${_shared_msg}
|
||||
"ENABLE_TESTS disabled, so continuing anyway.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(GetForceIncludeDefinitions)
|
||||
include(CopyResourcesToBuildTree)
|
||||
|
||||
if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
|
||||
set(_boosttesttargets_libs)
|
||||
set(_boostConfig "BoostTestTargetsIncluded.h")
|
||||
if(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
|
||||
find_package(Boost 1.34.0 QUIET COMPONENTS unit_test_framework)
|
||||
endif()
|
||||
if(Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
|
||||
set(_boosttesttargets_libs "${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}")
|
||||
if(Boost_USE_STATIC_LIBS)
|
||||
set(_boostConfig "BoostTestTargetsStatic.h")
|
||||
else()
|
||||
set(_boostConfig "BoostTestTargetsDynamic.h")
|
||||
endif()
|
||||
endif()
|
||||
get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
configure_file("${_moddir}/${_boostConfig}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h"
|
||||
COPYONLY)
|
||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
|
||||
function(add_boost_test _name)
|
||||
if(NOT ENABLE_TESTS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# parse arguments
|
||||
set(_nowhere)
|
||||
set(_curdest _nowhere)
|
||||
set(_val_args
|
||||
SOURCES
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
LAUNCHER
|
||||
LIBRARIES
|
||||
RESOURCES
|
||||
TESTS)
|
||||
set(_bool_args
|
||||
USE_COMPILED_LIBRARY)
|
||||
foreach(_arg ${_val_args} ${_bool_args})
|
||||
set(${_arg})
|
||||
endforeach()
|
||||
foreach(_element ${ARGN})
|
||||
list(FIND _val_args "${_element}" _val_arg_find)
|
||||
list(FIND _bool_args "${_element}" _bool_arg_find)
|
||||
if("${_val_arg_find}" GREATER "-1")
|
||||
set(_curdest "${_element}")
|
||||
elseif("${_bool_arg_find}" GREATER "-1")
|
||||
set("${_element}" ON)
|
||||
set(_curdest _nowhere)
|
||||
else()
|
||||
list(APPEND ${_curdest} "${_element}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(_nowhere)
|
||||
message(FATAL_ERROR "Syntax error in use of add_boost_test!")
|
||||
endif()
|
||||
|
||||
if(NOT SOURCES)
|
||||
message(FATAL_ERROR
|
||||
"Syntax error in use of add_boost_test: at least one source file required!")
|
||||
endif()
|
||||
|
||||
if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
|
||||
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
set(includeType)
|
||||
foreach(src ${SOURCES})
|
||||
file(READ ${src} thefile)
|
||||
if("${thefile}" MATCHES ".*BoostTestTargetConfig.h.*")
|
||||
set(includeType CONFIGURED)
|
||||
set(includeFileLoc ${src})
|
||||
break()
|
||||
elseif("${thefile}" MATCHES ".*boost/test/included/unit_test.hpp.*")
|
||||
set(includeType INCLUDED)
|
||||
set(includeFileLoc ${src})
|
||||
set(_boosttesttargets_libs) # clear this out - linking would be a bad idea
|
||||
if(NOT
|
||||
"${thefile}"
|
||||
MATCHES
|
||||
".*OVERRIDE_BOOST_TEST_INCLUDED_WARNING.*")
|
||||
message("Please replace the include line in ${src} with this alternate include line instead:")
|
||||
message(" \#include <BoostTestTargetConfig.h>")
|
||||
message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)")
|
||||
endif()
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT _boostTestTargetsNagged${_name} STREQUAL "${includeType}")
|
||||
if("includeType" STREQUAL "CONFIGURED")
|
||||
message(STATUS
|
||||
"Test '${_name}' uses the CMake-configurable form of the boost test framework - congrats! (Including File: ${includeFileLoc})")
|
||||
elseif("${includeType}" STREQUAL "INCLUDED")
|
||||
message("In test '${_name}': ${includeFileLoc} uses the 'included' form of the boost unit test framework.")
|
||||
else()
|
||||
message("In test '${_name}': Didn't detect the CMake-configurable boost test include.")
|
||||
message("Please replace your existing boost test include in that test with the following:")
|
||||
message(" \#include <BoostTestTargetConfig.h>")
|
||||
message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)")
|
||||
endif()
|
||||
endif()
|
||||
set(_boostTestTargetsNagged${_name}
|
||||
"${includeType}"
|
||||
CACHE
|
||||
INTERNAL
|
||||
""
|
||||
FORCE)
|
||||
|
||||
|
||||
if(RESOURCES)
|
||||
list(APPEND SOURCES ${RESOURCES})
|
||||
endif()
|
||||
|
||||
# Generate a unique target name, using the relative binary dir
|
||||
# and provided name. (transform all / into _ and remove all other
|
||||
# non-alphabet characters)
|
||||
file(RELATIVE_PATH
|
||||
targetpath
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
||||
string(REGEX REPLACE "[^A-Za-z/_]" "" targetpath "${targetpath}")
|
||||
string(REPLACE "/" "_" targetpath "${targetpath}")
|
||||
|
||||
set(_target_name ${BOOST_TEST_TARGET_PREFIX}-${targetpath}-${_name})
|
||||
set(${_name}_TARGET_NAME "${_target_name}" PARENT_SCOPE)
|
||||
|
||||
# Build the test.
|
||||
add_executable(${_target_name} ${SOURCES})
|
||||
|
||||
list(APPEND LIBRARIES ${_boosttesttargets_libs})
|
||||
|
||||
if(LIBRARIES)
|
||||
target_link_libraries(${_target_name} ${LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(RESOURCES)
|
||||
set_property(TARGET ${_target_name} PROPERTY RESOURCE ${RESOURCES})
|
||||
copy_resources_to_build_tree(${_target_name})
|
||||
endif()
|
||||
|
||||
if(NOT Boost_TEST_FLAGS)
|
||||
# set(Boost_TEST_FLAGS --catch_system_error=yes --output_format=XML)
|
||||
set(Boost_TEST_FLAGS --catch_system_error=yes)
|
||||
endif()
|
||||
|
||||
# TODO: Figure out why only recent boost handles individual test running properly
|
||||
|
||||
if(LAUNCHER)
|
||||
set(_test_command ${LAUNCHER} "\$<TARGET_FILE:${_target_name}>")
|
||||
else()
|
||||
set(_test_command ${_target_name})
|
||||
endif()
|
||||
|
||||
if(TESTS AND ( "${Boost_VERSION}" VERSION_GREATER "103799" ))
|
||||
foreach(_test ${TESTS})
|
||||
add_test(
|
||||
${_name}-${_test}
|
||||
${_test_command} --run_test=${_test} ${Boost_TEST_FLAGS}
|
||||
)
|
||||
if(FAIL_REGULAR_EXPRESSION)
|
||||
set_tests_properties(${_name}-${_test}
|
||||
PROPERTIES
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${FAIL_REGULAR_EXPRESSION}")
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
add_test(
|
||||
${_name}-boost_test
|
||||
${_test_command} ${Boost_TEST_FLAGS}
|
||||
)
|
||||
if(FAIL_REGULAR_EXPRESSION)
|
||||
set_tests_properties(${_name}-boost_test
|
||||
PROPERTIES
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${FAIL_REGULAR_EXPRESSION}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# CppCheck the test if we can.
|
||||
if(COMMAND add_cppcheck)
|
||||
add_cppcheck(${_target_name} STYLE UNUSED_FUNCTIONS)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endfunction()
|
||||
8
CMakeModules/BoostTestTargetsDynamic.h
Normal file
8
CMakeModules/BoostTestTargetsDynamic.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// Small header computed by CMake to set up boost test.
|
||||
// include AFTER #define BOOST_TEST_MODULE whatever
|
||||
// but before any other boost test includes.
|
||||
|
||||
// Using the Boost UTF dynamic library
|
||||
|
||||
#define BOOST_TEST_DYN_LINK
|
||||
#include <boost/test/unit_test.hpp>
|
||||
7
CMakeModules/BoostTestTargetsIncluded.h
Normal file
7
CMakeModules/BoostTestTargetsIncluded.h
Normal file
@@ -0,0 +1,7 @@
|
||||
// Small header computed by CMake to set up boost test.
|
||||
// include AFTER #define BOOST_TEST_MODULE whatever
|
||||
// but before any other boost test includes.
|
||||
|
||||
// Using the Boost UTF included framework
|
||||
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
7
CMakeModules/BoostTestTargetsStatic.h
Normal file
7
CMakeModules/BoostTestTargetsStatic.h
Normal file
@@ -0,0 +1,7 @@
|
||||
// Small header computed by CMake to set up boost test.
|
||||
// include AFTER #define BOOST_TEST_MODULE whatever
|
||||
// but before any other boost test includes.
|
||||
|
||||
// Using the Boost UTF static library
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
83
CMakeModules/CopyResourcesToBuildTree.cmake
Normal file
83
CMakeModules/CopyResourcesToBuildTree.cmake
Normal file
@@ -0,0 +1,83 @@
|
||||
# - Copy the resources your app needs to the build tree.
|
||||
#
|
||||
# copy_resources_to_build_tree(<target_name>)
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
if(__copy_resources_to_build_tree)
|
||||
return()
|
||||
endif()
|
||||
set(__copy_resources_to_build_tree YES)
|
||||
|
||||
function(copy_resources_to_build_tree _target)
|
||||
get_target_property(_resources ${_target} RESOURCE)
|
||||
if(NOT _resources)
|
||||
# Bail if no resources
|
||||
message(STATUS
|
||||
"Told to copy resources for target ${_target}, but "
|
||||
"no resources are set!")
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(_path ${_target} LOCATION)
|
||||
get_filename_component(_path "${_path}" PATH)
|
||||
|
||||
if(NOT MSVC AND NOT "${CMAKE_GENERATOR}" MATCHES "Makefiles")
|
||||
foreach(_config ${CMAKE_CONFIGURATION_TYPES})
|
||||
get_target_property(_path${_config} ${_target} LOCATION_${_config})
|
||||
get_filename_component(_path${_config} "${_path${_config}}" PATH)
|
||||
add_custom_command(TARGET ${_target}
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
ARGS -E make_directory "${_path${_config}}/"
|
||||
COMMENT "Creating directory ${_path${_config}}/")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
foreach(_res ${_resources})
|
||||
if(NOT IS_ABSOLUTE "${_res}")
|
||||
get_filename_component(_res "${_res}" ABSOLUTE)
|
||||
endif()
|
||||
get_filename_component(_name "${_res}" NAME)
|
||||
|
||||
if(MSVC)
|
||||
# Working dir is solution file dir, not exe file dir.
|
||||
add_custom_command(TARGET ${_target}
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
ARGS -E copy "${_res}" "${CMAKE_BINARY_DIR}/"
|
||||
COMMENT "Copying ${_name} to ${CMAKE_BINARY_DIR}/ for MSVC")
|
||||
else()
|
||||
if("${CMAKE_GENERATOR}" MATCHES "Makefiles")
|
||||
add_custom_command(TARGET ${_target}
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
ARGS -E copy "${_res}" "${_path}/"
|
||||
COMMENT "Copying ${_name} to ${_path}/")
|
||||
else()
|
||||
foreach(_config ${CMAKE_CONFIGURATION_TYPES})
|
||||
add_custom_command(TARGET ${_target}
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
ARGS -E copy "${_res}" "${_path${_config}}"
|
||||
COMMENT "Copying ${_name} to ${_path${_config}}")
|
||||
endforeach()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
44
CMakeModules/GetForceIncludeDefinitions.cmake
Normal file
44
CMakeModules/GetForceIncludeDefinitions.cmake
Normal file
@@ -0,0 +1,44 @@
|
||||
# - Get the platform-appropriate flags to add to force inclusion of a file
|
||||
#
|
||||
# The most common use of this is to use a generated config.h-type file
|
||||
# placed out of the source tree in all files.
|
||||
#
|
||||
# get_force_include_definitions(var forcedincludefiles...) -
|
||||
# where var is the name of your desired output variable, and everything
|
||||
# else is a source file to forcibly include.
|
||||
# a list item to be filtered.
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
if(__get_force_include_definitions)
|
||||
return()
|
||||
endif()
|
||||
set(__get_force_include_definitions YES)
|
||||
|
||||
function(get_force_include_definitions var)
|
||||
set(_flagprefix)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(_flag "-include")
|
||||
elseif(MSVC)
|
||||
set(_flag "/FI")
|
||||
else()
|
||||
message(SEND_ERROR "You don't seem to be using MSVC or GCC, but")
|
||||
message(SEND_ERROR "the project called get_force_include_definitions.")
|
||||
message(SEND_ERROR "Contact this project with the name of your")
|
||||
message(FATAL_ERROR "compiler and preferably the flag to force includes")
|
||||
endif()
|
||||
|
||||
set(_out)
|
||||
foreach(_item ${ARGN})
|
||||
list(APPEND _out "${_flag} \"${_item}\"")
|
||||
endforeach()
|
||||
set(${var} "${_out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -1,182 +0,0 @@
|
||||
# - Define GNU standard installation directories
|
||||
# Provides install directory variables as defined for GNU software:
|
||||
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
|
||||
# Inclusion of this module defines the following variables:
|
||||
# CMAKE_INSTALL_<dir> - destination for files of a given type
|
||||
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
|
||||
# where <dir> is one of:
|
||||
# BINDIR - user executables (bin)
|
||||
# SBINDIR - system admin executables (sbin)
|
||||
# LIBEXECDIR - program executables (libexec)
|
||||
# SYSCONFDIR - read-only single-machine data (etc)
|
||||
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
|
||||
# LOCALSTATEDIR - modifiable single-machine data (var)
|
||||
# LIBDIR - object code libraries (lib or lib64)
|
||||
# INCLUDEDIR - C header files (include)
|
||||
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
|
||||
# DATAROOTDIR - read-only architecture-independent data root (share)
|
||||
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
|
||||
# INFODIR - info documentation (DATAROOTDIR/info)
|
||||
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
|
||||
# MANDIR - man documentation (DATAROOTDIR/man)
|
||||
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
|
||||
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
|
||||
# install() commands for the corresponding file type. If the includer does
|
||||
# not define a value the above-shown default will be used and the value will
|
||||
# appear in the cache for editing by the user.
|
||||
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
|
||||
# from the corresponding destination by prepending (if necessary) the value
|
||||
# of CMAKE_INSTALL_PREFIX.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
|
||||
# Copyright 2011 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# Installation directories
|
||||
#
|
||||
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
|
||||
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
|
||||
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
|
||||
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
|
||||
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
|
||||
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
|
||||
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||
set(_LIBDIR_DEFAULT "lib")
|
||||
# Override this default 'lib' with 'lib64' iff:
|
||||
# - we are on Linux system but NOT cross-compiling
|
||||
# - we are NOT on debian
|
||||
# - we are on a 64 bits system
|
||||
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
|
||||
# Note that the future of multi-arch handling may be even
|
||||
# more complicated than that: http://wiki.debian.org/Multiarch
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
|
||||
AND NOT CMAKE_CROSSCOMPILING
|
||||
AND NOT EXISTS "/etc/debian_version")
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||
message(AUTHOR_WARNING
|
||||
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
|
||||
"Please enable at least one language before including GNUInstallDirs.")
|
||||
else()
|
||||
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(_LIBDIR_DEFAULT "lib64")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
|
||||
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
|
||||
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
|
||||
# the cache and store the defaults in local variables if the cache values are
|
||||
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
|
||||
|
||||
if(NOT CMAKE_INSTALL_DATADIR)
|
||||
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
|
||||
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_INFODIR)
|
||||
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
|
||||
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_LOCALEDIR)
|
||||
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
|
||||
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_MANDIR)
|
||||
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
|
||||
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_DOCDIR)
|
||||
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
|
||||
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
mark_as_advanced(
|
||||
CMAKE_INSTALL_BINDIR
|
||||
CMAKE_INSTALL_SBINDIR
|
||||
CMAKE_INSTALL_LIBEXECDIR
|
||||
CMAKE_INSTALL_SYSCONFDIR
|
||||
CMAKE_INSTALL_SHAREDSTATEDIR
|
||||
CMAKE_INSTALL_LOCALSTATEDIR
|
||||
CMAKE_INSTALL_LIBDIR
|
||||
CMAKE_INSTALL_INCLUDEDIR
|
||||
CMAKE_INSTALL_OLDINCLUDEDIR
|
||||
CMAKE_INSTALL_DATAROOTDIR
|
||||
CMAKE_INSTALL_DATADIR
|
||||
CMAKE_INSTALL_INFODIR
|
||||
CMAKE_INSTALL_LOCALEDIR
|
||||
CMAKE_INSTALL_MANDIR
|
||||
CMAKE_INSTALL_DOCDIR
|
||||
)
|
||||
|
||||
# Result directories
|
||||
#
|
||||
foreach(dir
|
||||
BINDIR
|
||||
SBINDIR
|
||||
LIBEXECDIR
|
||||
SYSCONFDIR
|
||||
SHAREDSTATEDIR
|
||||
LOCALSTATEDIR
|
||||
LIBDIR
|
||||
INCLUDEDIR
|
||||
OLDINCLUDEDIR
|
||||
DATAROOTDIR
|
||||
DATADIR
|
||||
INFODIR
|
||||
LOCALEDIR
|
||||
MANDIR
|
||||
DOCDIR
|
||||
)
|
||||
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
|
||||
endif()
|
||||
endforeach()
|
||||
16
SimGearConfig.cmake.in
Normal file
16
SimGearConfig.cmake.in
Normal file
@@ -0,0 +1,16 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(ZLIB)
|
||||
find_dependency(Threads)
|
||||
|
||||
# OSG
|
||||
|
||||
set(SIMGEAR_HEADLESS @SIMGEAR_HEADLESS@)
|
||||
set(SIMGEAR_SOUND @ENABLE_SOUND@)
|
||||
|
||||
# OpenAL isn't a public dependency, so maybe not needed
|
||||
#if (SIMGEAR_SOUND)
|
||||
# find_dependency(OpenAL)
|
||||
#endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/SimGearTargets.cmake")
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
file(WRITE ${PROJECT_BINARY_DIR}/simgear/version.h "#define SIMGEAR_VERSION ${SIMGEAR_VERSION}")
|
||||
|
||||
foreach( mylibfolder
|
||||
foreach( mylibfolder
|
||||
bucket
|
||||
bvh
|
||||
debug
|
||||
@@ -54,9 +54,11 @@ if(SIMGEAR_SHARED)
|
||||
set_property(TARGET SimGearCore PROPERTY LINKER_LANGUAGE CXX)
|
||||
set_property(TARGET SimGearCore PROPERTY VERSION ${SIMGEAR_VERSION})
|
||||
set_property(TARGET SimGearCore PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
|
||||
install(TARGETS SimGearCore EXPORT SimGearCoreConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(EXPORT SimGearCoreConfig DESTINATION share/SimGearCore)
|
||||
|
||||
install(TARGETS SimGearCore
|
||||
EXPORT SimGearTargets
|
||||
LIBRARY DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
add_library(SimGearScene SHARED ${sceneSources})
|
||||
set_property(TARGET SimGearScene PROPERTY LINKER_LANGUAGE CXX)
|
||||
@@ -64,10 +66,12 @@ if(SIMGEAR_SHARED)
|
||||
set_property(TARGET SimGearScene PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
|
||||
|
||||
# EXPORT SimGearSceneConfig
|
||||
install(TARGETS SimGearScene LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} )
|
||||
# install(EXPORT SimGearSceneConfig DESTINATION share/SimGearScene)
|
||||
install(TARGETS SimGearScene
|
||||
EXPORT SimGearTargets
|
||||
LIBRARY
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR} )
|
||||
endif()
|
||||
|
||||
|
||||
else()
|
||||
message(STATUS "Library building mode: STATIC LIBRARIES")
|
||||
|
||||
@@ -90,8 +94,10 @@ else()
|
||||
endforeach()
|
||||
|
||||
add_library(SimGearCore STATIC ${coreSources} ${localExpatSources})
|
||||
install(TARGETS SimGearCore ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
install(TARGETS SimGearCore
|
||||
EXPORT SimGearTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
get_property(FG_GROUPS_SCENE_SOURCES_C GLOBAL PROPERTY FG_GROUPS_SCENE_SOURCES_C)
|
||||
string(REPLACE "@" ";" groups ${FG_GROUPS_SCENE_SOURCES_C} )
|
||||
@@ -112,7 +118,9 @@ else()
|
||||
endforeach()
|
||||
|
||||
add_library(SimGearScene STATIC ${sceneSources})
|
||||
install(TARGETS SimGearScene ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(TARGETS SimGearScene
|
||||
EXPORT SimGearTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif(NOT SIMGEAR_HEADLESS)
|
||||
endif(SIMGEAR_SHARED)
|
||||
|
||||
@@ -122,7 +130,8 @@ target_link_libraries(SimGearCore
|
||||
${DL_LIBRARY}
|
||||
${EXPAT_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CORE_SERVICES_LIBRARY})
|
||||
${COCOA_LIBRARY}
|
||||
${CURL_LIBRARIES})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
target_link_libraries(SimGearScene
|
||||
|
||||
@@ -4,4 +4,13 @@ include (SimGearComponent)
|
||||
set(HEADERS newbucket.hxx)
|
||||
set(SOURCES newbucket.cxx)
|
||||
|
||||
simgear_component(bucket bucket "${SOURCES}" "${HEADERS}")
|
||||
simgear_component(bucket bucket "${SOURCES}" "${HEADERS}")
|
||||
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
|
||||
add_executable(test_bucket test_bucket.cxx)
|
||||
add_test(test_bucket ${EXECUTABLE_OUTPUT_PATH}/test_bucket)
|
||||
target_link_libraries(test_bucket ${TEST_LIBS})
|
||||
|
||||
endif(ENABLE_TESTS)
|
||||
@@ -27,36 +27,56 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#include <cstdio> // some platforms need this for ::snprintf
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "newbucket.hxx"
|
||||
|
||||
|
||||
// default constructor
|
||||
SGBucket::SGBucket() {
|
||||
SGBucket::SGBucket() :
|
||||
lon(-1000),
|
||||
lat(-1000),
|
||||
x(0),
|
||||
y(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool SGBucket::isValid() const
|
||||
{
|
||||
// The most northerly valid latitude is 89, not 90. There is no tile
|
||||
// whose *bottom* latitude is 90. Similar there is no tile whose left egde
|
||||
// is 180 longitude.
|
||||
return (lon >= -180) &&
|
||||
(lon < 180) &&
|
||||
(lat >= -90) &&
|
||||
(lat < 90) &&
|
||||
(x < 8) && (y < 8);
|
||||
}
|
||||
|
||||
void SGBucket::make_bad()
|
||||
{
|
||||
lon = -1000;
|
||||
lat = -1000;
|
||||
}
|
||||
|
||||
#ifndef NO_DEPRECATED_API
|
||||
|
||||
// constructor for specified location
|
||||
SGBucket::SGBucket(const double dlon, const double dlat) {
|
||||
set_bucket(dlon, dlat);
|
||||
}
|
||||
#endif
|
||||
|
||||
SGBucket::SGBucket(const SGGeod& geod) {
|
||||
set_bucket(geod);
|
||||
innerSet(geod.getLongitudeDeg(),
|
||||
geod.getLatitudeDeg());
|
||||
}
|
||||
|
||||
// create an impossible bucket if false
|
||||
SGBucket::SGBucket(const bool is_good) {
|
||||
set_bucket(0.0, 0.0);
|
||||
if ( !is_good ) {
|
||||
lon = -1000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Parse a unique scenery tile index and find the lon, lat, x, and y
|
||||
SGBucket::SGBucket(const long int bindex) {
|
||||
long int index = bindex;
|
||||
@@ -75,48 +95,59 @@ SGBucket::SGBucket(const long int bindex) {
|
||||
x = index;
|
||||
}
|
||||
|
||||
/* Calculate the greatest integral value less than
|
||||
* or equal to the given value (floor(x)),
|
||||
* but attribute coordinates close to the boundary to the next
|
||||
* (increasing) integral
|
||||
*/
|
||||
static int floorWithEpsilon(double x)
|
||||
{
|
||||
return static_cast<int>(floor(x + SG_EPSILON));
|
||||
}
|
||||
|
||||
#ifndef NO_DEPRECATED_API
|
||||
|
||||
void SGBucket::set_bucket(double dlon, double dlat)
|
||||
{
|
||||
innerSet(dlon, dlat);
|
||||
}
|
||||
|
||||
|
||||
void SGBucket::set_bucket(const SGGeod& geod)
|
||||
{
|
||||
innerSet(geod.getLongitudeDeg(), geod.getLatitudeDeg());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Set the bucket params for the specified lat and lon
|
||||
void SGBucket::set_bucket( double *lonlat ) {
|
||||
set_bucket( lonlat[0], lonlat[1] );
|
||||
}
|
||||
|
||||
|
||||
// Set the bucket params for the specified lat and lon
|
||||
void SGBucket::set_bucket( double dlon, double dlat ) {
|
||||
void SGBucket::innerSet( double dlon, double dlat )
|
||||
{
|
||||
if ((dlon < -180.0) || (dlon >= 180.0)) {
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::set_bucket: passed longitude:" << dlon);
|
||||
dlon = SGMiscd::normalizePeriodic(-180.0, 180.0, dlon);
|
||||
}
|
||||
|
||||
if ((dlat < -90.0) || (dlat > 90.0)) {
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::set_bucket: passed latitude" << dlat);
|
||||
dlat = SGMiscd::clip(dlat, -90.0, 90.0);
|
||||
}
|
||||
|
||||
//
|
||||
// latitude first
|
||||
// longitude first
|
||||
//
|
||||
double span = sg_bucket_span( dlat );
|
||||
double diff = dlon - (double)(int)dlon;
|
||||
|
||||
// cout << "diff = " << diff << " span = " << span << endl;
|
||||
|
||||
/* Calculate the greatest integral longitude less than
|
||||
* or equal to the given longitude (floor(dlon)),
|
||||
* but attribute coordinates near the east border
|
||||
* to the next tile.
|
||||
*/
|
||||
if ( (dlon >= 0) || (fabs(diff) < SG_EPSILON) ) {
|
||||
lon = (int)dlon;
|
||||
} else {
|
||||
lon = (int)dlon - 1;
|
||||
}
|
||||
|
||||
// we do NOT need to special case lon=180 here, since
|
||||
// normalizePeriodic will never return 180; it will
|
||||
// return -180, which is what we want.
|
||||
lon = floorWithEpsilon(dlon);
|
||||
|
||||
// find subdivision or super lon if needed
|
||||
if ( span < SG_EPSILON ) {
|
||||
/* sg_bucket_span() never returns 0.0
|
||||
* or anything near it, so this really
|
||||
* should not occur at any time.
|
||||
*/
|
||||
// polar cap
|
||||
lon = 0;
|
||||
x = 0;
|
||||
} else if ( span <= 1.0 ) {
|
||||
if ( span <= 1.0 ) {
|
||||
/* We have more than one tile per degree of
|
||||
* longitude, so we need an x offset.
|
||||
*/
|
||||
x = (int)((dlon - lon) / span);
|
||||
x = floorWithEpsilon((dlon - lon) / span);
|
||||
} else {
|
||||
/* We have one or more degrees per tile,
|
||||
* so we need to find the base longitude
|
||||
@@ -129,48 +160,28 @@ void SGBucket::set_bucket( double dlon, double dlat ) {
|
||||
*
|
||||
* That way, the Greenwich Meridian is always
|
||||
* a tile border.
|
||||
*
|
||||
* This gets us into trouble with the polar caps,
|
||||
* which have width 360 and thus either span
|
||||
* the range from 0 to 360 or from -360 to 0
|
||||
* degrees, depending on whether lon is positive
|
||||
* or negative!
|
||||
*
|
||||
* We also get into trouble with the 8 degree tiles
|
||||
* north of 88N and south of 88S, because the west-
|
||||
* and east-most tiles in that range will cover 184W
|
||||
* to 176W and 176E to 184E respectively, with their
|
||||
* center at 180E/W!
|
||||
*/
|
||||
lon=(int)floor(floor((lon+SG_EPSILON)/span)*span);
|
||||
/* Correct the polar cap issue */
|
||||
if ( lon < -180 ) {
|
||||
lon = -180;
|
||||
}
|
||||
x = 0;
|
||||
lon=static_cast<int>(floor(lon / span) * span);
|
||||
x = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// then latitude
|
||||
//
|
||||
diff = dlat - (double)(int)dlat;
|
||||
|
||||
/* Again, a modified floor() function (see longitude) */
|
||||
if ( (dlat >= 0) || (fabs(diff) < SG_EPSILON) ) {
|
||||
lat = (int)dlat;
|
||||
lat = floorWithEpsilon(dlat);
|
||||
|
||||
// special case when passing in the north pole point (possibly due to
|
||||
// clipping latitude above). Ensures we generate a valid bucket in this
|
||||
// scenario
|
||||
if (lat == 90) {
|
||||
lat = 89;
|
||||
y = 7;
|
||||
} else {
|
||||
lat = (int)dlat - 1;
|
||||
/* Latitude base and offset are easier, as
|
||||
* tiles always are 1/8 degree of latitude wide.
|
||||
*/
|
||||
y = floorWithEpsilon((dlat - lat) * 8);
|
||||
}
|
||||
/* Latitude base and offset are easier, as
|
||||
* tiles always are 1/8 degree of latitude wide.
|
||||
*/
|
||||
y = (int)((dlat - lat) * 8);
|
||||
}
|
||||
|
||||
|
||||
void SGBucket::set_bucket(const SGGeod& geod)
|
||||
{
|
||||
set_bucket(geod.getLongitudeDeg(), geod.getLatitudeDeg());
|
||||
}
|
||||
|
||||
// Build the path name for this bucket
|
||||
@@ -212,7 +223,7 @@ std::string SGBucket::gen_base_path() const {
|
||||
main_lat *= -1;
|
||||
}
|
||||
|
||||
snprintf(raw_path, 256, "%c%03d%c%02d/%c%03d%c%02d",
|
||||
::snprintf(raw_path, 256, "%c%03d%c%02d/%c%03d%c%02d",
|
||||
hem, top_lon, pole, top_lat,
|
||||
hem, main_lon, pole, main_lat);
|
||||
|
||||
@@ -233,17 +244,32 @@ double SGBucket::get_height() const {
|
||||
return SG_BUCKET_SPAN;
|
||||
}
|
||||
|
||||
|
||||
// return width of the tile in meters
|
||||
double SGBucket::get_width_m() const {
|
||||
double clat = (int)get_center_lat();
|
||||
if ( clat > 0 ) {
|
||||
clat = (int)clat + 0.5;
|
||||
} else {
|
||||
clat = (int)clat - 0.5;
|
||||
double SGBucket::get_highest_lat() const
|
||||
{
|
||||
unsigned char adjustedY = y;
|
||||
if (lat >= 0) {
|
||||
// tile is north of the equator, so we want the top edge. Add one
|
||||
// to y to achieve this.
|
||||
++adjustedY;
|
||||
}
|
||||
double clat_rad = clat * SGD_DEGREES_TO_RADIANS;
|
||||
|
||||
return lat + (adjustedY / 8.0);
|
||||
}
|
||||
|
||||
|
||||
// return width of the tile in meters. This function is used by the
|
||||
// tile-manager to estimate how many tiles are in the view distance, so
|
||||
// we care about the smallest width, which occurs at the highest latitude.
|
||||
double SGBucket::get_width_m() const
|
||||
{
|
||||
double clat_rad = get_highest_lat() * SGD_DEGREES_TO_RADIANS;
|
||||
double cos_lat = cos( clat_rad );
|
||||
if (fabs(cos_lat) < SG_EPSILON) {
|
||||
// happens for polar tiles, since we pass in a latitude of 90
|
||||
// return an arbitrary small value so all tiles are loaded
|
||||
return 10.0;
|
||||
}
|
||||
|
||||
double local_radius = cos_lat * SG_EQUATORIAL_RADIUS_M;
|
||||
double local_perimeter = local_radius * SGD_2PI;
|
||||
double degree_width = local_perimeter / 360.0;
|
||||
@@ -260,7 +286,89 @@ double SGBucket::get_height_m() const {
|
||||
return SG_BUCKET_SPAN * degree_height;
|
||||
}
|
||||
|
||||
unsigned int SGBucket::siblings( int dx, int dy, std::vector<SGBucket>& buckets ) const
|
||||
{
|
||||
if (!isValid()) {
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::sibling: requesting sibling of invalid bucket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
double src_span = sg_bucket_span( get_center_lat() );
|
||||
|
||||
double clat = get_center_lat() + dy * SG_BUCKET_SPAN;
|
||||
// return invalid here instead of clipping, so callers can discard
|
||||
// invalid buckets without having to check if it's an existing one
|
||||
if ((clat < -90.0) || (clat > 90.0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// find the lon span for the new latitude
|
||||
double trg_span = sg_bucket_span( clat );
|
||||
|
||||
// if target span < src_span, return multiple buckets...
|
||||
if ( trg_span < src_span ) {
|
||||
// calc center longitude of westernmost sibling
|
||||
double start_lon = get_center_lat() - src_span/2 + trg_span/2;
|
||||
|
||||
unsigned int num_buckets = src_span/trg_span;
|
||||
for ( unsigned int x = 0; x < num_buckets; x++ ) {
|
||||
double tmp = start_lon + x * trg_span;
|
||||
tmp = SGMiscd::normalizePeriodic(-180.0, 180.0, tmp);
|
||||
|
||||
SGBucket b;
|
||||
b.innerSet(tmp, clat);
|
||||
|
||||
buckets.push_back( b );
|
||||
}
|
||||
} else {
|
||||
// just return the single sibling
|
||||
double tmp = get_center_lon() + dx * trg_span;
|
||||
tmp = SGMiscd::normalizePeriodic(-180.0, 180.0, tmp);
|
||||
|
||||
SGBucket b;
|
||||
b.innerSet(tmp, clat);
|
||||
|
||||
buckets.push_back( b );
|
||||
}
|
||||
|
||||
return buckets.size();
|
||||
}
|
||||
|
||||
SGBucket SGBucket::sibling(int dx, int dy) const
|
||||
{
|
||||
if (!isValid()) {
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::sibling: requesting sibling of invalid bucket");
|
||||
return SGBucket();
|
||||
}
|
||||
|
||||
double clat = get_center_lat() + dy * SG_BUCKET_SPAN;
|
||||
// return invalid here instead of clipping, so callers can discard
|
||||
// invalid buckets without having to check if it's an existing one
|
||||
if ((clat < -90.0) || (clat > 90.0)) {
|
||||
return SGBucket();
|
||||
}
|
||||
|
||||
// find the lon span for the new latitude
|
||||
double span = sg_bucket_span( clat );
|
||||
|
||||
double tmp = get_center_lon() + dx * span;
|
||||
tmp = SGMiscd::normalizePeriodic(-180.0, 180.0, tmp);
|
||||
|
||||
SGBucket b;
|
||||
b.innerSet(tmp, clat);
|
||||
return b;
|
||||
}
|
||||
|
||||
std::string SGBucket::gen_index_str() const
|
||||
{
|
||||
char tmp[20];
|
||||
::snprintf(tmp, 20, "%ld",
|
||||
(((long)lon + 180) << 14) + ((lat + 90) << 6)
|
||||
+ (y << 3) + x);
|
||||
return (std::string)tmp;
|
||||
}
|
||||
|
||||
#ifndef NO_DEPRECATED_API
|
||||
// find the bucket which is offset by the specified tile units in the
|
||||
// X & Y direction. We need the current lon and lat to resolve
|
||||
// ambiguities when going from a wider tile to a narrower one above or
|
||||
@@ -287,7 +395,7 @@ SGBucket sgBucketOffset( double dlon, double dlat, int dx, int dy ) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// calculate the offset between two buckets
|
||||
void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) {
|
||||
@@ -348,10 +456,22 @@ void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) {
|
||||
void sgGetBuckets( const SGGeod& min, const SGGeod& max, std::vector<SGBucket>& list ) {
|
||||
double lon, lat, span;
|
||||
|
||||
for (lat = min.getLatitudeDeg(); lat <= max.getLatitudeDeg(); lat += SG_BUCKET_SPAN) {
|
||||
for (lat = min.getLatitudeDeg(); lat < max.getLatitudeDeg()+SG_BUCKET_SPAN; lat += SG_BUCKET_SPAN) {
|
||||
span = sg_bucket_span( lat );
|
||||
for (lon = min.getLongitudeDeg(); lon <= max.getLongitudeDeg(); lon += span) {
|
||||
list.push_back( SGBucket(lon , lat) );
|
||||
for (lon = min.getLongitudeDeg(); lon <= max.getLongitudeDeg(); lon += span)
|
||||
{
|
||||
SGBucket b(SGGeod::fromDeg(lon, lat));
|
||||
if (!b.isValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list.push_back(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<< ( std::ostream& out, const SGBucket& b )
|
||||
{
|
||||
return out << b.lon << ":" << (int)b.x << ", " << b.lat << ":" << (int)b.y;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,11 +39,12 @@
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio> // sprintf()
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
|
||||
// #define NO_DEPRECATED_API
|
||||
|
||||
/**
|
||||
* standard size of a bucket in degrees (1/8 of a degree)
|
||||
*/
|
||||
@@ -99,75 +100,69 @@ class SGBucket {
|
||||
private:
|
||||
short lon; // longitude index (-180 to 179)
|
||||
short lat; // latitude index (-90 to 89)
|
||||
char x; // x subdivision (0 to 7)
|
||||
char y; // y subdivision (0 to 7)
|
||||
unsigned char x; // x subdivision (0 to 7)
|
||||
unsigned char y; // y subdivision (0 to 7)
|
||||
|
||||
void innerSet( double dlon, double dlat );
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
* Default constructor, creates an invalid SGBucket
|
||||
*/
|
||||
SGBucket();
|
||||
|
||||
/**
|
||||
* Check if this bucket refers to a valid tile, or not.
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
#ifndef NO_DEPRECATED_API
|
||||
/**
|
||||
* Construct a bucket given a specific location.
|
||||
* @param dlon longitude specified in degrees
|
||||
* @param dlat latitude specified in degrees
|
||||
*/
|
||||
SGBucket(const double dlon, const double dlat);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Construct a bucket given a specific location.
|
||||
* @param dlon longitude specified in degrees
|
||||
* @param dlat latitude specified in degrees
|
||||
*
|
||||
* @param geod Geodetic location
|
||||
*/
|
||||
SGBucket(const SGGeod& geod);
|
||||
|
||||
/** Construct a bucket.
|
||||
* @param is_good if false, create an invalid bucket. This is
|
||||
* useful * if you are comparing cur_bucket to last_bucket and
|
||||
* you want to * make sure last_bucket starts out as something
|
||||
* impossible.
|
||||
*/
|
||||
SGBucket(const bool is_good);
|
||||
|
||||
/** Construct a bucket given a unique bucket index number.
|
||||
*
|
||||
* @param bindex unique bucket index
|
||||
*/
|
||||
SGBucket(const long int bindex);
|
||||
|
||||
#ifndef NO_DEPRECATED_API
|
||||
/**
|
||||
* Reset a bucket to represent a new location.
|
||||
*
|
||||
* @param geod New geodetic location
|
||||
*/
|
||||
void set_bucket(const SGGeod& geod);
|
||||
|
||||
|
||||
/**
|
||||
* Reset a bucket to represent a new lat and lon
|
||||
* @param dlon longitude specified in degrees
|
||||
* @param dlat latitude specified in degrees
|
||||
*/
|
||||
void set_bucket( double dlon, double dlat );
|
||||
|
||||
/**
|
||||
* Reset a bucket to represent a new lat and lon
|
||||
* @param lonlat an array of double[2] holding lon and lat
|
||||
* (specified) in degrees
|
||||
*/
|
||||
void set_bucket( double *lonlat );
|
||||
|
||||
/**
|
||||
* Reset a bucket to represent a new lat and lon
|
||||
* @param dlon longitude specified in degrees
|
||||
* @param dlat latitude specified in degrees
|
||||
*/
|
||||
void set_bucket(const SGGeod& geod);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Create an impossible bucket.
|
||||
* This is useful if you are comparing cur_bucket to last_bucket
|
||||
* and you want to make sure last_bucket starts out as something
|
||||
* impossible.
|
||||
*/
|
||||
inline void make_bad() {
|
||||
set_bucket(0.0, 0.0);
|
||||
lon = -1000;
|
||||
}
|
||||
|
||||
void make_bad();
|
||||
|
||||
/**
|
||||
* Generate the unique scenery tile index for this bucket
|
||||
*
|
||||
@@ -192,14 +187,8 @@ public:
|
||||
* string form.
|
||||
* @return tile index in string form
|
||||
*/
|
||||
inline std::string gen_index_str() const {
|
||||
char tmp[20];
|
||||
std::sprintf(tmp, "%ld",
|
||||
(((long)lon + 180) << 14) + ((lat + 90) << 6)
|
||||
+ (y << 3) + x);
|
||||
return (std::string)tmp;
|
||||
}
|
||||
|
||||
std::string gen_index_str() const;
|
||||
|
||||
/**
|
||||
* Build the base path name for this bucket.
|
||||
* @return base path in string form
|
||||
@@ -226,6 +215,13 @@ public:
|
||||
return lat + y / 8.0 + SG_HALF_BUCKET_SPAN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the highest (furthest from the equator) latitude of this
|
||||
* tile. This is the top edge for tiles north of the equator, and
|
||||
* the bottom edge for tiles south
|
||||
*/
|
||||
double get_highest_lat() const;
|
||||
|
||||
/**
|
||||
* @return the width of the tile in degrees.
|
||||
*/
|
||||
@@ -287,6 +283,16 @@ public:
|
||||
*/
|
||||
inline int get_y() const { return y; }
|
||||
|
||||
/**
|
||||
* @return bucket offset from this by dx,dy
|
||||
*/
|
||||
SGBucket sibling(int dx, int dy) const;
|
||||
|
||||
/**
|
||||
* @return multiple buckets offset from this by dx,dy
|
||||
*/
|
||||
unsigned int siblings(int dz, int dy, std::vector<SGBucket>& buckets) const;
|
||||
|
||||
// friends
|
||||
|
||||
friend std::ostream& operator<< ( std::ostream&, const SGBucket& );
|
||||
@@ -298,7 +304,7 @@ inline bool operator!= (const SGBucket& lhs, const SGBucket& rhs)
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
#ifndef NO_DEPRECATED_API
|
||||
/**
|
||||
* \relates SGBucket
|
||||
* Return the bucket which is offset from the specified dlon, dlat by
|
||||
@@ -310,6 +316,7 @@ inline bool operator!= (const SGBucket& lhs, const SGBucket& rhs)
|
||||
* @return offset bucket
|
||||
*/
|
||||
SGBucket sgBucketOffset( double dlon, double dlat, int x, int y );
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
@@ -337,12 +344,7 @@ void sgGetBuckets( const SGGeod& min, const SGGeod& max, std::vector<SGBucket>&
|
||||
* @param out output stream
|
||||
* @param b bucket
|
||||
*/
|
||||
inline std::ostream&
|
||||
operator<< ( std::ostream& out, const SGBucket& b )
|
||||
{
|
||||
return out << b.lon << ":" << (int)b.x << ", " << b.lat << ":" << (int)b.y;
|
||||
}
|
||||
|
||||
std::ostream& operator<< ( std::ostream& out, const SGBucket& b );
|
||||
|
||||
/**
|
||||
* Compare two bucket structures for equality.
|
||||
|
||||
283
simgear/bucket/test_bucket.cxx
Normal file
283
simgear/bucket/test_bucket.cxx
Normal file
@@ -0,0 +1,283 @@
|
||||
/**************************************************************************
|
||||
* test_bucket.cxx -- unit-tests for SGBucket class
|
||||
*
|
||||
* Copyright (C) 2014 James Turner - <zakalawe@mac.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <simgear/misc/test_macros.hxx>
|
||||
|
||||
void testBucketSpans()
|
||||
{
|
||||
COMPARE(sg_bucket_span(0.0), 0.125);
|
||||
COMPARE(sg_bucket_span(-20), 0.125);
|
||||
COMPARE(sg_bucket_span(-40), 0.25);
|
||||
COMPARE(sg_bucket_span(89.9), 12.0);
|
||||
COMPARE(sg_bucket_span(88.1), 4.0);
|
||||
COMPARE(sg_bucket_span(-89.9), 12.0);
|
||||
}
|
||||
|
||||
void testBasic()
|
||||
{
|
||||
SGBucket b1(5.1, 55.05);
|
||||
COMPARE(b1.get_chunk_lon(), 5);
|
||||
COMPARE(b1.get_chunk_lat(), 55);
|
||||
COMPARE(b1.get_x(), 0);
|
||||
COMPARE(b1.get_y(), 0);
|
||||
COMPARE(b1.gen_index(), 3040320);
|
||||
COMPARE(b1.gen_base_path(), "e000n50/e005n55");
|
||||
VERIFY(b1.isValid());
|
||||
|
||||
SGBucket b2(-10.1, -43.8);
|
||||
COMPARE(b2.get_chunk_lon(), -11);
|
||||
COMPARE(b2.get_chunk_lat(), -44);
|
||||
COMPARE(b2.get_x(), 3);
|
||||
COMPARE(b2.get_y(), 1); // latitude chunks numbered bottom to top, it seems
|
||||
COMPARE(b2.gen_base_path(), "w020s50/w011s44");
|
||||
VERIFY(b2.isValid());
|
||||
|
||||
SGBucket b3(123.48, 9.01);
|
||||
COMPARE(b3.get_chunk_lon(), 123);
|
||||
COMPARE(b3.get_chunk_lat(), 9);
|
||||
COMPARE(b3.get_x(), 3);
|
||||
COMPARE(b3.get_y(), 0);
|
||||
COMPARE(b3.gen_base_path(), "e120n00/e123n09");
|
||||
VERIFY(b3.isValid());
|
||||
|
||||
SGBucket defBuck;
|
||||
VERIFY(!defBuck.isValid());
|
||||
|
||||
b3.make_bad();
|
||||
VERIFY(!b3.isValid());
|
||||
|
||||
SGBucket atAntiMeridian(180.0, 12.3);
|
||||
VERIFY(atAntiMeridian.isValid());
|
||||
COMPARE(atAntiMeridian.get_chunk_lon(), -180);
|
||||
COMPARE(atAntiMeridian.get_x(), 0);
|
||||
|
||||
SGBucket atAntiMeridian2(-180.0, -78.1);
|
||||
VERIFY(atAntiMeridian2.isValid());
|
||||
COMPARE(atAntiMeridian2.get_chunk_lon(), -180);
|
||||
COMPARE(atAntiMeridian2.get_x(), 0);
|
||||
|
||||
// check comparisom operator overload
|
||||
SGBucket b4(5.11, 55.1);
|
||||
VERIFY(b1 == b4); // should be equal
|
||||
VERIFY(b1 == b1);
|
||||
VERIFY(b1 != defBuck);
|
||||
VERIFY(b1 != b2);
|
||||
|
||||
// check wrapping/clipping of inputs
|
||||
SGBucket wrapMeridian(-200.0, 45.0);
|
||||
COMPARE(wrapMeridian.get_chunk_lon(), 160);
|
||||
|
||||
SGBucket clipPole(48.9, 91);
|
||||
COMPARE(clipPole.get_chunk_lat(), 89);
|
||||
}
|
||||
|
||||
void testPolar()
|
||||
{
|
||||
SGBucket b1(0.0, 89.92);
|
||||
SGBucket b2(10.0, 89.96);
|
||||
COMPARE(b1.get_chunk_lat(), 89);
|
||||
COMPARE(b1.get_chunk_lon(), 0);
|
||||
COMPARE(b1.get_x(), 0);
|
||||
COMPARE(b1.get_y(), 7);
|
||||
|
||||
COMPARE_EP(b1.get_highest_lat(), 90.0);
|
||||
COMPARE_EP(b1.get_width_m(), 10.0);
|
||||
|
||||
COMPARE(b2.get_chunk_lat(), 89);
|
||||
COMPARE(b2.get_chunk_lon(), 0);
|
||||
COMPARE(b2.get_x(), 0);
|
||||
COMPARE(b2.get_y(), 7);
|
||||
|
||||
COMPARE(b1.gen_index(), b2.gen_index());
|
||||
|
||||
SGGeod actualNorthPole1 = b1.get_corner(2);
|
||||
SGGeod actualNorthPole2 = b1.get_corner(3);
|
||||
COMPARE_EP(actualNorthPole1.getLatitudeDeg(), 90.0);
|
||||
COMPARE_EP(actualNorthPole1.getLongitudeDeg(), 12.0);
|
||||
COMPARE_EP(actualNorthPole2.getLatitudeDeg(), 90.0);
|
||||
COMPARE_EP(actualNorthPole2.getLongitudeDeg(), 0.0);
|
||||
|
||||
SGBucket b3(-2, 89.88);
|
||||
SGBucket b4(-7, 89.88);
|
||||
COMPARE(b3.gen_index(), b4.gen_index());
|
||||
|
||||
// south pole
|
||||
SGBucket b5(-170, -89.88);
|
||||
SGBucket b6(-179, -89.88);
|
||||
|
||||
COMPARE(b5.get_chunk_lat(), -90);
|
||||
COMPARE(b5.get_chunk_lon(), -180);
|
||||
COMPARE(b5.get_x(), 0);
|
||||
COMPARE(b5.get_y(), 0);
|
||||
COMPARE(b5.gen_index(), b6.gen_index());
|
||||
COMPARE_EP(b5.get_highest_lat(), -90.0);
|
||||
COMPARE_EP(b5.get_width_m(), 10.0);
|
||||
|
||||
SGGeod actualSouthPole1 = b5.get_corner(0);
|
||||
SGGeod actualSouthPole2 = b5.get_corner(1);
|
||||
COMPARE_EP(actualSouthPole1.getLatitudeDeg(), -90.0);
|
||||
COMPARE_EP(actualSouthPole1.getLongitudeDeg(), -180);
|
||||
COMPARE_EP(actualSouthPole2.getLatitudeDeg(), -90.0);
|
||||
COMPARE_EP(actualSouthPole2.getLongitudeDeg(), -168);
|
||||
|
||||
SGBucket b7(200, 89.88);
|
||||
COMPARE(b7.get_chunk_lon(), -168);
|
||||
|
||||
}
|
||||
|
||||
// test the tiles just below the pole (between 86 & 89 degrees N/S)
|
||||
void testNearPolar()
|
||||
{
|
||||
SGBucket b1(1, 88.5);
|
||||
SGBucket b2(-1, 88.8);
|
||||
COMPARE(b1.get_chunk_lon(), 0);
|
||||
COMPARE(b1.get_chunk_lat(), 88);
|
||||
VERIFY(b1.gen_index() != b2.gen_index());
|
||||
|
||||
SGBucket b3(176.1, 88.5);
|
||||
COMPARE(b3.get_chunk_lon(), 176);
|
||||
|
||||
SGBucket b4(-178, 88.5);
|
||||
COMPARE(b4.get_chunk_lon(), -180);
|
||||
}
|
||||
|
||||
void testOffset()
|
||||
{
|
||||
// bucket just below the 22 degree cutoff, so the next tile north
|
||||
// is twice the width
|
||||
SGBucket b1(-59.8, 21.9);
|
||||
COMPARE(b1.get_chunk_lat(), 21);
|
||||
COMPARE(b1.get_chunk_lon(), -60);
|
||||
COMPARE(b1.get_x(), 1);
|
||||
COMPARE(b1.get_y(), 7);
|
||||
|
||||
// offset vertically
|
||||
SGBucket b2(b1.sibling(0, 1));
|
||||
COMPARE(b2.get_chunk_lat(), 22);
|
||||
COMPARE(b2.get_chunk_lon(), -60);
|
||||
COMPARE(b2.get_x(), 0);
|
||||
COMPARE(b2.get_y(), 0);
|
||||
|
||||
COMPARE(b2.gen_index(), sgBucketOffset(-59.8, 21.9, 0, 1));
|
||||
|
||||
// offset vertically and horizontally. We compute horizontal (x)
|
||||
// movement at the target latitude, so this should move 0.25 * -3 degrees,
|
||||
// NOT 0.125 * -3 degrees.
|
||||
SGBucket b3(b1.sibling(-3, 1));
|
||||
COMPARE(b3.get_chunk_lat(), 22);
|
||||
COMPARE(b3.get_chunk_lon(), -61);
|
||||
COMPARE(b3.get_x(), 1);
|
||||
COMPARE(b3.get_y(), 0);
|
||||
|
||||
COMPARE(b3.gen_index(), sgBucketOffset(-59.8, 21.9, -3, 1));
|
||||
}
|
||||
|
||||
void testPolarOffset()
|
||||
{
|
||||
SGBucket b1(-11.7, -89.6);
|
||||
COMPARE(b1.get_chunk_lat(), -90);
|
||||
COMPARE(b1.get_chunk_lon(), -12);
|
||||
COMPARE(b1.get_x(), 0);
|
||||
COMPARE(b1.get_y(), 3);
|
||||
|
||||
// offset horizontally
|
||||
SGBucket b2(b1.sibling(-2, 0));
|
||||
COMPARE(b2.get_chunk_lat(), -90);
|
||||
COMPARE(b2.get_chunk_lon(), -36);
|
||||
COMPARE(b2.get_x(), 0);
|
||||
COMPARE(b2.get_y(), 3);
|
||||
|
||||
COMPARE(b2.gen_index(), sgBucketOffset(-11.7, -89.6, -2, 0));
|
||||
|
||||
// offset and wrap
|
||||
SGBucket b3(-170, 89.1);
|
||||
SGBucket b4(b3.sibling(-1, 0));
|
||||
COMPARE(b4.get_chunk_lat(), 89);
|
||||
COMPARE(b4.get_chunk_lon(), 168);
|
||||
COMPARE(b4.get_x(), 0);
|
||||
COMPARE(b4.get_y(), 0);
|
||||
|
||||
COMPARE(b4.gen_index(), sgBucketOffset(-170, 89.1, -1, 0));
|
||||
|
||||
|
||||
SGBucket b5(177, 87.3);
|
||||
SGBucket b6(b5.sibling(1, 1));
|
||||
COMPARE(b6.get_chunk_lat(), 87);
|
||||
COMPARE(b6.get_chunk_lon(), -180);
|
||||
COMPARE(b6.get_x(), 0);
|
||||
COMPARE(b6.get_y(), 3);
|
||||
|
||||
COMPARE(b6.gen_index(), sgBucketOffset(177, 87.3, 1, 1));
|
||||
|
||||
// offset vertically towards the pole
|
||||
SGBucket b7(b1.sibling(0, -5));
|
||||
VERIFY(!b7.isValid());
|
||||
|
||||
VERIFY(!SGBucket(0, 90).sibling(0, 1).isValid());
|
||||
}
|
||||
|
||||
// test behaviour of bucket-offset near the anti-meridian (180-meridian)
|
||||
void testOffsetWrap()
|
||||
{
|
||||
// near the equator
|
||||
SGBucket b1(-179.8, 16.8);
|
||||
COMPARE(b1.get_chunk_lat(), 16);
|
||||
COMPARE(b1.get_chunk_lon(), -180);
|
||||
COMPARE(b1.get_x(), 1);
|
||||
COMPARE(b1.get_y(), 6);
|
||||
|
||||
SGBucket b2(b1.sibling(-2, 0));
|
||||
COMPARE(b2.get_chunk_lat(), 16);
|
||||
COMPARE(b2.get_chunk_lon(), 179);
|
||||
COMPARE(b2.get_x(), 7);
|
||||
COMPARE(b2.get_y(), 6);
|
||||
COMPARE(b2.gen_index(), sgBucketOffset(-179.8, 16.8, -2, 0));
|
||||
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
testBucketSpans();
|
||||
|
||||
testBasic();
|
||||
testPolar();
|
||||
testNearPolar();
|
||||
testOffset();
|
||||
testOffsetWrap();
|
||||
testPolarOffset();
|
||||
|
||||
cout << "all tests passed OK" << endl;
|
||||
return 0; // passed
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
void removeChild(BVHNode* child);
|
||||
|
||||
unsigned getNumChildren() const
|
||||
{ return _children.size(); }
|
||||
{ return static_cast<unsigned>(_children.size()); }
|
||||
const BVHNode* getChild(unsigned i) const
|
||||
{ if (_children.size() <= i) return 0; return _children[i]; }
|
||||
BVHNode* getChild(unsigned i)
|
||||
|
||||
@@ -31,13 +31,13 @@ public:
|
||||
virtual ~BVHStaticData() {}
|
||||
|
||||
unsigned addVertex(const SGVec3f& vertex)
|
||||
{ _vertices.push_back(vertex); return _vertices.size() - 1; }
|
||||
{ _vertices.push_back(vertex); return static_cast<unsigned>(_vertices.size() - 1); }
|
||||
const SGVec3f& getVertex(unsigned i) const
|
||||
{ return _vertices[i]; }
|
||||
|
||||
|
||||
unsigned addMaterial(const BVHMaterial* material)
|
||||
{ _materials.push_back(material); return _materials.size() - 1; }
|
||||
{ _materials.push_back(material); return static_cast<unsigned>(_materials.size() - 1); }
|
||||
const BVHMaterial* getMaterial(unsigned i) const
|
||||
{ if (_materials.size() <= i) return 0; return _materials[i]; }
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ set(HEADERS
|
||||
CanvasObjectPlacement.hxx
|
||||
CanvasPlacement.hxx
|
||||
CanvasSystemAdapter.hxx
|
||||
MouseEvent.hxx
|
||||
CanvasWindow.hxx
|
||||
ODGauge.hxx
|
||||
VGInitOperation.hxx
|
||||
)
|
||||
@@ -24,11 +24,14 @@ set(SOURCES
|
||||
CanvasMgr.cxx
|
||||
CanvasObjectPlacement.cxx
|
||||
CanvasPlacement.cxx
|
||||
CanvasWindow.cxx
|
||||
ODGauge.cxx
|
||||
VGInitOperation.cxx
|
||||
)
|
||||
|
||||
add_subdirectory(ShivaVG/src)
|
||||
add_subdirectory(elements)
|
||||
add_subdirectory(events)
|
||||
add_subdirectory(layout)
|
||||
|
||||
simgear_scene_component(canvas canvas "${SOURCES}" "${HEADERS}")
|
||||
|
||||
@@ -19,8 +19,9 @@
|
||||
#include "Canvas.hxx"
|
||||
#include "CanvasEventManager.hxx"
|
||||
#include "CanvasEventVisitor.hxx"
|
||||
#include <simgear/canvas/MouseEvent.hxx>
|
||||
#include <simgear/canvas/CanvasPlacement.hxx>
|
||||
#include "CanvasPlacement.hxx"
|
||||
#include <simgear/canvas/events/KeyboardEvent.hxx>
|
||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||
#include <simgear/scene/util/parse_color.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
|
||||
@@ -48,8 +49,12 @@ namespace canvas
|
||||
void Canvas::CullCallback::operator()( osg::Node* node,
|
||||
osg::NodeVisitor* nv )
|
||||
{
|
||||
if( (nv->getTraversalMask() & simgear::MODEL_BIT) && !_canvas.expired() )
|
||||
_canvas.lock()->enableRendering();
|
||||
if( (nv->getTraversalMask() & simgear::MODEL_BIT) )
|
||||
{
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( canvas )
|
||||
canvas->enableRendering();
|
||||
}
|
||||
|
||||
traverse(node, nv);
|
||||
}
|
||||
@@ -72,6 +77,13 @@ namespace canvas
|
||||
{
|
||||
_status = 0;
|
||||
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
|
||||
|
||||
_root_group.reset( new Group(this, _node) );
|
||||
|
||||
// Remove automatically created property listener as we forward them on our
|
||||
// own
|
||||
_root_group->removeListener();
|
||||
_cull_callback = new CullCallback(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -180,6 +192,32 @@ namespace canvas
|
||||
return _root_group;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setLayout(const LayoutRef& layout)
|
||||
{
|
||||
_layout = layout;
|
||||
_layout->setCanvas(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setFocusElement(const ElementPtr& el)
|
||||
{
|
||||
if( el && el->getCanvas().lock() != this )
|
||||
{
|
||||
SG_LOG(SG_GUI, SG_WARN, "setFocusElement: element not from this canvas");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO focus out/in events
|
||||
_focus_element = el;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::clearFocusElement()
|
||||
{
|
||||
_focus_element.reset();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::enableRendering(bool force)
|
||||
{
|
||||
@@ -191,11 +229,10 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::update(double delta_time_sec)
|
||||
{
|
||||
if( (!_texture.serviceable() && _status != STATUS_DIRTY)
|
||||
|| (_status & CREATE_FAILED) )
|
||||
if( _status & (CREATE_FAILED | MISSING_SIZE) )
|
||||
return;
|
||||
|
||||
if( _status == STATUS_DIRTY )
|
||||
if( _status & STATUS_DIRTY )
|
||||
{
|
||||
_texture.setSize(_size_x, _size_y);
|
||||
|
||||
@@ -237,23 +274,28 @@ namespace canvas
|
||||
}
|
||||
}
|
||||
|
||||
if( _layout )
|
||||
_layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
|
||||
|
||||
if( _visible || _render_always )
|
||||
{
|
||||
BOOST_FOREACH(CanvasWeakPtr canvas, _child_canvases)
|
||||
BOOST_FOREACH(CanvasWeakPtr canvas_weak, _child_canvases)
|
||||
{
|
||||
// TODO should we check if the image the child canvas is displayed
|
||||
// within is really visible?
|
||||
if( !canvas.expired() )
|
||||
canvas.lock()->_visible = true;
|
||||
CanvasPtr canvas = canvas_weak.lock();
|
||||
if( canvas )
|
||||
canvas->_visible = true;
|
||||
}
|
||||
|
||||
if( _render_dirty )
|
||||
{
|
||||
// Also mark all canvases this canvas is displayed within as dirty
|
||||
BOOST_FOREACH(CanvasWeakPtr canvas, _parent_canvases)
|
||||
BOOST_FOREACH(CanvasWeakPtr canvas_weak, _parent_canvases)
|
||||
{
|
||||
if( !canvas.expired() )
|
||||
canvas.lock()->_render_dirty = true;
|
||||
CanvasPtr canvas = canvas_weak.lock();
|
||||
if( canvas )
|
||||
canvas->_render_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,11 +338,7 @@ namespace canvas
|
||||
if( placement_factory != _placement_factories.end() )
|
||||
{
|
||||
Placements& placements = _placements[ node->getIndex() ] =
|
||||
placement_factory->second
|
||||
(
|
||||
node,
|
||||
boost::static_pointer_cast<Canvas>(_self.lock())
|
||||
);
|
||||
placement_factory->second(node, this);
|
||||
node->setStringValue
|
||||
(
|
||||
"status-msg",
|
||||
@@ -317,11 +355,20 @@ namespace canvas
|
||||
const EventListener& cb )
|
||||
{
|
||||
if( !_root_group.get() )
|
||||
throw std::runtime_error("Canvas::AddEventListener: no root group!");
|
||||
throw std::runtime_error("Canvas::addEventListener: no root group!");
|
||||
|
||||
return _root_group->addEventListener(type, cb);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Canvas::dispatchEvent(const EventPtr& event)
|
||||
{
|
||||
if( !_root_group.get() )
|
||||
throw std::runtime_error("Canvas::dispatchEvent: no root group!");
|
||||
|
||||
return _root_group->dispatchEvent(event);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setSizeX(int sx)
|
||||
{
|
||||
@@ -409,12 +456,11 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
bool Canvas::handleMouseEvent(const MouseEventPtr& event)
|
||||
{
|
||||
if( !_root_group.get() )
|
||||
if( !_root_group )
|
||||
return false;
|
||||
|
||||
EventVisitor visitor( EventVisitor::TRAVERSE_DOWN,
|
||||
event->getClientPos(),
|
||||
event->getDelta(),
|
||||
_root_group );
|
||||
if( !_root_group->accept(visitor) )
|
||||
return false;
|
||||
@@ -422,6 +468,25 @@ namespace canvas
|
||||
return _event_manager->handleEvent(event, visitor.getPropagationPath());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Canvas::handleKeyboardEvent(const KeyboardEventPtr& event)
|
||||
{
|
||||
ElementPtr target = _focus_element.lock();
|
||||
if( !target )
|
||||
target = _root_group;
|
||||
if( !target )
|
||||
return false;
|
||||
|
||||
return target->dispatchEvent(event);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Canvas::propagateEvent( EventPtr const& event,
|
||||
EventPropagationPath const& path )
|
||||
{
|
||||
return _event_manager->propagateEvent(event, path);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child )
|
||||
@@ -453,8 +518,10 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::valueChanged(SGPropertyNode* node)
|
||||
{
|
||||
if( boost::starts_with(node->getNameString(), "status")
|
||||
|| node->getParent()->getNameString() == "bounding-box" )
|
||||
const std::string& name = node->getNameString();
|
||||
|
||||
if( boost::starts_with(name, "status")
|
||||
|| boost::starts_with(name, "data-") )
|
||||
return;
|
||||
_render_dirty = true;
|
||||
|
||||
@@ -493,7 +560,7 @@ namespace canvas
|
||||
}
|
||||
else if( node->getParent() == _node )
|
||||
{
|
||||
if( node->getNameString() == "background" )
|
||||
if( name == "background" )
|
||||
{
|
||||
osg::Vec4 color;
|
||||
if( _texture.getCamera() && parseColor(node->getStringValue(), color) )
|
||||
@@ -502,35 +569,41 @@ namespace canvas
|
||||
_render_dirty = true;
|
||||
}
|
||||
}
|
||||
else if( node->getNameString() == "mipmapping"
|
||||
|| node->getNameString() == "coverage-samples"
|
||||
|| node->getNameString() == "color-samples" )
|
||||
else if( name == "mipmapping"
|
||||
|| name == "coverage-samples"
|
||||
|| name == "color-samples" )
|
||||
{
|
||||
_sampling_dirty = true;
|
||||
}
|
||||
else if( node->getNameString() == "additive-blend" )
|
||||
else if( name == "additive-blend" )
|
||||
{
|
||||
_texture.useAdditiveBlend( node->getBoolValue() );
|
||||
}
|
||||
else if( node->getNameString() == "render-always" )
|
||||
else if( name == "render-always" )
|
||||
{
|
||||
_render_always = node->getBoolValue();
|
||||
}
|
||||
else if( node->getNameString() == "size" )
|
||||
else if( name == "size" )
|
||||
{
|
||||
if( node->getIndex() == 0 )
|
||||
setSizeX( node->getIntValue() );
|
||||
else if( node->getIndex() == 1 )
|
||||
setSizeY( node->getIntValue() );
|
||||
}
|
||||
else if( node->getNameString() == "view" )
|
||||
else if( name == "update" )
|
||||
{
|
||||
if( _root_group )
|
||||
_root_group->update(0);
|
||||
return update(0);
|
||||
}
|
||||
else if( name == "view" )
|
||||
{
|
||||
if( node->getIndex() == 0 )
|
||||
setViewWidth( node->getIntValue() );
|
||||
else if( node->getIndex() == 1 )
|
||||
setViewHeight( node->getIntValue() );
|
||||
}
|
||||
else if( node->getNameString() == "freeze" )
|
||||
else if( name == "freeze" )
|
||||
_texture.setRender( node->getBoolValue() );
|
||||
else
|
||||
handled = false;
|
||||
@@ -615,23 +688,6 @@ namespace canvas
|
||||
return _system_adapter;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setSelf(const PropertyBasedElementPtr& self)
|
||||
{
|
||||
PropertyBasedElement::setSelf(self);
|
||||
|
||||
CanvasPtr canvas = boost::static_pointer_cast<Canvas>(self);
|
||||
|
||||
_root_group.reset( new Group(canvas, _node) );
|
||||
_root_group->setSelf(_root_group);
|
||||
|
||||
// Remove automatically created property listener as we forward them on our
|
||||
// own
|
||||
_root_group->removeListener();
|
||||
|
||||
_cull_callback = new CullCallback(canvas);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setStatusFlags(unsigned int flags, bool set)
|
||||
{
|
||||
@@ -648,7 +704,7 @@ namespace canvas
|
||||
_status_msg = "Missing size-y";
|
||||
else if( _status & CREATE_FAILED )
|
||||
_status_msg = "Creating render target failed";
|
||||
else if( _status == STATUS_DIRTY )
|
||||
else if( _status & STATUS_DIRTY )
|
||||
_status_msg = "Creation pending...";
|
||||
else
|
||||
_status_msg = "Ok";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// The canvas for rendering with the 2d API
|
||||
///@file
|
||||
/// The canvas for rendering with the 2d API
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -23,9 +24,12 @@
|
||||
#include "ODGauge.hxx"
|
||||
|
||||
#include <simgear/canvas/elements/CanvasGroup.hxx>
|
||||
#include <simgear/canvas/layout/Layout.hxx>
|
||||
#include <simgear/math/SGRect.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalObject.hxx>
|
||||
#include <simgear/props/PropertyBasedElement.hxx>
|
||||
#include <simgear/props/propertyObject.hxx>
|
||||
|
||||
#include <osg/NodeCallback>
|
||||
#include <osg/observer_ptr>
|
||||
|
||||
@@ -34,22 +38,28 @@
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
/// Canvas 2D drawing API
|
||||
namespace canvas
|
||||
{
|
||||
class CanvasMgr;
|
||||
class MouseEvent;
|
||||
|
||||
/**
|
||||
* Canvas to draw onto (to an off-screen render target).
|
||||
*/
|
||||
class Canvas:
|
||||
public PropertyBasedElement
|
||||
public PropertyBasedElement,
|
||||
public nasal::Object
|
||||
{
|
||||
public:
|
||||
|
||||
enum StatusFlags
|
||||
{
|
||||
STATUS_OK,
|
||||
STATUS_DIRTY = 1,
|
||||
STATUS_DIRTY = 1,
|
||||
MISSING_SIZE_X = STATUS_DIRTY << 1,
|
||||
MISSING_SIZE_Y = MISSING_SIZE_X << 1,
|
||||
MISSING_SIZE = MISSING_SIZE_X | MISSING_SIZE_Y,
|
||||
CREATE_FAILED = MISSING_SIZE_Y << 1
|
||||
};
|
||||
|
||||
@@ -120,6 +130,28 @@ namespace canvas
|
||||
*/
|
||||
GroupPtr getRootGroup();
|
||||
|
||||
/**
|
||||
* Set the layout of the canvas (the layout will automatically update with
|
||||
* the viewport size of the canvas)
|
||||
*/
|
||||
void setLayout(const LayoutRef& layout);
|
||||
|
||||
/**
|
||||
* Set the focus to the given element.
|
||||
*
|
||||
* The focus element will receive all keyboard events propagated to this
|
||||
* canvas. If there is no valid focus element the root group will receive
|
||||
* the events instead.
|
||||
*/
|
||||
void setFocusElement(const ElementPtr& el);
|
||||
|
||||
/**
|
||||
* Clear the focus element.
|
||||
*
|
||||
* @see setFocusElement()
|
||||
*/
|
||||
void clearFocusElement();
|
||||
|
||||
/**
|
||||
* Enable rendering for the next frame
|
||||
*
|
||||
@@ -131,6 +163,7 @@ namespace canvas
|
||||
void update(double delta_time_sec);
|
||||
|
||||
bool addEventListener(const std::string& type, const EventListener& cb);
|
||||
bool dispatchEvent(const EventPtr& event);
|
||||
|
||||
void setSizeX(int sx);
|
||||
void setSizeY(int sy);
|
||||
@@ -146,6 +179,10 @@ namespace canvas
|
||||
SGRect<int> getViewport() const;
|
||||
|
||||
bool handleMouseEvent(const MouseEventPtr& event);
|
||||
bool handleKeyboardEvent(const KeyboardEventPtr& event);
|
||||
|
||||
bool propagateEvent( EventPtr const& event,
|
||||
EventPropagationPath const& path );
|
||||
|
||||
virtual void childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
@@ -191,21 +228,24 @@ namespace canvas
|
||||
_visible;
|
||||
|
||||
ODGauge _texture;
|
||||
GroupPtr _root_group;
|
||||
|
||||
GroupPtr _root_group;
|
||||
LayoutRef _layout;
|
||||
|
||||
ElementWeakPtr _focus_element;
|
||||
|
||||
CullCallbackPtr _cull_callback;
|
||||
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
|
||||
bool _render_always; //!< Used to disable automatic lazy rendering (culling)
|
||||
|
||||
std::vector<SGPropertyNode*> _dirty_placements;
|
||||
std::vector<Placements> _placements;
|
||||
std::set<CanvasWeakPtr> _parent_canvases, //<! Canvases showing this canvas
|
||||
_child_canvases; //<! Canvases displayed within
|
||||
std::set<CanvasWeakPtr> _parent_canvases, //!< Canvases showing this canvas
|
||||
_child_canvases; //!< Canvases displayed within
|
||||
// this canvas
|
||||
|
||||
typedef std::map<std::string, PlacementFactory> PlacementFactoryMap;
|
||||
static PlacementFactoryMap _placement_factories;
|
||||
|
||||
virtual void setSelf(const PropertyBasedElementPtr& self);
|
||||
void setStatusFlags(unsigned int flags, bool set = true);
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,7 +26,9 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
Event::Event():
|
||||
type(UNKNOWN),
|
||||
propagation_stopped(false)
|
||||
time(-1),
|
||||
propagation_stopped(false),
|
||||
default_prevented(false)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -38,7 +40,13 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Event::Type Event::getType() const
|
||||
bool Event::canBubble() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Event::getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
@@ -46,14 +54,7 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
std::string Event::getTypeString() const
|
||||
{
|
||||
switch( type )
|
||||
{
|
||||
# define ENUM_MAPPING(name, str) case name: return str;
|
||||
# include "CanvasEventTypes.hxx"
|
||||
# undef ENUM_MAPPING
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
return typeToStr(type);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -81,23 +82,69 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Event::Type Event::strToType(const std::string& str)
|
||||
void Event::preventDefault()
|
||||
{
|
||||
default_prevented = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Event::defaultPrevented() const
|
||||
{
|
||||
return default_prevented;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Event::getOrRegisterType(const std::string& type_str)
|
||||
{
|
||||
int type = strToType(type_str);
|
||||
|
||||
if( type == UNKNOWN )
|
||||
{
|
||||
// Register new type
|
||||
TypeMap& type_map = getTypeMap();
|
||||
type = type_map.size() + 1; // ids start with 1 (after UNKNOWN)
|
||||
type_map.insert(TypeMap::value_type(type_str, type));
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Event::strToType(const std::string& str)
|
||||
{
|
||||
TypeMap const& type_map = getTypeMap();
|
||||
|
||||
TypeMap::map_by<name>::const_iterator it = type_map.by<name>().find(str);
|
||||
if( it == type_map.by<name>().end() )
|
||||
return UNKNOWN;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string Event::typeToStr(int type)
|
||||
{
|
||||
TypeMap const& type_map = getTypeMap();
|
||||
|
||||
TypeMap::map_by<id>::const_iterator it = type_map.by<id>().find(type);
|
||||
if( it == type_map.by<id>().end() )
|
||||
return "unknown";
|
||||
return it->second;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Event::TypeMap& Event::getTypeMap()
|
||||
{
|
||||
typedef std::map<std::string, Type> TypeMap;
|
||||
static TypeMap type_map;
|
||||
|
||||
if( type_map.empty() )
|
||||
{
|
||||
# define ENUM_MAPPING(type, str) type_map[ str ] = type;
|
||||
# include "CanvasEventTypes.hxx"
|
||||
# undef ENUM_MAPPING
|
||||
# define ENUM_MAPPING(type, str, class_name)\
|
||||
type_map.insert(TypeMap::value_type(str, type));
|
||||
# include "CanvasEventTypes.hxx"
|
||||
# undef ENUM_MAPPING
|
||||
}
|
||||
|
||||
TypeMap::const_iterator it = type_map.find(str);
|
||||
if( it == type_map.end() )
|
||||
return UNKNOWN;
|
||||
|
||||
return it->second;
|
||||
return type_map;
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Canvas Event for event model similar to DOM Level 3 Event Model
|
||||
/// @file
|
||||
/// Canvas Event for event model similar to DOM Level 3 Event Model
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -20,31 +21,43 @@
|
||||
#define CANVAS_EVENT_HXX_
|
||||
|
||||
#include "canvas_fwd.hxx"
|
||||
#include <boost/bimap.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class Event
|
||||
/**
|
||||
* Base class for all Canvas events.
|
||||
*
|
||||
* The event system is closely following the specification of the DOM Level 3
|
||||
* Event Model.
|
||||
*/
|
||||
class Event:
|
||||
public SGReferenced
|
||||
{
|
||||
public:
|
||||
|
||||
/// Event type identifier
|
||||
enum Type
|
||||
{
|
||||
UNKNOWN,
|
||||
# define ENUM_MAPPING(name, str) name,
|
||||
# define ENUM_MAPPING(name, str, class_name)\
|
||||
name, /*!< class_name (type=str) */
|
||||
# include "CanvasEventTypes.hxx"
|
||||
# undef ENUM_MAPPING
|
||||
USER_TYPE ///<! first unused id to be used for user defined types (not
|
||||
/// implemented yet)
|
||||
CUSTOM_EVENT ///< First event type id available for user defined event
|
||||
/// type.
|
||||
/// @see CustomEvent
|
||||
};
|
||||
|
||||
Type type;
|
||||
int type;
|
||||
ElementWeakPtr target,
|
||||
current_target;
|
||||
double time;
|
||||
bool propagation_stopped;
|
||||
bool propagation_stopped,
|
||||
default_prevented;
|
||||
|
||||
Event();
|
||||
|
||||
@@ -52,17 +65,64 @@ namespace canvas
|
||||
// of the actual event instances.
|
||||
virtual ~Event();
|
||||
|
||||
Type getType() const;
|
||||
/**
|
||||
* Get whether this events support bubbling
|
||||
*/
|
||||
virtual bool canBubble() const;
|
||||
|
||||
/**
|
||||
* Set type of event.
|
||||
*
|
||||
* If no such type exists it is registered.
|
||||
*/
|
||||
void setType(const std::string& type);
|
||||
|
||||
int getType() const;
|
||||
std::string getTypeString() const;
|
||||
|
||||
ElementWeakPtr getTarget() const;
|
||||
ElementWeakPtr getCurrentTarget() const;
|
||||
|
||||
/**
|
||||
* Get time at which the event was generated.
|
||||
*/
|
||||
double getTime() const;
|
||||
|
||||
/**
|
||||
* Prevent further propagation of the event during event flow.
|
||||
*
|
||||
* @note This does not prevent calling further event handlers registered
|
||||
* on the current event target.
|
||||
*/
|
||||
void stopPropagation();
|
||||
|
||||
static Type strToType(const std::string& str);
|
||||
/**
|
||||
* Cancel any default action normally taken as result of this event.
|
||||
*
|
||||
* @note For event handlers registered on the DesktopGroup (Nasal:
|
||||
* canvas.getDesktop()) this stops the event from being further
|
||||
* propagated to the normal FlightGear input event handling code.
|
||||
*/
|
||||
void preventDefault();
|
||||
|
||||
/**
|
||||
* Get if preventDefault() has been called.
|
||||
*/
|
||||
bool defaultPrevented() const;
|
||||
|
||||
static int getOrRegisterType(const std::string& type);
|
||||
static int strToType(const std::string& type);
|
||||
static std::string typeToStr(int type);
|
||||
|
||||
protected:
|
||||
struct name {};
|
||||
struct id {};
|
||||
typedef boost::bimaps::bimap<
|
||||
boost::bimaps::tagged<std::string, name>,
|
||||
boost::bimaps::tagged<int, id>
|
||||
> TypeMap;
|
||||
|
||||
static TypeMap& getTypeMap();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasEventManager.hxx"
|
||||
#include "MouseEvent.hxx"
|
||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||
#include <simgear/canvas/elements/CanvasElement.hxx>
|
||||
#include <cmath>
|
||||
|
||||
@@ -61,6 +61,16 @@ namespace canvas
|
||||
return !path.empty() && time > 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void EventManager::MouseEventInfo::set( const MouseEventPtr& event,
|
||||
const EventPropagationPath& p )
|
||||
{
|
||||
path = p;
|
||||
time = event->time;
|
||||
button = event->button;
|
||||
pos = event->screen_pos;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
EventManager::EventManager():
|
||||
_current_click_count(0)
|
||||
@@ -76,7 +86,7 @@ namespace canvas
|
||||
switch( event->type )
|
||||
{
|
||||
case Event::MOUSE_DOWN:
|
||||
_last_mouse_down = StampedPropagationPath(path, event->getTime());
|
||||
_last_mouse_down.set(event, path);
|
||||
break;
|
||||
case Event::MOUSE_UP:
|
||||
{
|
||||
@@ -89,12 +99,12 @@ namespace canvas
|
||||
// normal mouseup
|
||||
handled |= propagateEvent(event, path);
|
||||
|
||||
if( _last_mouse_down.path.empty() )
|
||||
if( !_last_mouse_down.valid() )
|
||||
// Ignore mouse up without any previous mouse down
|
||||
return handled;
|
||||
|
||||
// now handle click/dblclick
|
||||
if( checkClickDistance(path, _last_mouse_down.path) )
|
||||
if( checkClickDistance(event->screen_pos, _last_mouse_down.pos) )
|
||||
handled |=
|
||||
handleClick(event, getCommonAncestor(_last_mouse_down.path, path));
|
||||
|
||||
@@ -106,7 +116,11 @@ namespace canvas
|
||||
if( !_last_mouse_down.valid() )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
// OSG does not set button for drag events.
|
||||
event->button = _last_mouse_down.button;
|
||||
return propagateEvent(event, _last_mouse_down.path);
|
||||
}
|
||||
case Event::MOUSE_MOVE:
|
||||
handled |= handleMove(event, path);
|
||||
break;
|
||||
@@ -130,6 +144,71 @@ namespace canvas
|
||||
return handled | propagateEvent(event, path);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool EventManager::propagateEvent( const EventPtr& event,
|
||||
const EventPropagationPath& path )
|
||||
{
|
||||
event->target = path.back().element;
|
||||
MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get());
|
||||
|
||||
// Event propagation similar to DOM Level 3 event flow:
|
||||
// http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
|
||||
|
||||
// Position update only needed for drag event (as event needs to be
|
||||
// delivered to element of initial mousedown, but with update positions)
|
||||
if( mouse_event && mouse_event->type == MouseEvent::DRAG )
|
||||
{
|
||||
osg::Vec2f local_pos = mouse_event->client_pos;
|
||||
|
||||
// Capturing phase (currently just update position)
|
||||
for( EventPropagationPath::const_iterator it = path.begin();
|
||||
it != path.end();
|
||||
++it )
|
||||
{
|
||||
ElementPtr el = it->element.lock();
|
||||
if( !el )
|
||||
continue;
|
||||
|
||||
it->local_pos = local_pos = el->posToLocal(local_pos);
|
||||
}
|
||||
}
|
||||
|
||||
bool const do_bubble = event->canBubble();
|
||||
|
||||
// Bubbling phase
|
||||
for( EventPropagationPath::const_reverse_iterator
|
||||
it = path.rbegin();
|
||||
it != path.rend();
|
||||
++it )
|
||||
{
|
||||
ElementPtr el = it->element.lock();
|
||||
|
||||
if( !el )
|
||||
{
|
||||
// Ignore element if it has been destroyed while traversing the event
|
||||
// (eg. removed by another event handler)
|
||||
if( do_bubble )
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO provide functions to convert delta to local coordinates on demand.
|
||||
// Maybe also provide a clone method for events as local coordinates
|
||||
// might differ between different elements receiving the same event.
|
||||
if( mouse_event )
|
||||
mouse_event->local_pos = it->local_pos;
|
||||
|
||||
event->current_target = el;
|
||||
el->handleEvent(event);
|
||||
|
||||
if( event->propagation_stopped || !do_bubble )
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool EventManager::handleClick( const MouseEventPtr& event,
|
||||
const EventPropagationPath& path )
|
||||
@@ -146,8 +225,10 @@ namespace canvas
|
||||
|
||||
if( _current_click_count > 1 )
|
||||
{
|
||||
// Reset current click count if moved too far
|
||||
if( !checkClickDistance(path, _last_click.path) )
|
||||
// Reset current click count if moved too far or different button has
|
||||
// been clicked
|
||||
if( !checkClickDistance(event->screen_pos, _last_click.pos)
|
||||
|| _last_click.button != event->button )
|
||||
_current_click_count = 1;
|
||||
}
|
||||
}
|
||||
@@ -167,7 +248,7 @@ namespace canvas
|
||||
handled |= propagateEvent( dbl_click,
|
||||
getCommonAncestor(_last_click.path, path) );
|
||||
|
||||
_last_click = StampedPropagationPath(path, event->getTime());
|
||||
_last_click.set(event, path);
|
||||
|
||||
return handled;
|
||||
}
|
||||
@@ -233,89 +314,12 @@ namespace canvas
|
||||
return handled;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool EventManager::propagateEvent( const EventPtr& event,
|
||||
const EventPropagationPath& path )
|
||||
{
|
||||
event->target = path.back().element;
|
||||
MouseEventPtr mouse_event = boost::dynamic_pointer_cast<MouseEvent>(event);
|
||||
|
||||
// Event propagation similar to DOM Level 3 event flow:
|
||||
// http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
|
||||
|
||||
// Capturing phase
|
||||
// for( EventPropagationPath::const_iterator it = path.begin();
|
||||
// it != path.end();
|
||||
// ++it )
|
||||
// {
|
||||
// if( !it->element.expired() )
|
||||
// std::cout << it->element.lock()->getProps()->getPath() << std::endl;
|
||||
// }
|
||||
|
||||
// Check if event supports bubbling
|
||||
const Event::Type types_no_bubbling[] = {
|
||||
Event::MOUSE_ENTER,
|
||||
Event::MOUSE_LEAVE,
|
||||
};
|
||||
const size_t num_types_no_bubbling = sizeof(types_no_bubbling)
|
||||
/ sizeof(types_no_bubbling[0]);
|
||||
bool do_bubble = true;
|
||||
for( size_t i = 0; i < num_types_no_bubbling; ++i )
|
||||
if( event->type == types_no_bubbling[i] )
|
||||
{
|
||||
do_bubble = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Bubbling phase
|
||||
for( EventPropagationPath::const_reverse_iterator
|
||||
it = path.rbegin();
|
||||
it != path.rend();
|
||||
++it )
|
||||
{
|
||||
ElementPtr el = it->element.lock();
|
||||
|
||||
if( !el )
|
||||
{
|
||||
// Ignore element if it has been destroyed while traversing the event
|
||||
// (eg. removed by another event handler)
|
||||
if( do_bubble )
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO provide functions to convert delta to local coordinates on demand.
|
||||
// Maybe also provide a clone method for events as local coordinates
|
||||
// might differ between different elements receiving the same event.
|
||||
if( mouse_event ) //&& event->type != Event::DRAG )
|
||||
{
|
||||
// TODO transform pos and delta for drag events. Maybe we should just
|
||||
// store the global coordinates and convert to local coordinates
|
||||
// on demand.
|
||||
|
||||
// Position and delta are specified in local coordinate system of
|
||||
// current element
|
||||
mouse_event->local_pos = it->local_pos;
|
||||
//mouse_event->delta = it->local_delta;
|
||||
}
|
||||
|
||||
event->current_target = el;
|
||||
el->handleEvent(event);
|
||||
|
||||
if( event->propagation_stopped || !do_bubble )
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
EventManager::checkClickDistance( const EventPropagationPath& path1,
|
||||
const EventPropagationPath& path2 ) const
|
||||
EventManager::checkClickDistance( const osg::Vec2f& pos1,
|
||||
const osg::Vec2f& pos2 ) const
|
||||
{
|
||||
osg::Vec2 delta = path1.front().local_pos - path2.front().local_pos;
|
||||
osg::Vec2 delta = pos1 - pos2;
|
||||
return std::fabs(delta.x()) < drag_threshold
|
||||
&& std::fabs(delta.y()) < drag_threshold;
|
||||
}
|
||||
|
||||
@@ -29,11 +29,18 @@ namespace canvas
|
||||
|
||||
struct EventTarget
|
||||
{
|
||||
ElementWeakPtr element;
|
||||
osg::Vec2f local_pos,
|
||||
local_delta;
|
||||
ElementWeakPtr element;
|
||||
|
||||
// Used as storage by EventManager during event propagation
|
||||
mutable osg::Vec2f local_pos;
|
||||
|
||||
EventTarget( Element* el,
|
||||
const osg::Vec2f pos = osg::Vec2f() ):
|
||||
element(el),
|
||||
local_pos(pos)
|
||||
{}
|
||||
};
|
||||
typedef std::deque<EventTarget> EventPropagationPath;
|
||||
|
||||
inline bool operator==(const EventTarget& t1, const EventTarget& t2)
|
||||
{
|
||||
return t1.element.lock() == t2.element.lock();
|
||||
@@ -47,6 +54,9 @@ namespace canvas
|
||||
bool handleEvent( const MouseEventPtr& event,
|
||||
const EventPropagationPath& path );
|
||||
|
||||
bool propagateEvent( const EventPtr& event,
|
||||
const EventPropagationPath& path );
|
||||
|
||||
protected:
|
||||
struct StampedPropagationPath
|
||||
{
|
||||
@@ -62,11 +72,20 @@ namespace canvas
|
||||
|
||||
// TODO if we really need the paths modify to not copy around the paths
|
||||
// that much.
|
||||
StampedPropagationPath _last_mouse_down,
|
||||
_last_click,
|
||||
_last_mouse_over;
|
||||
StampedPropagationPath _last_mouse_over;
|
||||
size_t _current_click_count;
|
||||
|
||||
struct MouseEventInfo:
|
||||
public StampedPropagationPath
|
||||
{
|
||||
int button;
|
||||
osg::Vec2f pos;
|
||||
|
||||
void set( const MouseEventPtr& event,
|
||||
const EventPropagationPath& path );
|
||||
} _last_mouse_down,
|
||||
_last_click;
|
||||
|
||||
/**
|
||||
* Propagate click event and handle multi-click (eg. create dblclick)
|
||||
*/
|
||||
@@ -79,16 +98,13 @@ namespace canvas
|
||||
bool handleMove( const MouseEventPtr& event,
|
||||
const EventPropagationPath& path );
|
||||
|
||||
bool propagateEvent( const EventPtr& event,
|
||||
const EventPropagationPath& path );
|
||||
|
||||
/**
|
||||
* Check if two click events (either mousedown/up or two consecutive
|
||||
* clicks) are inside a maximum distance to still create a click or
|
||||
* dblclick event respectively.
|
||||
*/
|
||||
bool checkClickDistance( const EventPropagationPath& path1,
|
||||
const EventPropagationPath& path2 ) const;
|
||||
bool checkClickDistance( const osg::Vec2f& pos1,
|
||||
const osg::Vec2f& pos2 ) const;
|
||||
EventPropagationPath
|
||||
getCommonAncestor( const EventPropagationPath& path1,
|
||||
const EventPropagationPath& path2 ) const;
|
||||
|
||||
@@ -20,14 +20,17 @@
|
||||
# error "Don't include this file directly!"
|
||||
#endif
|
||||
|
||||
ENUM_MAPPING(MOUSE_DOWN, "mousedown")
|
||||
ENUM_MAPPING(MOUSE_UP, "mouseup")
|
||||
ENUM_MAPPING(CLICK, "click")
|
||||
ENUM_MAPPING(DBL_CLICK, "dblclick")
|
||||
ENUM_MAPPING(DRAG, "drag")
|
||||
ENUM_MAPPING(WHEEL, "wheel")
|
||||
ENUM_MAPPING(MOUSE_MOVE, "mousemove")
|
||||
ENUM_MAPPING(MOUSE_OVER, "mouseover")
|
||||
ENUM_MAPPING(MOUSE_OUT, "mouseout")
|
||||
ENUM_MAPPING(MOUSE_ENTER, "mouseenter")
|
||||
ENUM_MAPPING(MOUSE_LEAVE, "mouseleave")
|
||||
ENUM_MAPPING(MOUSE_DOWN, "mousedown", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_UP, "mouseup", MouseEvent)
|
||||
ENUM_MAPPING(CLICK, "click", MouseEvent)
|
||||
ENUM_MAPPING(DBL_CLICK, "dblclick", MouseEvent)
|
||||
ENUM_MAPPING(DRAG, "drag", MouseEvent)
|
||||
ENUM_MAPPING(WHEEL, "wheel", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_MOVE, "mousemove", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_OVER, "mouseover", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_OUT, "mouseout", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_ENTER, "mouseenter", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_LEAVE, "mouseleave", MouseEvent)
|
||||
ENUM_MAPPING(KEY_DOWN, "keydown", KeyboardEvent)
|
||||
ENUM_MAPPING(KEY_UP, "keyup", KeyboardEvent)
|
||||
ENUM_MAPPING(KEY_PRESS, "keypress", KeyboardEvent)
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "CanvasEvent.hxx"
|
||||
#include "CanvasEventVisitor.hxx"
|
||||
#include <simgear/canvas/elements/CanvasElement.hxx>
|
||||
#include <iostream>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@@ -30,16 +29,12 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
EventVisitor::EventVisitor( TraverseMode mode,
|
||||
const osg::Vec2f& pos,
|
||||
const osg::Vec2f& delta,
|
||||
const ElementPtr& root ):
|
||||
_traverse_mode( mode ),
|
||||
_root(root)
|
||||
{
|
||||
if( mode == TRAVERSE_DOWN )
|
||||
{
|
||||
EventTarget target = {ElementWeakPtr(), pos, delta};
|
||||
_target_path.push_back(target);
|
||||
}
|
||||
_target_path.push_back( EventTarget(NULL, pos) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -63,31 +58,18 @@ namespace canvas
|
||||
// We only need to check for hits while traversing down
|
||||
if( _traverse_mode == TRAVERSE_DOWN )
|
||||
{
|
||||
// Transform event to local coordinates
|
||||
const osg::Matrix& m = el.getMatrixTransform()->getInverseMatrix();
|
||||
const osg::Vec2f& pos = _target_path.back().local_pos;
|
||||
const osg::Vec2f local_pos
|
||||
(
|
||||
m(0, 0) * pos[0] + m(1, 0) * pos[1] + m(3, 0),
|
||||
m(0, 1) * pos[0] + m(1, 1) * pos[1] + m(3, 1)
|
||||
);
|
||||
const osg::Vec2f local_pos = el.posToLocal(pos);
|
||||
|
||||
// Don't check specified root element for collision, as its purpose is to
|
||||
// catch all events which have no target. This allows for example calling
|
||||
// event listeners attached to the canvas itself (its root group) even if
|
||||
// no element has been hit.
|
||||
if( _root.get() != &el && !el.hitBound(pos, local_pos) )
|
||||
if( _root.get() != &el
|
||||
&& !el.hitBound(_target_path.front().local_pos, pos, local_pos) )
|
||||
return false;
|
||||
|
||||
const osg::Vec2f& delta = _target_path.back().local_delta;
|
||||
const osg::Vec2f local_delta
|
||||
(
|
||||
m(0, 0) * delta[0] + m(1, 0) * delta[1],
|
||||
m(0, 1) * delta[0] + m(1, 1) * delta[1]
|
||||
);
|
||||
|
||||
EventTarget target = {el.getWeakPtr(), local_pos, local_delta};
|
||||
_target_path.push_back(target);
|
||||
_target_path.push_back( EventTarget(&el, local_pos) );
|
||||
|
||||
if( el.traverse(*this) || &el == _root.get() )
|
||||
return true;
|
||||
|
||||
@@ -42,12 +42,10 @@ namespace canvas
|
||||
*
|
||||
* @param mode
|
||||
* @param pos Mouse position
|
||||
* @param delta Mouse movement since last mouse move event
|
||||
* @param root Element to dispatch events to if no element is hit
|
||||
*/
|
||||
EventVisitor( TraverseMode mode,
|
||||
const osg::Vec2f& pos,
|
||||
const osg::Vec2f& delta,
|
||||
const ElementPtr& root = ElementPtr() );
|
||||
virtual ~EventVisitor();
|
||||
virtual bool traverse(Element& el);
|
||||
|
||||
@@ -45,25 +45,25 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
CanvasPtr CanvasMgr::createCanvas(const std::string& name)
|
||||
{
|
||||
return boost::static_pointer_cast<Canvas>( createElement(name) );
|
||||
return static_cast<Canvas*>( createElement(name).get() );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CanvasPtr CanvasMgr::getCanvas(size_t index) const
|
||||
{
|
||||
return boost::static_pointer_cast<Canvas>( getElement(index) );
|
||||
return static_cast<Canvas*>( getElement(index).get() );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CanvasPtr CanvasMgr::getCanvas(const std::string& name) const
|
||||
{
|
||||
return boost::static_pointer_cast<Canvas>( getElement(name) );
|
||||
return static_cast<Canvas*>( getElement(name).get() );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void CanvasMgr::elementCreated(PropertyBasedElementPtr element)
|
||||
{
|
||||
CanvasPtr canvas = boost::static_pointer_cast<Canvas>(element);
|
||||
CanvasPtr canvas = static_cast<Canvas*>(element.get());
|
||||
canvas->setCanvasMgr(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace canvas
|
||||
public:
|
||||
|
||||
/**
|
||||
* @param node Root node of branch used to control canvasses
|
||||
* @param node Root node of branch used to control canvasses
|
||||
*/
|
||||
CanvasMgr(SGPropertyNode_ptr node);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "Canvas.hxx"
|
||||
#include "CanvasObjectPlacement.hxx"
|
||||
#include "MouseEvent.hxx"
|
||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/scene/util/SGPickCallback.hxx>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Canvas placement for placing a canvas texture onto osg objects.
|
||||
//
|
||||
// It also provides a SGPickCallback for passing mouse events to the canvas and
|
||||
// manages emissive lighting of the placed canvas.
|
||||
///@file
|
||||
/// Placement for putting a canvas texture onto OpenSceneGraph objects.
|
||||
///
|
||||
/// It also provides a SGPickCallback for passing mouse events to the canvas and
|
||||
/// manages emissive lighting of the placed canvas.
|
||||
//
|
||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -19,7 +20,7 @@
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_PICK_PLACEMENT_HXX_
|
||||
#ifndef CANVAS_OBJECT_PLACEMENT_HXX_
|
||||
#define CANVAS_OBJECT_PLACEMENT_HXX_
|
||||
|
||||
#include "CanvasPlacement.hxx"
|
||||
@@ -33,6 +34,9 @@ namespace simgear
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Place a Canvas onto an osg object (as texture).
|
||||
*/
|
||||
class ObjectPlacement:
|
||||
public Placement
|
||||
{
|
||||
@@ -72,4 +76,4 @@ namespace canvas
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_PICK_PLACEMENT_HXX_ */
|
||||
#endif /* CANVAS_OBJECT_PLACEMENT_HXX_ */
|
||||
|
||||
@@ -21,8 +21,11 @@
|
||||
|
||||
#include "canvas_fwd.hxx"
|
||||
|
||||
class SGSubsystem;
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace HTTP { class Client; }
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
@@ -34,7 +37,9 @@ namespace canvas
|
||||
virtual FontPtr getFont(const std::string& name) const = 0;
|
||||
virtual void addCamera(osg::Camera* camera) const = 0;
|
||||
virtual void removeCamera(osg::Camera* camera) const = 0;
|
||||
virtual osg::Image* getImage(const std::string& path) const = 0;
|
||||
virtual osg::ref_ptr<osg::Image> getImage(const std::string& path) const = 0;
|
||||
virtual SGSubsystem* getSubsystem(const std::string& name) const = 0;
|
||||
virtual HTTP::Client* getHTTPClient() const = 0;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
346
simgear/canvas/CanvasWindow.cxx
Normal file
346
simgear/canvas/CanvasWindow.cxx
Normal file
@@ -0,0 +1,346 @@
|
||||
// Window for placing a Canvas onto it (for dialogs, menus, etc.)
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasMgr.hxx"
|
||||
#include "CanvasSystemAdapter.hxx"
|
||||
#include "CanvasWindow.hxx"
|
||||
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/scene/util/OsgMath.hxx>
|
||||
|
||||
#include <osgGA/GUIEventHandler>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const std::string Window::TYPE_NAME = "window";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Window::Window( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
Image(canvas, node, parent_style, parent),
|
||||
_attributes_dirty(0),
|
||||
_resizable(false),
|
||||
_capture_events(true),
|
||||
_resize_top(node, "resize-top"),
|
||||
_resize_right(node, "resize-right"),
|
||||
_resize_bottom(node, "resize-bottom"),
|
||||
_resize_left(node, "resize-left"),
|
||||
_resize_status(node, "resize-status")
|
||||
{
|
||||
node->setFloatValue("source/right", 1);
|
||||
node->setFloatValue("source/bottom", 1);
|
||||
node->setBoolValue("source/normalized", true);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Window::~Window()
|
||||
{
|
||||
if( _canvas_decoration )
|
||||
_canvas_decoration->destroy();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::update(double delta_time_sec)
|
||||
{
|
||||
if( _attributes_dirty & DECORATION )
|
||||
{
|
||||
updateDecoration();
|
||||
_attributes_dirty &= ~DECORATION;
|
||||
}
|
||||
|
||||
Image::update(delta_time_sec);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::valueChanged(SGPropertyNode * node)
|
||||
{
|
||||
bool handled = false;
|
||||
if( node->getParent() == _node )
|
||||
{
|
||||
handled = true;
|
||||
const std::string& name = node->getNameString();
|
||||
if( name == "resize" )
|
||||
_resizable = node->getBoolValue();
|
||||
else if( name == "update" )
|
||||
update(0);
|
||||
else if( name == "capture-events" )
|
||||
_capture_events = node->getBoolValue();
|
||||
else if( name == "decoration-border" )
|
||||
parseDecorationBorder(node->getStringValue());
|
||||
else if( boost::starts_with(name, "shadow-")
|
||||
|| name == "content-size" )
|
||||
_attributes_dirty |= DECORATION;
|
||||
else
|
||||
handled = false;
|
||||
}
|
||||
|
||||
if( !handled )
|
||||
Image::valueChanged(node);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Group* Window::getGroup()
|
||||
{
|
||||
return getMatrixTransform();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const SGVec2<float> Window::getPosition() const
|
||||
{
|
||||
const osg::Matrix& m = getMatrixTransform()->getMatrix();
|
||||
return SGVec2<float>( m(3, 0), m(3, 1) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const SGRect<float> Window::getScreenRegion() const
|
||||
{
|
||||
return getPosition() + getRegion();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::setCanvasContent(CanvasPtr canvas)
|
||||
{
|
||||
_canvas_content = canvas;
|
||||
if( _layout )
|
||||
{
|
||||
canvas->setLayout(_layout);
|
||||
_layout.clear();
|
||||
}
|
||||
|
||||
if( _image_content )
|
||||
// Placement within decoration canvas
|
||||
_image_content->setSrcCanvas(canvas);
|
||||
else
|
||||
setSrcCanvas(canvas);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CanvasWeakPtr Window::getCanvasContent() const
|
||||
{
|
||||
return _canvas_content;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::setLayout(const LayoutRef& layout)
|
||||
{
|
||||
CanvasPtr canvas = _canvas_content.lock();
|
||||
if( canvas )
|
||||
canvas->setLayout(layout);
|
||||
else
|
||||
_layout = layout; // keep layout until content canvas is set
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
CanvasPtr Window::getCanvasDecoration() const
|
||||
{
|
||||
return _canvas_decoration;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Window::isResizable() const
|
||||
{
|
||||
return _resizable;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Window::isCapturingEvents() const
|
||||
{
|
||||
return _capture_events;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::setVisible(bool visible)
|
||||
{
|
||||
LayoutItem::setVisible(visible);
|
||||
Element::setVisible(LayoutItem::isVisible());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Window::isVisible() const
|
||||
{
|
||||
return Element::isVisible();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::raise()
|
||||
{
|
||||
// on writing the z-index the window always is moved to the top of all other
|
||||
// windows with the same z-index.
|
||||
set<int>("z-index", get<int>("z-index", 0));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::handleResize( uint8_t mode,
|
||||
const osg::Vec2f& offset )
|
||||
{
|
||||
if( mode == NONE )
|
||||
{
|
||||
_resize_status = 0;
|
||||
return;
|
||||
}
|
||||
else if( mode & INIT )
|
||||
{
|
||||
_resize_top = getRegion().t();
|
||||
_resize_right = getRegion().r();
|
||||
_resize_bottom = getRegion().b();
|
||||
_resize_left = getRegion().l();
|
||||
_resize_status = 1;
|
||||
}
|
||||
|
||||
if( mode & BOTTOM )
|
||||
_resize_bottom = getRegion().b() + offset.y();
|
||||
else if( mode & TOP )
|
||||
_resize_top = getRegion().t() + offset.y();
|
||||
|
||||
if( mode & canvas::Window::RIGHT )
|
||||
_resize_right = getRegion().r() + offset.x();
|
||||
else if( mode & canvas::Window::LEFT )
|
||||
_resize_left = getRegion().l() + offset.x();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::parseDecorationBorder(const std::string& str)
|
||||
{
|
||||
_decoration_border = simgear::CSSBorder::parse(str);
|
||||
_attributes_dirty |= DECORATION;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::updateDecoration()
|
||||
{
|
||||
int shadow_radius = get<float>("shadow-radius") + 0.5;
|
||||
if( shadow_radius < 2 )
|
||||
shadow_radius = 0;
|
||||
|
||||
CanvasPtr content = _canvas_content.lock();
|
||||
SGRect<int> content_view
|
||||
(
|
||||
0,
|
||||
0,
|
||||
get<int>("content-size[0]", content ? content->getViewWidth() : 400),
|
||||
get<int>("content-size[1]", content ? content->getViewHeight() : 300)
|
||||
);
|
||||
|
||||
if( _decoration_border.isNone() && !shadow_radius )
|
||||
{
|
||||
setSrcCanvas(content);
|
||||
set<int>("size[0]", content_view.width());
|
||||
set<int>("size[1]", content_view.height());
|
||||
|
||||
_image_content.reset();
|
||||
_image_shadow.reset();
|
||||
if( _canvas_decoration )
|
||||
_canvas_decoration->destroy();
|
||||
_canvas_decoration.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if( !_canvas_decoration )
|
||||
{
|
||||
CanvasMgr* mgr = dynamic_cast<CanvasMgr*>(
|
||||
Canvas::getSystemAdapter()->getSubsystem("Canvas")
|
||||
);
|
||||
|
||||
if( !mgr )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "canvas::Window: no canvas manager!");
|
||||
return;
|
||||
}
|
||||
|
||||
_canvas_decoration = mgr->createCanvas("window-decoration");
|
||||
_canvas_decoration->getProps()
|
||||
->setStringValue("background", "rgba(0,0,0,0)");
|
||||
setSrcCanvas(_canvas_decoration);
|
||||
|
||||
_image_content = _canvas_decoration->getRootGroup()
|
||||
->createChild<Image>("content");
|
||||
_image_content->setSrcCanvas(content);
|
||||
|
||||
// Forward keyboard events to content
|
||||
_image_content->setFocus();
|
||||
|
||||
// Draw content on top of decoration
|
||||
_image_content->set<int>("z-index", 1);
|
||||
}
|
||||
|
||||
GroupPtr group_decoration =
|
||||
_canvas_decoration->getOrCreateGroup("decoration");
|
||||
group_decoration->set<int>("tf/t[0]", shadow_radius);
|
||||
group_decoration->set<int>("tf/t[1]", shadow_radius);
|
||||
// TODO do we need clipping or shall we trust the decorator not to draw over
|
||||
// the shadow?
|
||||
|
||||
CSSBorder::Offsets const border =
|
||||
_decoration_border.getAbsOffsets(content_view);
|
||||
|
||||
int shad2 = 2 * shadow_radius,
|
||||
outer_width = border.l + content_view.width() + border.r + shad2,
|
||||
outer_height = border.t + content_view.height() + border.b + shad2;
|
||||
|
||||
_canvas_decoration->setSizeX( outer_width );
|
||||
_canvas_decoration->setSizeY( outer_height );
|
||||
_canvas_decoration->setViewWidth( outer_width );
|
||||
_canvas_decoration->setViewHeight( outer_height );
|
||||
|
||||
set<int>("size[0]", outer_width - shad2);
|
||||
set<int>("size[1]", outer_height - shad2);
|
||||
set<int>("outset", shadow_radius);
|
||||
|
||||
assert(_image_content);
|
||||
_image_content->set<int>("x", shadow_radius + border.l);
|
||||
_image_content->set<int>("y", shadow_radius + border.t);
|
||||
_image_content->set<int>("size[0]", content_view.width());
|
||||
_image_content->set<int>("size[1]", content_view.height());
|
||||
|
||||
if( !shadow_radius )
|
||||
{
|
||||
if( _image_shadow )
|
||||
{
|
||||
_image_shadow->destroy();
|
||||
_image_shadow.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int shadow_inset = std::max<int>(get<float>("shadow-inset") + 0.5, 0),
|
||||
slice_width = shadow_radius + shadow_inset;
|
||||
|
||||
_image_shadow = _canvas_decoration->getRootGroup()
|
||||
->getOrCreateChild<Image>("shadow");
|
||||
_image_shadow->set<std::string>("src", "gui/images/shadow.png");
|
||||
_image_shadow->set<float>("slice", 7);
|
||||
_image_shadow->set<std::string>("fill", "#000000");
|
||||
_image_shadow->set<float>("slice-width", slice_width);
|
||||
_image_shadow->set<int>("size[0]", outer_width);
|
||||
_image_shadow->set<int>("size[1]", outer_height);
|
||||
|
||||
// Draw shadow below decoration
|
||||
_image_shadow->set<int>("z-index", -1);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
134
simgear/canvas/CanvasWindow.hxx
Normal file
134
simgear/canvas/CanvasWindow.hxx
Normal file
@@ -0,0 +1,134 @@
|
||||
// Window for placing a Canvas onto it (for dialogs, menus, etc.)
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef CANVAS_WINDOW_HXX_
|
||||
#define CANVAS_WINDOW_HXX_
|
||||
|
||||
#include <simgear/canvas/elements/CanvasImage.hxx>
|
||||
#include <simgear/canvas/layout/Layout.hxx>
|
||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||
#include <simgear/props/PropertyBasedElement.hxx>
|
||||
#include <simgear/props/propertyObject.hxx>
|
||||
#include <simgear/misc/CSSBorder.hxx>
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class Window:
|
||||
public Image,
|
||||
public LayoutItem
|
||||
{
|
||||
public:
|
||||
static const std::string TYPE_NAME;
|
||||
|
||||
enum Resize
|
||||
{
|
||||
NONE = 0,
|
||||
LEFT = 1,
|
||||
RIGHT = LEFT << 1,
|
||||
TOP = RIGHT << 1,
|
||||
BOTTOM = TOP << 1,
|
||||
INIT = BOTTOM << 1
|
||||
};
|
||||
|
||||
/**
|
||||
* @param node Property node containing settings for this window:
|
||||
* capture-events Disable/Enable event capturing
|
||||
* content-size[0-1] Size of content area (excluding
|
||||
* decoration border)
|
||||
* decoration-border Size of decoration border
|
||||
* resize Enable resize cursor and properties
|
||||
* shadow-inset Inset of shadow image
|
||||
* shadow-radius Radius/outset of shadow image
|
||||
*/
|
||||
Window( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style = Style(),
|
||||
Element* parent = 0 );
|
||||
virtual ~Window();
|
||||
|
||||
virtual void update(double delta_time_sec);
|
||||
virtual void valueChanged(SGPropertyNode* node);
|
||||
|
||||
osg::Group* getGroup();
|
||||
const SGVec2<float> getPosition() const;
|
||||
const SGRect<float> getScreenRegion() const;
|
||||
|
||||
void setCanvasContent(CanvasPtr canvas);
|
||||
simgear::canvas::CanvasWeakPtr getCanvasContent() const;
|
||||
|
||||
void setLayout(const LayoutRef& layout);
|
||||
|
||||
CanvasPtr getCanvasDecoration() const;
|
||||
|
||||
bool isResizable() const;
|
||||
bool isCapturingEvents() const;
|
||||
|
||||
virtual void setVisible(bool visible);
|
||||
virtual bool isVisible() const;
|
||||
|
||||
/**
|
||||
* Moves window on top of all other windows with the same z-index.
|
||||
*
|
||||
* @note If no z-index is set it defaults to 0.
|
||||
*/
|
||||
void raise();
|
||||
|
||||
void handleResize( uint8_t mode,
|
||||
const osg::Vec2f& offset = osg::Vec2f() );
|
||||
|
||||
protected:
|
||||
|
||||
enum Attributes
|
||||
{
|
||||
DECORATION = 1
|
||||
};
|
||||
|
||||
uint32_t _attributes_dirty;
|
||||
|
||||
CanvasPtr _canvas_decoration;
|
||||
CanvasWeakPtr _canvas_content;
|
||||
LayoutRef _layout;
|
||||
|
||||
ImagePtr _image_content,
|
||||
_image_shadow;
|
||||
|
||||
bool _resizable,
|
||||
_capture_events;
|
||||
|
||||
PropertyObject<int> _resize_top,
|
||||
_resize_right,
|
||||
_resize_bottom,
|
||||
_resize_left,
|
||||
_resize_status;
|
||||
|
||||
CSSBorder _decoration_border;
|
||||
|
||||
void parseDecorationBorder(const std::string& str);
|
||||
void updateDecoration();
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_WINDOW_HXX_ */
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <osg/ShadeModel>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
|
||||
#include <osg/Version>
|
||||
#include <osgUtil/RenderBin>
|
||||
|
||||
#include <cassert>
|
||||
@@ -266,7 +267,15 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::reinit()
|
||||
{
|
||||
osg::NodeCallback* cull_callback = camera ? camera->getCullCallback() : 0;
|
||||
osg::NodeCallback* cull_callback =
|
||||
camera
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
? camera->getCullCallback()
|
||||
#else
|
||||
? dynamic_cast<osg::NodeCallback*>(camera->getCullCallback())
|
||||
#endif
|
||||
: 0;
|
||||
|
||||
clear();
|
||||
allocRT(cull_callback);
|
||||
}
|
||||
|
||||
@@ -38,4 +38,9 @@
|
||||
|
||||
#endif
|
||||
|
||||
// We currently do not support using images (inside paths). If we were going to
|
||||
// use it loading and unloading needs to happen within OpenSceneGraph to handle
|
||||
// synchronization correctly in multithreading mode.
|
||||
#define SH_NO_IMAGE
|
||||
|
||||
#endif // __SHCONFIG_H
|
||||
|
||||
@@ -53,7 +53,7 @@ VG_API_CALL VGboolean vgCreateContextSH(VGint width, VGint height)
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0,width,0,height);
|
||||
glOrtho(0, width, 0, height, -1, 1);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();*/
|
||||
@@ -79,7 +79,7 @@ VG_API_CALL void vgResizeSurfaceSH(VGint width, VGint height)
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0,width,0,height);
|
||||
glOrtho(0, width, 0, height, -1, 1);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
#ifndef VG_API_MACOSX
|
||||
#if !defined(VG_API_MACOSX) && !defined(__FreeBSD__)
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
@@ -156,20 +156,16 @@ SHfloat getMaxFloat();
|
||||
|
||||
/* OpenGL headers */
|
||||
|
||||
#if defined(VG_API_LINUX)
|
||||
#if defined(VG_API_LINUX) || defined(VG_API_FREEBSD)
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glx.h>
|
||||
#elif defined(VG_API_MACOSX)
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#elif defined(VG_API_WINDOWS)
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#else
|
||||
#define GL_GLEXT_LEGACY /* don't include glext.h */
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glx.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#define _ARRAY_DEFINE
|
||||
#include "shArrayBase.h"
|
||||
|
||||
#ifndef SH_NO_IMAGE
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Prepares the proper pixel pack/unpack info for the given
|
||||
@@ -440,6 +441,7 @@ void shLoadColor(SHColor *c, const void *data, SHImageFormatDesc *f)
|
||||
if (f->rmask == 0x0) { c->r = 1.0f; c->g = 1.0f; c->b = 1.0f; }
|
||||
}
|
||||
|
||||
#endif // SH_NO_IMAGE
|
||||
|
||||
/*----------------------------------------------
|
||||
* Color and Image constructors and destructors
|
||||
@@ -461,18 +463,28 @@ void SHImage_ctor(SHImage *i)
|
||||
i->data = NULL;
|
||||
i->width = 0;
|
||||
i->height = 0;
|
||||
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
glGenTextures(1, &i->texture);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SHImage_dtor(SHImage *i)
|
||||
{
|
||||
if (i->data != NULL)
|
||||
free(i->data);
|
||||
|
||||
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
if (glIsTexture(i->texture))
|
||||
glDeleteTextures(1, &i->texture);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SH_NO_IMAGE
|
||||
/*--------------------------------------------------------
|
||||
* Finds appropriate OpenGL texture size for the size of
|
||||
* the given image
|
||||
@@ -553,6 +565,7 @@ void shUpdateImageTexture(SHImage *i, VGContext *c)
|
||||
i->texwidth, i->texheight, 0,
|
||||
i->fd.glformat, i->fd.gltype, i->data);
|
||||
}
|
||||
#endif // SH_NO_IMAGE
|
||||
|
||||
/*----------------------------------------------------------
|
||||
* Creates a new image object and returns the handle to it
|
||||
@@ -562,6 +575,10 @@ VG_API_CALL VGImage vgCreateImage(VGImageFormat format,
|
||||
VGint width, VGint height,
|
||||
VGbitfield allowedQuality)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
return VG_INVALID_HANDLE;
|
||||
#else
|
||||
SHImage *i = NULL;
|
||||
SHImageFormatDesc fd;
|
||||
VG_GETCONTEXT(VG_INVALID_HANDLE);
|
||||
@@ -614,12 +631,16 @@ VG_API_CALL VGImage vgCreateImage(VGImageFormat format,
|
||||
|
||||
/* Add to resource list */
|
||||
shImageArrayPushBack(&context->images, i);
|
||||
|
||||
|
||||
VG_RETURN((VGImage)i);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
VG_API_CALL void vgDestroyImage(VGImage image)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
SHint index;
|
||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||
|
||||
@@ -630,8 +651,9 @@ VG_API_CALL void vgDestroyImage(VGImage image)
|
||||
/* Delete object and remove resource */
|
||||
SH_DELETEOBJ(SHImage, (SHImage*)image);
|
||||
shImageArrayRemoveAt(&context->images, index);
|
||||
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
/*---------------------------------------------------
|
||||
@@ -642,6 +664,9 @@ VG_API_CALL void vgDestroyImage(VGImage image)
|
||||
VG_API_CALL void vgClearImage(VGImage image,
|
||||
VGint x, VGint y, VGint width, VGint height)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
SHImage *i;
|
||||
SHColor clear;
|
||||
SHuint8 *data;
|
||||
@@ -682,9 +707,13 @@ VG_API_CALL void vgClearImage(VGImage image,
|
||||
}}
|
||||
|
||||
shUpdateImageTexture(i, context);
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
#ifndef SH_NO_IMAGE
|
||||
|
||||
/*------------------------------------------------------------
|
||||
* Generic function for copying a rectangle area of pixels
|
||||
* of size (width,height) among two data buffers. The size of
|
||||
@@ -795,6 +824,8 @@ void shCopyPixels(SHuint8 *dst, VGImageFormat dstFormat, SHint dstStride,
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SH_NO_IMAGE
|
||||
|
||||
/*---------------------------------------------------------
|
||||
* Copies a rectangle area of pixels of size (width,height)
|
||||
* from given data buffer to image surface at destination
|
||||
@@ -806,6 +837,9 @@ VG_API_CALL void vgImageSubData(VGImage image,
|
||||
VGImageFormat dataFormat,
|
||||
VGint x, VGint y, VGint width, VGint height)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
SHImage *i;
|
||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||
|
||||
@@ -836,7 +870,9 @@ VG_API_CALL void vgImageSubData(VGImage image,
|
||||
x, y, 0, 0, width, height);
|
||||
|
||||
shUpdateImageTexture(i, context);
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
@@ -851,6 +887,9 @@ VG_API_CALL void vgGetImageSubData(VGImage image,
|
||||
VGint x, VGint y,
|
||||
VGint width, VGint height)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
SHImage *i;
|
||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||
|
||||
@@ -878,9 +917,10 @@ VG_API_CALL void vgGetImageSubData(VGImage image,
|
||||
shCopyPixels(data, dataFormat, dataStride,
|
||||
i->data, i->fd.vgformat, i->texwidth * i->fd.bytes,
|
||||
width, height, i->width, i->height,
|
||||
0,0,x,x,width,height);
|
||||
|
||||
0,0,x,y,width,height);
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------
|
||||
@@ -894,6 +934,9 @@ VG_API_CALL void vgCopyImage(VGImage dst, VGint dx, VGint dy,
|
||||
VGint width, VGint height,
|
||||
VGboolean dither)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
SHImage *s, *d;
|
||||
SHuint8 *pixels;
|
||||
|
||||
@@ -933,7 +976,9 @@ VG_API_CALL void vgCopyImage(VGImage dst, VGint dx, VGint dy,
|
||||
free(pixels);
|
||||
|
||||
shUpdateImageTexture(d, context);
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
@@ -946,6 +991,9 @@ VG_API_CALL void vgSetPixels(VGint dx, VGint dy,
|
||||
VGImage src, VGint sx, VGint sy,
|
||||
VGint width, VGint height)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
SHImage *i;
|
||||
SHuint8 *pixels;
|
||||
SHImageFormatDesc winfd;
|
||||
@@ -986,6 +1034,7 @@ VG_API_CALL void vgSetPixels(VGint dx, VGint dy,
|
||||
free(pixels);
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
@@ -999,6 +1048,9 @@ VG_API_CALL void vgWritePixels(const void * data, VGint dataStride,
|
||||
VGint dx, VGint dy,
|
||||
VGint width, VGint height)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
SHuint8 *pixels;
|
||||
SHImageFormatDesc winfd;
|
||||
|
||||
@@ -1043,7 +1095,8 @@ VG_API_CALL void vgWritePixels(const void * data, VGint dataStride,
|
||||
|
||||
free(pixels);
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
@@ -1056,6 +1109,9 @@ VG_API_CALL void vgGetPixels(VGImage dst, VGint dx, VGint dy,
|
||||
VGint sx, VGint sy,
|
||||
VGint width, VGint height)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
SHImage *i;
|
||||
SHuint8 *pixels;
|
||||
SHImageFormatDesc winfd;
|
||||
@@ -1093,7 +1149,9 @@ VG_API_CALL void vgGetPixels(VGImage dst, VGint dx, VGint dy,
|
||||
free(pixels);
|
||||
|
||||
shUpdateImageTexture(i, context);
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
@@ -1107,6 +1165,9 @@ VG_API_CALL void vgReadPixels(void * data, VGint dataStride,
|
||||
VGint sx, VGint sy,
|
||||
VGint width, VGint height)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
SHuint8 *pixels;
|
||||
SHImageFormatDesc winfd;
|
||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||
@@ -1146,8 +1207,9 @@ VG_API_CALL void vgReadPixels(void * data, VGint dataStride,
|
||||
0, 0, 0, 0, width, height);
|
||||
|
||||
free(pixels);
|
||||
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------
|
||||
@@ -1160,6 +1222,9 @@ VG_API_CALL void vgCopyPixels(VGint dx, VGint dy,
|
||||
VGint sx, VGint sy,
|
||||
VGint width, VGint height)
|
||||
{
|
||||
#ifdef SH_NO_IMAGE
|
||||
printf("ShivaVG: images not supported!");
|
||||
#else
|
||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||
|
||||
VG_RETURN_ERR_IF(width <= 0 || height <= 0,
|
||||
@@ -1170,8 +1235,9 @@ VG_API_CALL void vgCopyPixels(VGint dx, VGint dy,
|
||||
glRasterPos2i(dx, dy);
|
||||
glCopyPixels(sx, sy, width, height, GL_COLOR);
|
||||
glRasterPos2i(0, 0);
|
||||
|
||||
|
||||
VG_RETURN(VG_NO_RETVAL);
|
||||
#endif // SH_NO_IMAGE
|
||||
}
|
||||
|
||||
VG_API_CALL VGImage vgChildImage(VGImage parent,
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#define _ARRAY_DEFINE
|
||||
#include "shArrayBase.h"
|
||||
|
||||
// We currently do not use gradients which need textures, so disable them to
|
||||
// prevent freeing resources outside the correct OpenGL thread/context.
|
||||
#define SH_NO_PAINT_TEXTURE
|
||||
|
||||
void SHPaint_ctor(SHPaint *p)
|
||||
{
|
||||
@@ -51,20 +54,26 @@ void SHPaint_ctor(SHPaint *p)
|
||||
for (i=0; i<4; ++i) p->linearGradient[i] = 0.0f;
|
||||
for (i=0; i<5; ++i) p->radialGradient[i] = 0.0f;
|
||||
p->pattern = VG_INVALID_HANDLE;
|
||||
|
||||
|
||||
#ifndef SH_NO_PAINT_TEXTURE
|
||||
glGenTextures(1, &p->texture);
|
||||
glBindTexture(GL_TEXTURE_1D, p->texture);
|
||||
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, SH_GRADIENT_TEX_SIZE, 0,
|
||||
GL_RGBA, GL_FLOAT, NULL);
|
||||
#else
|
||||
p->texture = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SHPaint_dtor(SHPaint *p)
|
||||
{
|
||||
SH_DEINITOBJ(SHStopArray, p->instops);
|
||||
SH_DEINITOBJ(SHStopArray, p->stops);
|
||||
|
||||
|
||||
#ifndef SH_NO_PAINT_TEXTURE
|
||||
if (glIsTexture(p->texture))
|
||||
glDeleteTextures(1, &p->texture);
|
||||
#endif
|
||||
}
|
||||
|
||||
VG_API_CALL VGPaint vgCreatePaint(void)
|
||||
@@ -143,6 +152,7 @@ VG_API_CALL void vgPaintPattern(VGPaint paint, VGImage pattern)
|
||||
|
||||
void shUpdateColorRampTexture(SHPaint *p)
|
||||
{
|
||||
#ifndef SH_NO_PAINT_TEXTURE
|
||||
SHint s=0;
|
||||
SHStop *stop1, *stop2;
|
||||
SHfloat rgba[SH_GRADIENT_TEX_COORDSIZE];
|
||||
@@ -177,12 +187,15 @@ void shUpdateColorRampTexture(SHPaint *p)
|
||||
CSTORE_RGBA1D_F(c, rgba, x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update texture image */
|
||||
glBindTexture(GL_TEXTURE_1D, p->texture);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, SH_GRADIENT_TEX_SIZE,
|
||||
GL_RGBA, GL_FLOAT, rgba);
|
||||
#else
|
||||
printf("ShivaVG: gradients not supported!");
|
||||
#endif
|
||||
}
|
||||
|
||||
void shValidateInputStops(SHPaint *p)
|
||||
@@ -344,6 +357,7 @@ void shGenerateStops(SHPaint *p, SHfloat minOffset, SHfloat maxOffset,
|
||||
|
||||
void shSetGradientTexGLState(SHPaint *p)
|
||||
{
|
||||
#ifndef SH_NO_PAINT_TEXTURE
|
||||
glBindTexture(GL_TEXTURE_1D, p->texture);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
@@ -359,6 +373,9 @@ void shSetGradientTexGLState(SHPaint *p)
|
||||
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glColor4f(1,1,1,1);
|
||||
#else
|
||||
printf("ShivaVG: gradients not supported!");
|
||||
#endif
|
||||
}
|
||||
|
||||
void shSetPatternTexGLState(SHPaint *p, VGContext *c)
|
||||
|
||||
@@ -314,9 +314,9 @@ VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes)
|
||||
}
|
||||
|
||||
/* TODO: Turn antialiasing on/off */
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glDisable(GL_POLYGON_SMOOTH);
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
// glDisable(GL_LINE_SMOOTH);
|
||||
// glDisable(GL_POLYGON_SMOOTH);
|
||||
// glEnable(GL_MULTISAMPLE);
|
||||
|
||||
/* Pick paint if available or default*/
|
||||
fill = (context->fillPaint ? context->fillPaint : &context->defaultPaint);
|
||||
@@ -364,26 +364,27 @@ VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes)
|
||||
/* TODO: Is there any way to do this safely along
|
||||
with the paint generation pass?? */
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
// glDisable(GL_MULTISAMPLE);
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
shDrawBoundBox(context, p, VG_FILL_PATH);
|
||||
|
||||
/* Reset state */
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
// glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
/* TODO: Turn antialiasing on/off */
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glDisable(GL_POLYGON_SMOOTH);
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
// glDisable(GL_LINE_SMOOTH);
|
||||
// glDisable(GL_POLYGON_SMOOTH);
|
||||
// glEnable(GL_MULTISAMPLE);
|
||||
|
||||
if ((paintModes & VG_STROKE_PATH) &&
|
||||
context->strokeLineWidth > 0.0f) {
|
||||
|
||||
if (1) {/*context->strokeLineWidth > 1.0f) {*/
|
||||
|
||||
#if 0
|
||||
if (1) {/*context->strokeLineWidth > 1.0f) {*/
|
||||
#endif
|
||||
if (shIsStrokeCacheValid( context, p ) == VG_FALSE)
|
||||
{
|
||||
/* Generate stroke triangles in user space */
|
||||
@@ -411,15 +412,15 @@ VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes)
|
||||
|
||||
/* Clear stencil for sure */
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
// glDisable(GL_MULTISAMPLE);
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
shDrawBoundBox(context, p, VG_STROKE_PATH);
|
||||
|
||||
/* Reset state */
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
// glDisable(GL_BLEND);
|
||||
#if 0
|
||||
}else{
|
||||
|
||||
/* Simulate thin stroke by alpha */
|
||||
@@ -438,6 +439,7 @@ VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes)
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -124,11 +124,13 @@ int shLineLineXsection(SHVector2 *o1, SHVector2 *v1,
|
||||
SHfloat DX = rightU * (-v2->y) - rightD * (-v2->x);
|
||||
/*SHfloat DY = v1.x * rightD - v1.y * rightU;*/
|
||||
|
||||
SHfloat t1 = DX / D;
|
||||
SHfloat t1;
|
||||
|
||||
if (D == 0.0f)
|
||||
return 0;
|
||||
|
||||
|
||||
t1 = DX / D;
|
||||
|
||||
xsection->x = o1->x + t1*v1->x;
|
||||
xsection->y = o1->y + t1*v1->y;
|
||||
return 1;
|
||||
|
||||
@@ -39,8 +39,8 @@ namespace canvas
|
||||
|
||||
#define SG_FWD_DECL(name)\
|
||||
class name;\
|
||||
typedef boost::shared_ptr<name> name##Ptr;\
|
||||
typedef boost::weak_ptr<name> name##WeakPtr;
|
||||
typedef SGSharedPtr<name> name##Ptr;\
|
||||
typedef SGWeakPtr<name> name##WeakPtr;
|
||||
|
||||
SG_FWD_DECL(Canvas)
|
||||
SG_FWD_DECL(Element)
|
||||
@@ -49,9 +49,21 @@ namespace canvas
|
||||
SG_FWD_DECL(Map)
|
||||
SG_FWD_DECL(Path)
|
||||
SG_FWD_DECL(Text)
|
||||
SG_FWD_DECL(Window)
|
||||
|
||||
SG_FWD_DECL(Event)
|
||||
SG_FWD_DECL(CustomEvent)
|
||||
SG_FWD_DECL(DeviceEvent)
|
||||
SG_FWD_DECL(KeyboardEvent)
|
||||
SG_FWD_DECL(MouseEvent)
|
||||
|
||||
#undef SG_FWD_DECL
|
||||
|
||||
#define SG_FWD_DECL(name)\
|
||||
class name;\
|
||||
typedef boost::shared_ptr<name> name##Ptr;\
|
||||
typedef boost::weak_ptr<name> name##WeakPtr;
|
||||
|
||||
SG_FWD_DECL(Placement)
|
||||
SG_FWD_DECL(SystemAdapter)
|
||||
|
||||
@@ -60,6 +72,9 @@ namespace canvas
|
||||
class EventManager;
|
||||
class EventVisitor;
|
||||
|
||||
struct EventTarget;
|
||||
typedef std::deque<EventTarget> EventPropagationPath;
|
||||
|
||||
typedef std::map<std::string, const SGPropertyNode*> Style;
|
||||
typedef ElementPtr (*ElementFactory)( const CanvasWeakPtr&,
|
||||
const SGPropertyNode_ptr&,
|
||||
|
||||
@@ -23,4 +23,9 @@ set(SOURCES
|
||||
)
|
||||
|
||||
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
|
||||
simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}")
|
||||
simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}")
|
||||
|
||||
add_boost_test(canvas_element
|
||||
SOURCES canvas_element_test.cpp
|
||||
LIBRARIES ${TEST_LIBS}
|
||||
)
|
||||
@@ -17,15 +17,17 @@
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "CanvasElement.hxx"
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/canvas/CanvasEventVisitor.hxx>
|
||||
#include <simgear/canvas/MouseEvent.hxx>
|
||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||
#include <simgear/math/SGMisc.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/scene/material/parseBlendFunc.hxx>
|
||||
|
||||
#include <osg/Drawable>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Scissor>
|
||||
#include <osg/StateAttribute>
|
||||
#include <osg/Version>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
@@ -45,19 +47,79 @@ namespace canvas
|
||||
* glScissor with coordinates relative to different reference frames.
|
||||
*/
|
||||
class Element::RelativeScissor:
|
||||
public osg::Scissor
|
||||
public osg::StateAttribute
|
||||
{
|
||||
public:
|
||||
|
||||
ReferenceFrame _coord_reference;
|
||||
osg::Matrix _parent_inverse;
|
||||
ReferenceFrame _coord_reference;
|
||||
osg::observer_ptr<osg::Node> _node;
|
||||
|
||||
RelativeScissor():
|
||||
_coord_reference(GLOBAL)
|
||||
explicit RelativeScissor(osg::Node* node = NULL):
|
||||
_coord_reference(GLOBAL),
|
||||
_node(node),
|
||||
_x(0),
|
||||
_y(0),
|
||||
_width(0),
|
||||
_height(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** Copy constructor using CopyOp to manage deep vs shallow copy. */
|
||||
RelativeScissor( const RelativeScissor& vp,
|
||||
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY ):
|
||||
StateAttribute(vp, copyop),
|
||||
_coord_reference(vp._coord_reference),
|
||||
_node(vp._node),
|
||||
_x(vp._x),
|
||||
_y(vp._y),
|
||||
_width(vp._width),
|
||||
_height(vp._height)
|
||||
{}
|
||||
|
||||
META_StateAttribute(simgear, RelativeScissor, SCISSOR);
|
||||
|
||||
/** Return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */
|
||||
virtual int compare(const StateAttribute& sa) const
|
||||
{
|
||||
// check the types are equal and then create the rhs variable
|
||||
// used by the COMPARE_StateAttribute_Parameter macros below.
|
||||
COMPARE_StateAttribute_Types(RelativeScissor,sa)
|
||||
|
||||
// compare each parameter in turn against the rhs.
|
||||
COMPARE_StateAttribute_Parameter(_x)
|
||||
COMPARE_StateAttribute_Parameter(_y)
|
||||
COMPARE_StateAttribute_Parameter(_width)
|
||||
COMPARE_StateAttribute_Parameter(_height)
|
||||
COMPARE_StateAttribute_Parameter(_coord_reference)
|
||||
COMPARE_StateAttribute_Parameter(_node)
|
||||
|
||||
return 0; // passed all the above comparison macros, must be equal.
|
||||
}
|
||||
|
||||
virtual bool getModeUsage(StateAttribute::ModeUsage& usage) const
|
||||
{
|
||||
usage.usesMode(GL_SCISSOR_TEST);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline float& x() { return _x; }
|
||||
inline float x() const { return _x; }
|
||||
|
||||
inline float& y() { return _y; }
|
||||
inline float y() const { return _y; }
|
||||
|
||||
inline float& width() { return _width; }
|
||||
inline float width() const { return _width; }
|
||||
|
||||
inline float& height() { return _height; }
|
||||
inline float height() const { return _height; }
|
||||
|
||||
virtual void apply(osg::State& state) const
|
||||
{
|
||||
if( _width <= 0 || _height <= 0 )
|
||||
return;
|
||||
|
||||
const osg::Viewport* vp = state.getCurrentViewport();
|
||||
float w2 = 0.5 * vp->width(),
|
||||
h2 = 0.5 * vp->height();
|
||||
@@ -73,17 +135,28 @@ namespace canvas
|
||||
|
||||
if( _coord_reference != GLOBAL )
|
||||
{
|
||||
model_view.preMult(state.getModelViewMatrix());
|
||||
osg::Node* ref_obj = _node.get();
|
||||
|
||||
if( _coord_reference == PARENT )
|
||||
model_view.preMult(_parent_inverse);
|
||||
{
|
||||
if( _node->getNumParents() < 1 )
|
||||
{
|
||||
SG_LOG(SG_GL, SG_WARN, "RelativeScissor: missing parent.");
|
||||
return;
|
||||
}
|
||||
|
||||
ref_obj = _node->getParent(0);
|
||||
}
|
||||
|
||||
osg::MatrixList const& parent_matrices = ref_obj->getWorldMatrices();
|
||||
assert( !parent_matrices.empty() );
|
||||
model_view.preMult(parent_matrices.front());
|
||||
}
|
||||
|
||||
const osg::Vec2 scale( model_view(0,0), model_view(1,1)),
|
||||
offset(model_view(3,0), model_view(3,1));
|
||||
|
||||
// TODO check/warn for rotation?
|
||||
|
||||
GLint x = SGMiscf::roundToInt(scale.x() * _x + offset.x()),
|
||||
y = SGMiscf::roundToInt(scale.y() * _y + offset.y()),
|
||||
w = SGMiscf::roundToInt(std::fabs(scale.x()) * _width),
|
||||
@@ -96,6 +169,32 @@ namespace canvas
|
||||
|
||||
glScissor(x, y, w, h);
|
||||
}
|
||||
|
||||
bool contains(const osg::Vec2f& pos) const
|
||||
{
|
||||
return _x <= pos.x() && pos.x() <= _x + _width
|
||||
&& _y <= pos.y() && pos.y() <= _y + _height;
|
||||
}
|
||||
|
||||
bool contains( const osg::Vec2f& global_pos,
|
||||
const osg::Vec2f& parent_pos,
|
||||
const osg::Vec2f& local_pos ) const
|
||||
{
|
||||
switch( _coord_reference )
|
||||
{
|
||||
case GLOBAL: return contains(global_pos);
|
||||
case PARENT: return contains(parent_pos);
|
||||
case LOCAL: return contains(local_pos);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
float _x,
|
||||
_y,
|
||||
_width,
|
||||
_height;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -108,30 +207,6 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
Element::~Element()
|
||||
{
|
||||
if( !_transform.valid() )
|
||||
return;
|
||||
|
||||
for(unsigned int i = 0; i < _transform->getNumChildren(); ++i)
|
||||
{
|
||||
OSGUserData* ud =
|
||||
static_cast<OSGUserData*>(_transform->getChild(i)->getUserData());
|
||||
|
||||
if( ud )
|
||||
// Ensure parent is cleared to prevent accessing released memory if an
|
||||
// element somehow survives longer than his parent.
|
||||
ud->element->_parent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setSelf(const PropertyBasedElementPtr& self)
|
||||
{
|
||||
PropertyBasedElement::setSelf(self);
|
||||
|
||||
_transform->setUserData
|
||||
(
|
||||
new OSGUserData(boost::static_pointer_cast<Element>(self))
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -146,101 +221,41 @@ namespace canvas
|
||||
{
|
||||
parent->removeChild(_transform.get());
|
||||
}
|
||||
|
||||
// Hide in case someone still holds a reference
|
||||
setVisible(false);
|
||||
removeListener();
|
||||
|
||||
_parent = 0;
|
||||
_transform = 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ElementWeakPtr Element::getWeakPtr() const
|
||||
ElementPtr Element::getParent() const
|
||||
{
|
||||
return boost::static_pointer_cast<Element>(_self.lock());
|
||||
return _parent.lock();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ElementPtr Element::getParent()
|
||||
CanvasWeakPtr Element::getCanvas() const
|
||||
{
|
||||
return _parent ? _parent->getWeakPtr().lock() : ElementPtr();
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::update(double dt)
|
||||
{
|
||||
if( !_transform->getNodeMask() )
|
||||
// Don't do anything if element is hidden
|
||||
if( !isVisible() )
|
||||
return;
|
||||
|
||||
if( _transform_dirty )
|
||||
{
|
||||
osg::Matrix m;
|
||||
for( size_t i = 0; i < _transform_types.size(); ++i )
|
||||
{
|
||||
// Skip unused indizes...
|
||||
if( _transform_types[i] == TT_NONE )
|
||||
continue;
|
||||
|
||||
SGPropertyNode* tf_node = _node->getChild("tf", i, true);
|
||||
|
||||
// Build up the matrix representation of the current transform node
|
||||
osg::Matrix tf;
|
||||
switch( _transform_types[i] )
|
||||
{
|
||||
case TT_MATRIX:
|
||||
tf = osg::Matrix( tf_node->getDoubleValue("m[0]", 1),
|
||||
tf_node->getDoubleValue("m[1]", 0),
|
||||
0,
|
||||
tf_node->getDoubleValue("m[6]", 0),
|
||||
|
||||
tf_node->getDoubleValue("m[2]", 0),
|
||||
tf_node->getDoubleValue("m[3]", 1),
|
||||
0,
|
||||
tf_node->getDoubleValue("m[7]", 0),
|
||||
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
|
||||
tf_node->getDoubleValue("m[4]", 0),
|
||||
tf_node->getDoubleValue("m[5]", 0),
|
||||
0,
|
||||
tf_node->getDoubleValue("m[8]", 1) );
|
||||
break;
|
||||
case TT_TRANSLATE:
|
||||
tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("t[0]", 0),
|
||||
tf_node->getDoubleValue("t[1]", 0),
|
||||
0 ) );
|
||||
break;
|
||||
case TT_ROTATE:
|
||||
tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 );
|
||||
break;
|
||||
case TT_SCALE:
|
||||
{
|
||||
float sx = tf_node->getDoubleValue("s[0]", 1);
|
||||
// sy defaults to sx...
|
||||
tf.makeScale( sx, tf_node->getDoubleValue("s[1]", sx), 1 );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m.postMult( tf );
|
||||
}
|
||||
_transform->setMatrix(m);
|
||||
_transform_dirty = false;
|
||||
_attributes_dirty |= SCISSOR_COORDS;
|
||||
}
|
||||
|
||||
if( _attributes_dirty & SCISSOR_COORDS )
|
||||
{
|
||||
if( _scissor && _scissor->_coord_reference != GLOBAL )
|
||||
_scissor->_parent_inverse = _transform->getInverseMatrix();
|
||||
|
||||
_attributes_dirty &= ~SCISSOR_COORDS;
|
||||
}
|
||||
// Trigger matrix update
|
||||
getMatrix();
|
||||
|
||||
// Update bounding box on manual update (manual updates pass zero dt)
|
||||
if( dt == 0 && _drawable )
|
||||
_drawable->getBound();
|
||||
|
||||
if( _attributes_dirty & BLEND_FUNC )
|
||||
if( (_attributes_dirty & BLEND_FUNC) && _transform.valid() )
|
||||
{
|
||||
parseBlendFunc(
|
||||
_transform->getOrCreateStateSet(),
|
||||
@@ -266,17 +281,7 @@ namespace canvas
|
||||
"addEventListener(" << _node->getPath() << ", " << type_str << ")"
|
||||
);
|
||||
|
||||
Event::Type type = Event::strToType(type_str);
|
||||
if( type == Event::UNKNOWN )
|
||||
{
|
||||
SG_LOG( SG_GENERAL,
|
||||
SG_WARN,
|
||||
"addEventListener: Unknown event type " << type_str );
|
||||
return false;
|
||||
}
|
||||
|
||||
_listener[ type ].push_back(cb);
|
||||
|
||||
_listener[ Event::getOrRegisterType(type_str) ].push_back(cb);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -286,6 +291,14 @@ namespace canvas
|
||||
_listener.clear();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setFocus()
|
||||
{
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( canvas )
|
||||
canvas->setFocusElement(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::accept(EventVisitor& visitor)
|
||||
{
|
||||
@@ -298,8 +311,9 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::ascend(EventVisitor& visitor)
|
||||
{
|
||||
if( _parent )
|
||||
return _parent->accept(visitor);
|
||||
ElementPtr parent = getParent();
|
||||
if( parent )
|
||||
return parent->accept(visitor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -310,30 +324,89 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::handleEvent(canvas::EventPtr event)
|
||||
size_t Element::numEventHandler(int type) const
|
||||
{
|
||||
ListenerMap::const_iterator listeners = _listener.find(type);
|
||||
if( listeners != _listener.end() )
|
||||
return listeners->second.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::handleEvent(const EventPtr& event)
|
||||
{
|
||||
ListenerMap::iterator listeners = _listener.find(event->getType());
|
||||
if( listeners == _listener.end() )
|
||||
return false;
|
||||
|
||||
BOOST_FOREACH(EventListener const& listener, listeners->second)
|
||||
listener(event);
|
||||
try
|
||||
{
|
||||
listener(event);
|
||||
}
|
||||
catch( std::exception const& ex )
|
||||
{
|
||||
SG_LOG(
|
||||
SG_GENERAL,
|
||||
SG_WARN,
|
||||
"canvas::Element: event handler error: '" << ex.what() << "'"
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::hitBound( const osg::Vec2f& pos,
|
||||
bool Element::dispatchEvent(const EventPtr& event)
|
||||
{
|
||||
EventPropagationPath path;
|
||||
path.push_back( EventTarget(this) );
|
||||
|
||||
for( ElementPtr parent = getParent();
|
||||
parent.valid();
|
||||
parent = parent->getParent() )
|
||||
path.push_front( EventTarget(parent) );
|
||||
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( !canvas )
|
||||
return false;
|
||||
|
||||
return canvas->propagateEvent(event, path);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::hitBound( const osg::Vec2f& global_pos,
|
||||
const osg::Vec2f& parent_pos,
|
||||
const osg::Vec2f& local_pos ) const
|
||||
{
|
||||
const osg::Vec3f pos3(pos, 0);
|
||||
if( _scissor && !_scissor->contains(global_pos, parent_pos, local_pos) )
|
||||
return false;
|
||||
|
||||
const osg::Vec3f pos3(parent_pos, 0);
|
||||
|
||||
// Drawables have a bounding box...
|
||||
if( _drawable )
|
||||
return _drawable->getBound().contains(osg::Vec3f(local_pos, 0));
|
||||
// ... for other elements, i.e. groups only a bounding sphere is available
|
||||
return _drawable->
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
getBound()
|
||||
#else
|
||||
getBoundingBox()
|
||||
#endif
|
||||
.contains(osg::Vec3f(local_pos, 0));
|
||||
else if( _transform.valid() )
|
||||
// ... for other elements, i.e. groups only a bounding sphere is available
|
||||
return _transform->getBound().contains(osg::Vec3f(parent_pos, 0));
|
||||
else
|
||||
return _transform->getBound().contains(osg::Vec3f(pos, 0));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setVisible(bool visible)
|
||||
{
|
||||
if( _transform.valid() )
|
||||
// TODO check if we need another nodemask
|
||||
_transform->setNodeMask(visible ? 0xffffffff : 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -354,6 +427,18 @@ namespace canvas
|
||||
return _transform.get();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2f Element::posToLocal(const osg::Vec2f& pos) const
|
||||
{
|
||||
getMatrix();
|
||||
const osg::Matrix& m = _transform->getInverseMatrix();
|
||||
return osg::Vec2f
|
||||
(
|
||||
m(0, 0) * pos[0] + m(1, 0) * pos[1] + m(3, 0),
|
||||
m(0, 1) * pos[0] + m(1, 1) * pos[1] + m(3, 1)
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
@@ -364,7 +449,7 @@ namespace canvas
|
||||
_transform_types.resize( child->getIndex() + 1 );
|
||||
|
||||
_transform_types[ child->getIndex() ] = TT_NONE;
|
||||
_transform_dirty = true;
|
||||
_attributes_dirty |= TRANSFORM;
|
||||
return;
|
||||
}
|
||||
else if( parent->getParent() == _node
|
||||
@@ -385,7 +470,7 @@ namespace canvas
|
||||
else if( name == "s" )
|
||||
type = TT_SCALE;
|
||||
|
||||
_transform_dirty = true;
|
||||
_attributes_dirty |= TRANSFORM;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -418,7 +503,7 @@ namespace canvas
|
||||
while( !_transform_types.empty() && _transform_types.back() == TT_NONE )
|
||||
_transform_types.pop_back();
|
||||
|
||||
_transform_dirty = true;
|
||||
_attributes_dirty |= TRANSFORM;
|
||||
return;
|
||||
}
|
||||
else if( StyleInfo const* style = getStyleInfo(child->getNameString()) )
|
||||
@@ -438,7 +523,9 @@ namespace canvas
|
||||
if( parent == _node )
|
||||
{
|
||||
const std::string& name = child->getNameString();
|
||||
if( StyleInfo const* style_info = getStyleInfo(name) )
|
||||
if( boost::starts_with(name, "data-") )
|
||||
return;
|
||||
else if( StyleInfo const* style_info = getStyleInfo(name) )
|
||||
{
|
||||
SGPropertyNode const* style = child;
|
||||
if( isStyleEmpty(child) )
|
||||
@@ -451,16 +538,14 @@ namespace canvas
|
||||
}
|
||||
else if( name == "update" )
|
||||
return update(0);
|
||||
else if( name == "visible" )
|
||||
// TODO check if we need another nodemask
|
||||
return _transform->setNodeMask( child->getBoolValue() ? 0xffffffff : 0 );
|
||||
else if( boost::starts_with(name, "blend-") )
|
||||
return (void)(_attributes_dirty |= BLEND_FUNC);
|
||||
}
|
||||
else if( parent->getParent() == _node
|
||||
else if( parent
|
||||
&& parent->getParent() == _node
|
||||
&& parent->getNameString() == NAME_TRANSFORM )
|
||||
{
|
||||
_transform_dirty = true;
|
||||
_attributes_dirty |= TRANSFORM;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -477,9 +562,13 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setClip(const std::string& clip)
|
||||
{
|
||||
osg::StateSet* ss = getOrCreateStateSet();
|
||||
if( !ss )
|
||||
return;
|
||||
|
||||
if( clip.empty() || clip == "auto" )
|
||||
{
|
||||
getOrCreateStateSet()->removeAttribute(osg::StateAttribute::SCISSOR);
|
||||
ss->removeAttribute(osg::StateAttribute::SCISSOR);
|
||||
_scissor = 0;
|
||||
return;
|
||||
}
|
||||
@@ -526,47 +615,53 @@ namespace canvas
|
||||
return;
|
||||
}
|
||||
|
||||
_scissor = new RelativeScissor();
|
||||
// <top>, <right>, <bottom>, <left>
|
||||
_scissor->x() = SGMiscf::roundToInt(values[3]);
|
||||
_scissor->y() = SGMiscf::roundToInt(values[0]);
|
||||
_scissor->width() = SGMiscf::roundToInt(width);
|
||||
_scissor->height() = SGMiscf::roundToInt(height);
|
||||
if( !_scissor )
|
||||
_scissor = new RelativeScissor(_transform.get());
|
||||
|
||||
getOrCreateStateSet()->setAttributeAndModes(_scissor);
|
||||
// <top>, <right>, <bottom>, <left>
|
||||
_scissor->x() = values[3];
|
||||
_scissor->y() = values[0];
|
||||
_scissor->width() = width;
|
||||
_scissor->height() = height;
|
||||
|
||||
SGPropertyNode* clip_frame = _node->getChild("clip-frame", 0);
|
||||
if( clip_frame )
|
||||
valueChanged(clip_frame);
|
||||
else
|
||||
_scissor->_coord_reference = GLOBAL;
|
||||
|
||||
ss->setAttributeAndModes(_scissor);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setClipFrame(ReferenceFrame rf)
|
||||
{
|
||||
if( _scissor )
|
||||
{
|
||||
_scissor->_coord_reference = rf;
|
||||
_attributes_dirty |= SCISSOR_COORDS;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setBoundingBox(const osg::BoundingBox& bb)
|
||||
osg::BoundingBox Element::getBoundingBox() const
|
||||
{
|
||||
if( _bounding_box.empty() )
|
||||
{
|
||||
SGPropertyNode* bb_node = _node->getChild("bounding-box", 0, true);
|
||||
_bounding_box.resize(4);
|
||||
_bounding_box[0] = bb_node->getChild("min-x", 0, true);
|
||||
_bounding_box[1] = bb_node->getChild("min-y", 0, true);
|
||||
_bounding_box[2] = bb_node->getChild("max-x", 0, true);
|
||||
_bounding_box[3] = bb_node->getChild("max-y", 0, true);
|
||||
}
|
||||
if( _drawable )
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
return _drawable->getBound();
|
||||
#else
|
||||
return _drawable->getBoundingBox();
|
||||
#endif
|
||||
|
||||
_bounding_box[0]->setFloatValue(bb._min.x());
|
||||
_bounding_box[1]->setFloatValue(bb._min.y());
|
||||
_bounding_box[2]->setFloatValue(bb._max.x());
|
||||
_bounding_box[3]->setFloatValue(bb._max.y());
|
||||
osg::BoundingBox bb;
|
||||
|
||||
if( _transform.valid() )
|
||||
bb.expandBy(_transform->getBound());
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::BoundingBox Element::getTightBoundingBox() const
|
||||
{
|
||||
return getTransformedBounds(getMatrix());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -576,13 +671,88 @@ namespace canvas
|
||||
return osg::BoundingBox();
|
||||
|
||||
osg::BoundingBox transformed;
|
||||
const osg::BoundingBox& bb = _drawable->getBound();
|
||||
const osg::BoundingBox& bb =
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
_drawable->getBound();
|
||||
#else
|
||||
_drawable->getBoundingBox();
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < 4; ++i)
|
||||
transformed.expandBy( bb.corner(i) * m );
|
||||
|
||||
return transformed;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Matrix Element::getMatrix() const
|
||||
{
|
||||
if( !_transform )
|
||||
return osg::Matrix::identity();
|
||||
|
||||
if( !(_attributes_dirty & TRANSFORM) )
|
||||
return _transform->getMatrix();
|
||||
|
||||
osg::Matrix m;
|
||||
for( size_t i = 0; i < _transform_types.size(); ++i )
|
||||
{
|
||||
// Skip unused indizes...
|
||||
if( _transform_types[i] == TT_NONE )
|
||||
continue;
|
||||
|
||||
SGPropertyNode* tf_node = _node->getChild("tf", i, true);
|
||||
|
||||
// Build up the matrix representation of the current transform node
|
||||
osg::Matrix tf;
|
||||
switch( _transform_types[i] )
|
||||
{
|
||||
case TT_MATRIX:
|
||||
tf = osg::Matrix( tf_node->getDoubleValue("m[0]", 1),
|
||||
tf_node->getDoubleValue("m[1]", 0),
|
||||
0,
|
||||
tf_node->getDoubleValue("m[6]", 0),
|
||||
|
||||
tf_node->getDoubleValue("m[2]", 0),
|
||||
tf_node->getDoubleValue("m[3]", 1),
|
||||
0,
|
||||
tf_node->getDoubleValue("m[7]", 0),
|
||||
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
|
||||
tf_node->getDoubleValue("m[4]", 0),
|
||||
tf_node->getDoubleValue("m[5]", 0),
|
||||
0,
|
||||
tf_node->getDoubleValue("m[8]", 1) );
|
||||
break;
|
||||
case TT_TRANSLATE:
|
||||
tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("t[0]", 0),
|
||||
tf_node->getDoubleValue("t[1]", 0),
|
||||
0 ) );
|
||||
break;
|
||||
case TT_ROTATE:
|
||||
tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 );
|
||||
break;
|
||||
case TT_SCALE:
|
||||
{
|
||||
float sx = tf_node->getDoubleValue("s[0]", 1);
|
||||
// sy defaults to sx...
|
||||
tf.makeScale( sx, tf_node->getDoubleValue("s[1]", sx), 1 );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m.postMult( tf );
|
||||
}
|
||||
_transform->setMatrix(m);
|
||||
_attributes_dirty &= ~TRANSFORM;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Element::StyleSetters Element::_style_setters;
|
||||
|
||||
@@ -590,12 +760,11 @@ namespace canvas
|
||||
Element::Element( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
PropertyBasedElement(node),
|
||||
_canvas( canvas ),
|
||||
_parent( parent ),
|
||||
_attributes_dirty( 0 ),
|
||||
_transform_dirty( false ),
|
||||
_transform( new osg::MatrixTransform ),
|
||||
_style( parent_style ),
|
||||
_scissor( 0 ),
|
||||
@@ -618,6 +787,8 @@ namespace canvas
|
||||
"PreOrderBin",
|
||||
osg::StateSet::OVERRIDE_RENDERBIN_DETAILS
|
||||
);
|
||||
|
||||
_transform->setUserData( new OSGUserData(this) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -628,6 +799,7 @@ namespace canvas
|
||||
|
||||
addStyle("clip", "", &Element::setClip, false);
|
||||
addStyle("clip-frame", "", &Element::setClipFrame, false);
|
||||
addStyle("visible", "", &Element::setVisible, false);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -687,11 +859,12 @@ namespace canvas
|
||||
Element::getParentStyle(const SGPropertyNode* child) const
|
||||
{
|
||||
// Try to get value from parent...
|
||||
if( _parent )
|
||||
ElementPtr parent = getParent();
|
||||
if( parent )
|
||||
{
|
||||
Style::const_iterator style =
|
||||
_parent->_style.find(child->getNameString());
|
||||
if( style != _parent->_style.end() )
|
||||
parent->_style.find(child->getNameString());
|
||||
if( style != parent->_style.end() )
|
||||
return style->second;
|
||||
}
|
||||
|
||||
@@ -713,8 +886,12 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
osg::StateSet* Element::getOrCreateStateSet()
|
||||
{
|
||||
return _drawable ? _drawable->getOrCreateStateSet()
|
||||
: _transform->getOrCreateStateSet();
|
||||
if( _drawable.valid() )
|
||||
return _drawable->getOrCreateStateSet();
|
||||
if( _transform.valid() )
|
||||
return _transform->getOrCreateStateSet();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Interface for 2D Canvas elements
|
||||
///@file
|
||||
/// Interface for 2D Canvas elements
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -41,6 +42,9 @@ namespace simgear
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Base class for Elements displayed inside a Canvas.
|
||||
*/
|
||||
class Element:
|
||||
public PropertyBasedElement
|
||||
{
|
||||
@@ -69,10 +73,10 @@ namespace canvas
|
||||
};
|
||||
struct StyleInfo
|
||||
{
|
||||
StyleSetter setter; ///!< Function(s) for setting this style
|
||||
std::string type; ///!< Interpolation type
|
||||
bool inheritable; ///!< Whether children can inherit this style from
|
||||
/// their parents
|
||||
StyleSetter setter; ///< Function(s) for setting this style
|
||||
std::string type; ///< Interpolation type
|
||||
bool inheritable; ///< Whether children can inherit this style from
|
||||
/// their parents
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -80,22 +84,20 @@ namespace canvas
|
||||
*/
|
||||
enum ReferenceFrame
|
||||
{
|
||||
GLOBAL, ///!< Global coordinates
|
||||
PARENT, ///!< Coordinates relative to parent coordinate frame
|
||||
LOCAL ///!< Coordinates relative to local coordinates (parent
|
||||
/// coordinates with local transformations applied)
|
||||
GLOBAL, ///< Global coordinates
|
||||
PARENT, ///< Coordinates relative to parent coordinate frame
|
||||
LOCAL ///< Coordinates relative to local coordinates (parent
|
||||
/// coordinates with local transformations applied)
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
virtual ~Element() = 0;
|
||||
|
||||
virtual void setSelf(const PropertyBasedElementPtr& self);
|
||||
virtual void onDestroy();
|
||||
|
||||
ElementWeakPtr getWeakPtr() const;
|
||||
ElementPtr getParent();
|
||||
ElementPtr getParent() const;
|
||||
CanvasWeakPtr getCanvas() const;
|
||||
|
||||
/**
|
||||
* Called every frame to update internal state
|
||||
@@ -107,24 +109,47 @@ namespace canvas
|
||||
bool addEventListener(const std::string& type, const EventListener& cb);
|
||||
virtual void clearEventListener();
|
||||
|
||||
/// Get (keyboard) input focus.
|
||||
void setFocus();
|
||||
|
||||
virtual bool accept(EventVisitor& visitor);
|
||||
virtual bool ascend(EventVisitor& visitor);
|
||||
virtual bool traverse(EventVisitor& visitor);
|
||||
|
||||
virtual bool handleEvent(canvas::EventPtr event);
|
||||
/// Get the number of event handlers for the given type
|
||||
size_t numEventHandler(int type) const;
|
||||
|
||||
virtual bool hitBound( const osg::Vec2f& pos,
|
||||
virtual bool handleEvent(const EventPtr& event);
|
||||
bool dispatchEvent(const EventPtr& event);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param global_pos Position in global (canvas) coordinate frame
|
||||
* @param parent_pos Position in parent coordinate frame
|
||||
* @param local_pos Position in local (element) coordinate frame
|
||||
*/
|
||||
virtual bool hitBound( const osg::Vec2f& global_pos,
|
||||
const osg::Vec2f& parent_pos,
|
||||
const osg::Vec2f& local_pos ) const;
|
||||
|
||||
/**
|
||||
* Get whether the element is visible or hidden (Can be changed with
|
||||
* setting property "visible" accordingly).
|
||||
* Set visibility of the element.
|
||||
*/
|
||||
bool isVisible() const;
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
/**
|
||||
* Get whether the element is visible or hidden.
|
||||
*/
|
||||
virtual bool isVisible() const;
|
||||
|
||||
osg::MatrixTransform* getMatrixTransform();
|
||||
osg::MatrixTransform const* getMatrixTransform() const;
|
||||
|
||||
/**
|
||||
* Transform position to local coordinages.
|
||||
*/
|
||||
osg::Vec2f posToLocal(const osg::Vec2f& pos) const;
|
||||
|
||||
virtual void childAdded( SGPropertyNode * parent,
|
||||
SGPropertyNode * child );
|
||||
virtual void childRemoved( SGPropertyNode * parent,
|
||||
@@ -148,15 +173,27 @@ namespace canvas
|
||||
void setClipFrame(ReferenceFrame rf);
|
||||
|
||||
/**
|
||||
* Write the given bounding box to the property tree
|
||||
* Get bounding box (may not be as tight as bounding box returned by
|
||||
* #getTightBoundingBox)
|
||||
*/
|
||||
void setBoundingBox(const osg::BoundingBox& bb);
|
||||
osg::BoundingBox getBoundingBox() const;
|
||||
|
||||
/**
|
||||
* Get tight bounding box (child points are transformed to elements
|
||||
* coordinate space before calculating the bounding box).
|
||||
*/
|
||||
osg::BoundingBox getTightBoundingBox() const;
|
||||
|
||||
/**
|
||||
* Get bounding box with children/drawables transformed by passed matrix
|
||||
*/
|
||||
virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
|
||||
|
||||
/**
|
||||
* Get the transformation matrix (product of all transforms)
|
||||
*/
|
||||
osg::Matrix getMatrix() const;
|
||||
|
||||
/**
|
||||
* Create an canvas Element
|
||||
*
|
||||
@@ -169,21 +206,19 @@ namespace canvas
|
||||
ElementPtr
|
||||
>::type create( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& style,
|
||||
Element* parent )
|
||||
const Style& style = Style(),
|
||||
Element* parent = NULL )
|
||||
{
|
||||
ElementPtr el( new Derived(canvas, node, style, parent) );
|
||||
el->setSelf(el);
|
||||
return el;
|
||||
return ElementPtr( new Derived(canvas, node, style, parent) );
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
enum Attributes
|
||||
{
|
||||
BLEND_FUNC = 1,
|
||||
SCISSOR_COORDS = BLEND_FUNC << 1,
|
||||
LAST_ATTRIBUTE = SCISSOR_COORDS << 1
|
||||
TRANSFORM = 1,
|
||||
BLEND_FUNC = TRANSFORM << 1,
|
||||
LAST_ATTRIBUTE = BLEND_FUNC << 1
|
||||
};
|
||||
|
||||
enum TransformType
|
||||
@@ -197,33 +232,31 @@ namespace canvas
|
||||
|
||||
class RelativeScissor;
|
||||
|
||||
CanvasWeakPtr _canvas;
|
||||
Element *_parent;
|
||||
CanvasWeakPtr _canvas;
|
||||
ElementWeakPtr _parent;
|
||||
|
||||
uint32_t _attributes_dirty;
|
||||
mutable uint32_t _attributes_dirty;
|
||||
|
||||
bool _transform_dirty;
|
||||
osg::observer_ptr<osg::MatrixTransform> _transform;
|
||||
std::vector<TransformType> _transform_types;
|
||||
|
||||
Style _style;
|
||||
std::vector<SGPropertyNode_ptr> _bounding_box;
|
||||
RelativeScissor *_scissor;
|
||||
Style _style;
|
||||
RelativeScissor *_scissor;
|
||||
|
||||
typedef std::vector<EventListener> Listener;
|
||||
typedef std::map<Event::Type, Listener> ListenerMap;
|
||||
typedef std::map<int, Listener> ListenerMap;
|
||||
|
||||
ListenerMap _listener;
|
||||
|
||||
typedef std::map<std::string, StyleInfo> StyleSetters;
|
||||
static StyleSetters _style_setters;
|
||||
static StyleSetters _style_setters;
|
||||
|
||||
static void staticInit();
|
||||
|
||||
Element( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent );
|
||||
ElementWeakPtr parent );
|
||||
|
||||
/**
|
||||
* Returns false on first call and true on any successive call. Use to
|
||||
@@ -246,9 +279,10 @@ namespace canvas
|
||||
/**
|
||||
* Register a function for setting a style specified by the given property
|
||||
*
|
||||
* @param name Property name
|
||||
* @param type Interpolation type
|
||||
* @param setter Setter function
|
||||
* @param name Property name
|
||||
* @param type Interpolation type
|
||||
* @param setter Setter function
|
||||
* @param inheritable If this style propagates to child elements
|
||||
*
|
||||
* @tparam T1 Type of value used to retrieve value from property
|
||||
* node
|
||||
@@ -530,7 +564,7 @@ namespace canvas
|
||||
/**
|
||||
* Get stateset of drawable if available or use transform otherwise
|
||||
*/
|
||||
osg::StateSet* getOrCreateStateSet();
|
||||
virtual osg::StateSet* getOrCreateStateSet();
|
||||
|
||||
void setupStyle();
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "CanvasPath.hxx"
|
||||
#include "CanvasText.hxx"
|
||||
#include <simgear/canvas/CanvasEventVisitor.hxx>
|
||||
#include <simgear/canvas/MouseEvent.hxx>
|
||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
@@ -70,7 +70,7 @@ namespace canvas
|
||||
Group::Group( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent)
|
||||
{
|
||||
staticInit();
|
||||
@@ -146,7 +146,7 @@ namespace canvas
|
||||
if( el->get<std::string>("id") == id )
|
||||
return el;
|
||||
|
||||
GroupPtr group = boost::dynamic_pointer_cast<Group>(el);
|
||||
Group* group = dynamic_cast<Group*>(el.get());
|
||||
if( group )
|
||||
groups.push_back(group);
|
||||
}
|
||||
@@ -320,10 +320,12 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void Group::childChanged(SGPropertyNode* node)
|
||||
{
|
||||
if( node->getParent()->getParent() == _node
|
||||
SGPropertyNode* parent = node->getParent();
|
||||
SGPropertyNode* grand_parent = parent ? parent->getParent() : NULL;
|
||||
|
||||
if( grand_parent == _node
|
||||
&& node->getNameString() == "z-index" )
|
||||
return handleZIndexChanged( getChild(node->getParent()),
|
||||
node->getIntValue() );
|
||||
return handleZIndexChanged(getChild(parent), node->getIntValue());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace canvas
|
||||
Group( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style = Style(),
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Group();
|
||||
|
||||
ElementPtr createChild( const std::string& type,
|
||||
@@ -56,28 +56,27 @@ namespace canvas
|
||||
const std::string& id );
|
||||
|
||||
template<class T>
|
||||
boost::shared_ptr<T> createChild(const std::string& id = "")
|
||||
SGSharedPtr<T> createChild(const std::string& id = "")
|
||||
{
|
||||
return boost::dynamic_pointer_cast<T>( createChild(T::TYPE_NAME, id) );
|
||||
return dynamic_cast<T*>( createChild(T::TYPE_NAME, id).get() );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
boost::shared_ptr<T> getChild(const SGPropertyNode* node)
|
||||
SGSharedPtr<T> getChild(const SGPropertyNode* node)
|
||||
{
|
||||
return boost::dynamic_pointer_cast<T>( getChild(node) );
|
||||
return dynamic_cast<T*>( getChild(node).get() );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
boost::shared_ptr<T> getChild(const std::string& id)
|
||||
SGSharedPtr<T> getChild(const std::string& id)
|
||||
{
|
||||
return boost::dynamic_pointer_cast<T>( getChild(id) );
|
||||
return dynamic_cast<T*>( getChild(id).get() );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
boost::shared_ptr<T> getOrCreateChild(const std::string& id)
|
||||
SGSharedPtr<T> getOrCreateChild(const std::string& id)
|
||||
{
|
||||
return
|
||||
boost::dynamic_pointer_cast<T>( getOrCreateChild(T::TYPE_NAME, id) );
|
||||
return dynamic_cast<T*>( getOrCreateChild(T::TYPE_NAME, id).get() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/canvas/CanvasMgr.hxx>
|
||||
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
||||
#include <simgear/canvas/MouseEvent.hxx>
|
||||
#include <simgear/canvas/events/KeyboardEvent.hxx>
|
||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||
#include <simgear/scene/util/OsgMath.hxx>
|
||||
#include <simgear/scene/util/parse_color.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
@@ -29,8 +30,8 @@
|
||||
#include <osg/Array>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/PrimitiveSet>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <osgDB/Registry>
|
||||
#include <osg/Version>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@@ -75,8 +76,9 @@ namespace canvas
|
||||
osg::Drawable* drawable,
|
||||
osg::RenderInfo* renderInfo ) const
|
||||
{
|
||||
if( !_canvas.expired() )
|
||||
_canvas.lock()->enableRendering();
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( canvas )
|
||||
canvas->enableRendering();
|
||||
|
||||
if( !_cull_next_frame )
|
||||
// TODO check if window/image should be culled
|
||||
@@ -96,16 +98,21 @@ namespace canvas
|
||||
return;
|
||||
|
||||
addStyle("fill", "color", &Image::setFill);
|
||||
addStyle("outset", "", &Image::setOutset);
|
||||
addStyle("preserveAspectRatio", "", &Image::setPreserveAspectRatio);
|
||||
addStyle("slice", "", &Image::setSlice);
|
||||
addStyle("slice-width", "", &Image::setSliceWidth);
|
||||
addStyle("outset", "", &Image::setOutset);
|
||||
|
||||
osgDB::Registry* reg = osgDB::Registry::instance();
|
||||
if( !reg->getReaderWriterForExtension("png") )
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: Missing 'png' image reader");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Image::Image( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent),
|
||||
_texture(new osg::Texture2D),
|
||||
_node_src_rect( node->getNode("source", 0, true) ),
|
||||
@@ -128,12 +135,11 @@ namespace canvas
|
||||
|
||||
_texCoords = new osg::Vec2Array(4);
|
||||
_texCoords->setDataVariance(osg::Object::DYNAMIC);
|
||||
_geom->setTexCoordArray(0, _texCoords);
|
||||
_geom->setTexCoordArray(0, _texCoords, osg::Array::BIND_PER_VERTEX);
|
||||
|
||||
_colors = new osg::Vec4Array(1);
|
||||
_colors->setDataVariance(osg::Object::DYNAMIC);
|
||||
_geom->setColorArray(_colors);
|
||||
_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||
_geom->setColorArray(_colors, osg::Array::BIND_OVERALL);
|
||||
|
||||
_prim = new osg::DrawArrays(osg::PrimitiveSet::QUADS);
|
||||
_prim->set(osg::PrimitiveSet::QUADS, 0, 4);
|
||||
@@ -149,7 +155,9 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
Image::~Image()
|
||||
{
|
||||
|
||||
if( _http_request ) {
|
||||
Canvas::getSystemAdapter()->getHTTPClient()->cancelRequest(_http_request, "image destroyed");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -214,6 +222,10 @@ namespace canvas
|
||||
if( !_slice.isValid() )
|
||||
{
|
||||
setQuad(0, region.getMin(), region.getMax());
|
||||
|
||||
if( !_preserve_aspect_ratio.scaleToFill() )
|
||||
// We need to update texture coordinates to keep the aspect ratio
|
||||
_attributes_dirty |= SRC_RECT;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -272,7 +284,6 @@ namespace canvas
|
||||
_vertices->dirty();
|
||||
_attributes_dirty &= ~DEST_SIZE;
|
||||
_geom->dirtyBound();
|
||||
setBoundingBox(_geom->getBound());
|
||||
}
|
||||
|
||||
if( _attributes_dirty & SRC_RECT )
|
||||
@@ -291,6 +302,66 @@ namespace canvas
|
||||
|
||||
if( !_slice.isValid() )
|
||||
{
|
||||
// Image scaling preserving aspect ratio. Change texture coordinates to
|
||||
// scale image accordingly.
|
||||
//
|
||||
// TODO allow to specify what happens to not filled space (eg. color,
|
||||
// or texture repeat/mirror)
|
||||
//
|
||||
// http://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
|
||||
if( !_preserve_aspect_ratio.scaleToFill() )
|
||||
{
|
||||
osg::BoundingBox const& bb = getBoundingBox();
|
||||
float dst_width = bb._max.x() - bb._min.x(),
|
||||
dst_height = bb._max.y() - bb._min.y();
|
||||
float scale_x = dst_width / tex_dim.width(),
|
||||
scale_y = dst_height / tex_dim.height();
|
||||
|
||||
float scale = _preserve_aspect_ratio.scaleToFit()
|
||||
? std::min(scale_x, scale_y)
|
||||
: std::max(scale_x, scale_y);
|
||||
|
||||
if( scale_x != scale )
|
||||
{
|
||||
float d = scale_x / scale - 1;
|
||||
if( _preserve_aspect_ratio.alignX()
|
||||
== SVGpreserveAspectRatio::ALIGN_MIN )
|
||||
{
|
||||
src_rect.r() += d;
|
||||
}
|
||||
else if( _preserve_aspect_ratio.alignX()
|
||||
== SVGpreserveAspectRatio::ALIGN_MAX )
|
||||
{
|
||||
src_rect.l() -= d;
|
||||
}
|
||||
else
|
||||
{
|
||||
src_rect.l() -= d / 2;
|
||||
src_rect.r() += d / 2;
|
||||
}
|
||||
}
|
||||
|
||||
if( scale_y != scale )
|
||||
{
|
||||
float d = scale_y / scale - 1;
|
||||
if( _preserve_aspect_ratio.alignY()
|
||||
== SVGpreserveAspectRatio::ALIGN_MIN )
|
||||
{
|
||||
src_rect.b() -= d;
|
||||
}
|
||||
else if( _preserve_aspect_ratio.alignY()
|
||||
== SVGpreserveAspectRatio::ALIGN_MAX )
|
||||
{
|
||||
src_rect.t() += d;
|
||||
}
|
||||
else
|
||||
{
|
||||
src_rect.t() += d / 2;
|
||||
src_rect.b() -= d / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setQuadUV(0, src_rect.getMin(), src_rect.getMax());
|
||||
}
|
||||
else
|
||||
@@ -344,7 +415,14 @@ namespace canvas
|
||||
&& child->getNameString() == "visible"
|
||||
&& child->getBoolValue() )
|
||||
{
|
||||
CullCallback* cb = static_cast<CullCallback*>(_geom->getCullCallback());
|
||||
CullCallback* cb =
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
static_cast<CullCallback*>
|
||||
#else
|
||||
dynamic_cast<CullCallback*>
|
||||
#endif
|
||||
( _geom->getCullCallback() );
|
||||
|
||||
if( cb )
|
||||
cb->cullNextFrame();
|
||||
}
|
||||
@@ -386,7 +464,7 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::setImage(osg::Image *img)
|
||||
void Image::setImage(osg::ref_ptr<osg::Image> img)
|
||||
{
|
||||
// remove canvas...
|
||||
setSrcCanvas( CanvasPtr() );
|
||||
@@ -414,6 +492,20 @@ namespace canvas
|
||||
_colors->dirty();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::setOutset(const std::string& outset)
|
||||
{
|
||||
_outset = CSSBorder::parse(outset);
|
||||
_attributes_dirty |= DEST_SIZE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::setPreserveAspectRatio(const std::string& scale)
|
||||
{
|
||||
_preserve_aspect_ratio = SVGpreserveAspectRatio::parse(scale);
|
||||
_attributes_dirty |= SRC_RECT;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::setSlice(const std::string& slice)
|
||||
{
|
||||
@@ -428,13 +520,6 @@ namespace canvas
|
||||
_attributes_dirty |= DEST_SIZE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::setOutset(const std::string& outset)
|
||||
{
|
||||
_outset = CSSBorder::parse(outset);
|
||||
_attributes_dirty |= DEST_SIZE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const SGRect<float>& Image::getRegion() const
|
||||
{
|
||||
@@ -442,7 +527,7 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Image::handleEvent(EventPtr event)
|
||||
bool Image::handleEvent(const EventPtr& event)
|
||||
{
|
||||
bool handled = Element::handleEvent(event);
|
||||
|
||||
@@ -450,11 +535,9 @@ namespace canvas
|
||||
if( !src_canvas )
|
||||
return handled;
|
||||
|
||||
MouseEventPtr mouse_event = boost::dynamic_pointer_cast<MouseEvent>(event);
|
||||
if( mouse_event )
|
||||
if( MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get()) )
|
||||
{
|
||||
mouse_event.reset( new MouseEvent(*mouse_event) );
|
||||
event = mouse_event;
|
||||
|
||||
mouse_event->client_pos = mouse_event->local_pos
|
||||
- toOsg(_region.getMin());
|
||||
@@ -474,9 +557,16 @@ namespace canvas
|
||||
mouse_event->client_pos.x() *= src_canvas->getViewWidth() / size.x();
|
||||
mouse_event->client_pos.y() *= src_canvas->getViewHeight()/ size.y();
|
||||
mouse_event->local_pos = mouse_event->client_pos;
|
||||
|
||||
handled |= src_canvas->handleMouseEvent(mouse_event);
|
||||
}
|
||||
else if( KeyboardEventPtr keyboard_event =
|
||||
dynamic_cast<KeyboardEvent*>(event.get()) )
|
||||
{
|
||||
handled |= src_canvas->handleKeyboardEvent(keyboard_event);
|
||||
}
|
||||
|
||||
return handled | src_canvas->handleMouseEvent(mouse_event);
|
||||
return handled;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -521,20 +611,41 @@ namespace canvas
|
||||
|
||||
_attributes_dirty |= DEST_SIZE;
|
||||
}
|
||||
else if( name == "file" )
|
||||
else if( name == "src" || name == "file" )
|
||||
{
|
||||
static const std::string CANVAS_PROTOCOL = "canvas://";
|
||||
const std::string& path = child->getStringValue();
|
||||
if( name == "file" )
|
||||
SG_LOG(SG_GL, SG_WARN, "'file' is deprecated. Use 'src' instead");
|
||||
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( !canvas )
|
||||
// Abort pending request
|
||||
if( _http_request )
|
||||
{
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No canvas available");
|
||||
return;
|
||||
Canvas::getSystemAdapter()->getHTTPClient()->cancelRequest(_http_request, "setting new image");
|
||||
_http_request.reset();
|
||||
}
|
||||
|
||||
if( boost::starts_with(path, CANVAS_PROTOCOL) )
|
||||
static const std::string PROTOCOL_SEP = "://";
|
||||
|
||||
std::string url = child->getStringValue(),
|
||||
protocol, path;
|
||||
|
||||
size_t sep_pos = url.find(PROTOCOL_SEP);
|
||||
if( sep_pos != std::string::npos )
|
||||
{
|
||||
protocol = url.substr(0, sep_pos);
|
||||
path = url.substr(sep_pos + PROTOCOL_SEP.length());
|
||||
}
|
||||
else
|
||||
path = url;
|
||||
|
||||
if( protocol == "canvas" )
|
||||
{
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( !canvas )
|
||||
{
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No canvas available");
|
||||
return;
|
||||
}
|
||||
|
||||
CanvasMgr* canvas_mgr = canvas->getCanvasMgr();
|
||||
if( !canvas_mgr )
|
||||
{
|
||||
@@ -545,7 +656,7 @@ namespace canvas
|
||||
const SGPropertyNode* canvas_node =
|
||||
canvas_mgr->getPropertyRoot()
|
||||
->getParent()
|
||||
->getNode( path.substr(CANVAS_PROTOCOL.size()) );
|
||||
->getNode( path );
|
||||
if( !canvas_node )
|
||||
{
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No such canvas: " << path);
|
||||
@@ -563,6 +674,16 @@ namespace canvas
|
||||
|
||||
setSrcCanvas(src_canvas);
|
||||
}
|
||||
else if( protocol == "http" || protocol == "https" )
|
||||
// TODO check https
|
||||
{
|
||||
_http_request =
|
||||
Canvas::getSystemAdapter()
|
||||
->getHTTPClient()
|
||||
->load(url)
|
||||
// TODO handle capture of 'this'
|
||||
->done(this, &Image::handleImageLoadDone);
|
||||
}
|
||||
else
|
||||
{
|
||||
setImage( Canvas::getSystemAdapter()->getImage(path) );
|
||||
@@ -638,5 +759,65 @@ namespace canvas
|
||||
(*_texCoords)[i + 3].set(tl.x(), br.y());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Image::handleImageLoadDone(HTTP::Request* req)
|
||||
{
|
||||
// Ignore stale/expired requests
|
||||
if( _http_request != req )
|
||||
return;
|
||||
_http_request.reset();
|
||||
|
||||
if( req->responseCode() != 200 )
|
||||
{
|
||||
SG_LOG(SG_IO, SG_WARN, "failed to download '" << req->url() << "': "
|
||||
<< req->responseReason());
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string ext = SGPath(req->path()).extension(),
|
||||
mime = req->responseMime();
|
||||
|
||||
SG_LOG(SG_IO, SG_INFO, "received " << req->url() <<
|
||||
" (ext=" << ext << ", MIME=" << mime << ")");
|
||||
|
||||
const std::string& img_data =
|
||||
static_cast<HTTP::MemoryRequest*>(req)->responseBody();
|
||||
osgDB::Registry* reg = osgDB::Registry::instance();
|
||||
|
||||
// First try to detect image type by extension
|
||||
osgDB::ReaderWriter* rw = reg->getReaderWriterForExtension(ext);
|
||||
if( rw && loadImage(*rw, img_data, *req, "extension") )
|
||||
return;
|
||||
|
||||
// Now try with MIME type
|
||||
rw = reg->getReaderWriterForMimeType(mime);
|
||||
if( rw && loadImage(*rw, img_data, *req, "MIME type") )
|
||||
return;
|
||||
|
||||
SG_LOG(SG_IO, SG_WARN, "unable to read image '" << req->url() << "'");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Image::loadImage( osgDB::ReaderWriter& reader,
|
||||
const std::string& data,
|
||||
HTTP::Request& request,
|
||||
const std::string& type )
|
||||
{
|
||||
SG_LOG(SG_IO, SG_DEBUG, "use image reader detected by " << type);
|
||||
|
||||
std::istringstream data_strm(data);
|
||||
osgDB::ReaderWriter::ReadResult result = reader.readImage(data_strm);
|
||||
if( result.success() )
|
||||
{
|
||||
setImage( result.takeImage() );
|
||||
return true;
|
||||
}
|
||||
|
||||
SG_LOG(SG_IO, SG_WARN, "failed to read image '" << request.url() << "': "
|
||||
<< result.message());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
@@ -22,11 +22,14 @@
|
||||
#include "CanvasElement.hxx"
|
||||
|
||||
#include <simgear/canvas/canvas_fwd.hxx>
|
||||
#include <simgear/io/HTTPClient.hxx>
|
||||
#include <simgear/misc/CSSBorder.hxx>
|
||||
#include <simgear/misc/SVGpreserveAspectRatio.hxx>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace HTTP { class Request; }
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
@@ -47,7 +50,7 @@ namespace canvas
|
||||
Image( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style = Style(),
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Image();
|
||||
|
||||
virtual void update(double dt);
|
||||
@@ -56,9 +59,20 @@ namespace canvas
|
||||
void setSrcCanvas(CanvasPtr canvas);
|
||||
CanvasWeakPtr getSrcCanvas() const;
|
||||
|
||||
void setImage(osg::Image *img);
|
||||
void setImage(osg::ref_ptr<osg::Image> img);
|
||||
void setFill(const std::string& fill);
|
||||
|
||||
/**
|
||||
* @see http://www.w3.org/TR/css3-background/#border-image-outset
|
||||
*/
|
||||
void setOutset(const std::string& outset);
|
||||
|
||||
/**
|
||||
* @see
|
||||
* http://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
|
||||
*/
|
||||
void setPreserveAspectRatio(const std::string& scale);
|
||||
|
||||
/**
|
||||
* Set image slice (aka. 9-scale)
|
||||
*
|
||||
@@ -77,14 +91,9 @@ namespace canvas
|
||||
*/
|
||||
void setSliceWidth(const std::string& width);
|
||||
|
||||
/**
|
||||
* http://www.w3.org/TR/css3-background/#border-image-outset
|
||||
*/
|
||||
void setOutset(const std::string& outset);
|
||||
|
||||
const SGRect<float>& getRegion() const;
|
||||
|
||||
bool handleEvent(EventPtr event);
|
||||
bool handleEvent(const EventPtr& event);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -103,9 +112,16 @@ namespace canvas
|
||||
void setQuad(size_t index, const SGVec2f& tl, const SGVec2f& br);
|
||||
void setQuadUV(size_t index, const SGVec2f& tl, const SGVec2f& br);
|
||||
|
||||
void handleImageLoadDone(HTTP::Request*);
|
||||
bool loadImage( osgDB::ReaderWriter& reader,
|
||||
const std::string& data,
|
||||
HTTP::Request& request,
|
||||
const std::string& type );
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> _texture;
|
||||
// TODO optionally forward events to canvas
|
||||
CanvasWeakPtr _src_canvas;
|
||||
HTTP::Request_ptr _http_request;
|
||||
|
||||
osg::ref_ptr<osg::Geometry> _geom;
|
||||
osg::ref_ptr<osg::DrawArrays>_prim;
|
||||
@@ -117,9 +133,11 @@ namespace canvas
|
||||
SGRect<float> _src_rect,
|
||||
_region;
|
||||
|
||||
CSSBorder _slice,
|
||||
_slice_width,
|
||||
_outset;
|
||||
SVGpreserveAspectRatio _preserve_aspect_ratio;
|
||||
|
||||
CSSBorder _outset,
|
||||
_slice,
|
||||
_slice_width;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace canvas
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const std::string GEO = "-geo";
|
||||
const std::string HDG = "hdg";
|
||||
const std::string Map::TYPE_NAME = "map";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -61,7 +62,7 @@ namespace canvas
|
||||
Map::Map( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Group(canvas, node, parent_style, parent),
|
||||
// TODO make projection configurable
|
||||
_projection(new SansonFlamsteedProjection),
|
||||
@@ -112,87 +113,50 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
||||
if( boost::ends_with(child->getNameString(), GEO) )
|
||||
_geo_nodes[child].reset(new GeoNodePair());
|
||||
else if( parent != _node && child->getNameString() == HDG )
|
||||
_hdg_nodes.insert(child);
|
||||
else
|
||||
return Element::childAdded(parent, child);
|
||||
|
||||
_geo_nodes[child].reset(new GeoNodePair());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
||||
return Element::childRemoved(parent, child);
|
||||
|
||||
// TODO remove from other node
|
||||
_geo_nodes.erase(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::valueChanged(SGPropertyNode * child)
|
||||
{
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
if( !boost::ends_with(name, GEO) )
|
||||
return Group::valueChanged(child);
|
||||
|
||||
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
|
||||
if( it_geo_node == _geo_nodes.end() )
|
||||
LOG_GEO_RET("geo node not found!")
|
||||
GeoNodePair* geo_node = it_geo_node->second.get();
|
||||
|
||||
geo_node->setDirty();
|
||||
|
||||
if( geo_node->getStatus() & GeoNodePair::INCOMPLETE )
|
||||
if( boost::ends_with(child->getNameString(), GEO) )
|
||||
// TODO remove from other node
|
||||
_geo_nodes.erase(child);
|
||||
else if( parent != _node && child->getName() == HDG )
|
||||
{
|
||||
// Detect lat, lon tuples...
|
||||
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
||||
int index_other = -1;
|
||||
_hdg_nodes.erase(child);
|
||||
|
||||
switch( coord.type )
|
||||
{
|
||||
case GeoCoord::LATITUDE:
|
||||
index_other = child->getIndex() + 1;
|
||||
geo_node->setNodeLat(child);
|
||||
break;
|
||||
case GeoCoord::LONGITUDE:
|
||||
index_other = child->getIndex() - 1;
|
||||
geo_node->setNodeLon(child);
|
||||
break;
|
||||
default:
|
||||
LOG_GEO_RET("Invalid geo coord")
|
||||
}
|
||||
|
||||
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
|
||||
if( !other )
|
||||
return;
|
||||
|
||||
GeoCoord coord_other = parseGeoCoord(other->getStringValue());
|
||||
if( coord_other.type == GeoCoord::INVALID
|
||||
|| coord_other.type == coord.type )
|
||||
return;
|
||||
|
||||
GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
|
||||
if( it_geo_node_other == _geo_nodes.end() )
|
||||
LOG_GEO_RET("other geo node not found!")
|
||||
GeoNodePair* geo_node_other = it_geo_node_other->second.get();
|
||||
|
||||
// Let use both nodes use the same GeoNodePair instance
|
||||
if( geo_node_other != geo_node )
|
||||
it_geo_node_other->second = it_geo_node->second;
|
||||
|
||||
if( coord_other.type == GeoCoord::LATITUDE )
|
||||
geo_node->setNodeLat(other);
|
||||
else
|
||||
geo_node->setNodeLon(other);
|
||||
|
||||
// Set name for resulting screen coordinate nodes
|
||||
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
|
||||
// Remove rotation matrix (tf[0]) and return to element always being
|
||||
// oriented upwards (or any orientation inside other matrices).
|
||||
child->getParent()->removeChild("tf", 0);
|
||||
}
|
||||
else
|
||||
return Element::childRemoved(parent, child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childChanged(SGPropertyNode * child)
|
||||
void Map::valueChanged(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
{
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
if( boost::ends_with(name, GEO) )
|
||||
return geoNodeChanged(child);
|
||||
else if( name == HDG )
|
||||
return hdgNodeChanged(child);
|
||||
}
|
||||
|
||||
return Group::valueChanged(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childChanged(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
return Group::childChanged(child);
|
||||
@@ -201,8 +165,14 @@ namespace canvas
|
||||
|| child->getNameString() == "ref-lon" )
|
||||
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
|
||||
_node->getDoubleValue("ref-lon") );
|
||||
else if( child->getNameString() == "hdg" )
|
||||
else if( child->getNameString() == HDG )
|
||||
{
|
||||
_projection->setOrientation(child->getFloatValue());
|
||||
for( NodeSet::iterator it = _hdg_nodes.begin();
|
||||
it != _hdg_nodes.end();
|
||||
++it )
|
||||
hdgNodeChanged(*it);
|
||||
}
|
||||
else if( child->getNameString() == "range" )
|
||||
_projection->setRange(child->getDoubleValue());
|
||||
else if( child->getNameString() == "screen-range" )
|
||||
@@ -213,6 +183,74 @@ namespace canvas
|
||||
_projection_dirty = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::geoNodeChanged(SGPropertyNode* child)
|
||||
{
|
||||
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
|
||||
if( it_geo_node == _geo_nodes.end() )
|
||||
LOG_GEO_RET("GeoNode not found!")
|
||||
GeoNodePair* geo_node = it_geo_node->second.get();
|
||||
|
||||
geo_node->setDirty();
|
||||
|
||||
if( !(geo_node->getStatus() & GeoNodePair::INCOMPLETE) )
|
||||
return;
|
||||
|
||||
// Detect lat, lon tuples...
|
||||
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
||||
int index_other = -1;
|
||||
|
||||
switch( coord.type )
|
||||
{
|
||||
case GeoCoord::LATITUDE:
|
||||
index_other = child->getIndex() + 1;
|
||||
geo_node->setNodeLat(child);
|
||||
break;
|
||||
case GeoCoord::LONGITUDE:
|
||||
index_other = child->getIndex() - 1;
|
||||
geo_node->setNodeLon(child);
|
||||
break;
|
||||
default:
|
||||
LOG_GEO_RET("Invalid geo coord")
|
||||
}
|
||||
|
||||
const std::string& name = child->getNameString();
|
||||
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
|
||||
if( !other )
|
||||
return;
|
||||
|
||||
GeoCoord coord_other = parseGeoCoord(other->getStringValue());
|
||||
if( coord_other.type == GeoCoord::INVALID
|
||||
|| coord_other.type == coord.type )
|
||||
return;
|
||||
|
||||
GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
|
||||
if( it_geo_node_other == _geo_nodes.end() )
|
||||
LOG_GEO_RET("other geo node not found!")
|
||||
GeoNodePair* geo_node_other = it_geo_node_other->second.get();
|
||||
|
||||
// Let use both nodes use the same GeoNodePair instance
|
||||
if( geo_node_other != geo_node )
|
||||
it_geo_node_other->second = it_geo_node->second;
|
||||
|
||||
if( coord_other.type == GeoCoord::LATITUDE )
|
||||
geo_node->setNodeLat(other);
|
||||
else
|
||||
geo_node->setNodeLon(other);
|
||||
|
||||
// Set name for resulting screen coordinate nodes
|
||||
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::hdgNodeChanged(SGPropertyNode* child)
|
||||
{
|
||||
child->getParent()->setFloatValue(
|
||||
"tf[0]/rot",
|
||||
SGMiscf::deg2rad(child->getFloatValue() - _projection->orientation())
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Map::GeoCoord Map::parseGeoCoord(const std::string& val) const
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@@ -41,7 +42,7 @@ namespace canvas
|
||||
Map( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Map();
|
||||
|
||||
virtual void update(double dt);
|
||||
@@ -59,14 +60,18 @@ namespace canvas
|
||||
typedef boost::unordered_map< SGPropertyNode*,
|
||||
boost::shared_ptr<GeoNodePair>
|
||||
> GeoNodes;
|
||||
typedef boost::unordered_set<SGPropertyNode*> NodeSet;
|
||||
|
||||
GeoNodes _geo_nodes;
|
||||
NodeSet _hdg_nodes;
|
||||
boost::shared_ptr<HorizontalProjection> _projection;
|
||||
bool _projection_dirty;
|
||||
|
||||
struct GeoCoord
|
||||
{
|
||||
GeoCoord():
|
||||
type(INVALID)
|
||||
type(INVALID),
|
||||
value(0)
|
||||
{}
|
||||
enum
|
||||
{
|
||||
@@ -77,6 +82,9 @@ namespace canvas
|
||||
double value;
|
||||
};
|
||||
|
||||
void geoNodeChanged(SGPropertyNode * child);
|
||||
void hdgNodeChanged(SGPropertyNode * child);
|
||||
|
||||
GeoCoord parseGeoCoord(const std::string& val) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <simgear/scene/util/parse_color.hxx>
|
||||
|
||||
#include <osg/Drawable>
|
||||
#include <osg/Version>
|
||||
|
||||
#include <vg/openvg.h>
|
||||
#include <cassert>
|
||||
@@ -69,7 +70,8 @@ namespace canvas
|
||||
_mode(0),
|
||||
_fill_rule(VG_EVEN_ODD),
|
||||
_stroke_width(1),
|
||||
_stroke_linecap(VG_CAP_BUTT)
|
||||
_stroke_linecap(VG_CAP_BUTT),
|
||||
_stroke_linejoin(VG_JOIN_MITER)
|
||||
{
|
||||
setSupportsDisplayList(false);
|
||||
setDataVariance(Object::DYNAMIC);
|
||||
@@ -202,6 +204,21 @@ namespace canvas
|
||||
_stroke_linecap = VG_CAP_BUTT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stroke-linejoin
|
||||
*
|
||||
* @see http://www.w3.org/TR/SVG/painting.html#StrokeLinejoinProperty
|
||||
*/
|
||||
void setStrokeLinejoin(const std::string& linejoin)
|
||||
{
|
||||
if( linejoin == "round" )
|
||||
_stroke_linejoin = VG_JOIN_ROUND;
|
||||
else if( linejoin == "bevel" )
|
||||
_stroke_linejoin = VG_JOIN_BEVEL;
|
||||
else
|
||||
_stroke_linejoin = VG_JOIN_MITER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw callback
|
||||
*/
|
||||
@@ -217,9 +234,10 @@ namespace canvas
|
||||
state->setClientActiveTextureUnit(0);
|
||||
state->disableAllVertexArrays();
|
||||
|
||||
glPushAttrib(~0u); // Don't use GL_ALL_ATTRIB_BITS as on my machine it
|
||||
// eg. doesn't include GL_MULTISAMPLE_BIT
|
||||
glPushClientAttrib(~0u);
|
||||
bool was_blend_enabled = state->getLastAppliedMode(GL_BLEND);
|
||||
bool was_stencil_enabled = state->getLastAppliedMode(GL_STENCIL_TEST);
|
||||
osg::StateAttribute const* blend_func =
|
||||
state->getLastAppliedAttribute(osg::StateAttribute::BLENDFUNC);
|
||||
|
||||
// Initialize/Update the paint
|
||||
if( _attributes_dirty & STROKE_COLOR )
|
||||
@@ -250,6 +268,7 @@ namespace canvas
|
||||
|
||||
vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width);
|
||||
vgSeti(VG_STROKE_CAP_STYLE, _stroke_linecap);
|
||||
vgSeti(VG_STROKE_JOIN_STYLE, _stroke_linejoin);
|
||||
vgSetfv( VG_STROKE_DASH_PATTERN,
|
||||
_stroke_dash.size(),
|
||||
_stroke_dash.empty() ? 0 : &_stroke_dash[0] );
|
||||
@@ -269,15 +288,19 @@ namespace canvas
|
||||
if( err != VG_NO_ERROR )
|
||||
SG_LOG(SG_GL, SG_ALERT, "vgError: " << err);
|
||||
|
||||
glPopAttrib();
|
||||
glPopClientAttrib();
|
||||
// Restore OpenGL state (TODO check if more is needed or integrate
|
||||
// better with OpenSceneGraph)
|
||||
if( was_blend_enabled ) glEnable(GL_BLEND);
|
||||
if( was_stencil_enabled ) glEnable(GL_STENCIL_TEST);
|
||||
if( blend_func ) blend_func->apply(*state);
|
||||
}
|
||||
|
||||
osg::BoundingBox getTransformedBounds(const osg::Matrix& mat) const
|
||||
{
|
||||
osg::BoundingBox bb;
|
||||
|
||||
osg::Vec2f cur; // VG "Current point" (in local coordinates)
|
||||
osg::Vec2f cur(0, 0), // VG "Current point" (in local coordinates)
|
||||
sub(0, 0); // beginning of current sub path
|
||||
VGubyte cmd_index = 0;
|
||||
for( size_t i = 0, ci = 0;
|
||||
i < _cmds.size() && ci < _coords.size();
|
||||
@@ -297,6 +320,7 @@ namespace canvas
|
||||
switch( cmd )
|
||||
{
|
||||
case VG_CLOSE_PATH:
|
||||
cur = sub;
|
||||
break;
|
||||
case VG_MOVE_TO:
|
||||
case VG_LINE_TO:
|
||||
@@ -352,7 +376,12 @@ namespace canvas
|
||||
}
|
||||
|
||||
if( num_coords > 0 )
|
||||
{
|
||||
cur = points[ num_coords - 1 ];
|
||||
|
||||
if( cmd == VG_MOVE_TO )
|
||||
sub = cur;
|
||||
}
|
||||
}
|
||||
|
||||
return bb;
|
||||
@@ -361,7 +390,13 @@ namespace canvas
|
||||
/**
|
||||
* Compute the bounding box
|
||||
*/
|
||||
virtual osg::BoundingBox computeBound() const
|
||||
virtual osg::BoundingBox
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
computeBound()
|
||||
#else
|
||||
computeBoundingBox()
|
||||
#endif
|
||||
const
|
||||
{
|
||||
if( _path == VG_INVALID_HANDLE || (_attributes_dirty & PATH) )
|
||||
return osg::BoundingBox();
|
||||
@@ -374,14 +409,11 @@ namespace canvas
|
||||
// vgPathBounds doesn't take stroke width into account
|
||||
float ext = 0.5 * _stroke_width;
|
||||
|
||||
osg::BoundingBox bb
|
||||
return osg::BoundingBox
|
||||
(
|
||||
min[0] - ext, min[1] - ext, -0.1,
|
||||
min[0] + size[0] + ext, min[1] + size[1] + ext, 0.1
|
||||
);
|
||||
_path_element->setBoundingBox(bb);
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -411,6 +443,7 @@ namespace canvas
|
||||
VGfloat _stroke_width;
|
||||
std::vector<VGfloat> _stroke_dash;
|
||||
VGCapStyle _stroke_linecap;
|
||||
VGJoinStyle _stroke_linejoin;
|
||||
|
||||
osg::Vec3f transformPoint( const osg::Matrix& m,
|
||||
osg::Vec2f pos ) const
|
||||
@@ -456,7 +489,12 @@ namespace canvas
|
||||
}
|
||||
|
||||
if( _attributes_dirty & BOUNDING_BOX )
|
||||
{
|
||||
dirtyBound();
|
||||
|
||||
// Recalculate bounding box now (prevent race condition)
|
||||
getBound();
|
||||
}
|
||||
}
|
||||
|
||||
struct PathUpdateCallback:
|
||||
@@ -486,13 +524,14 @@ namespace canvas
|
||||
addStyle("stroke-width", "numeric", &PathDrawable::setStrokeWidth, path);
|
||||
addStyle("stroke-dasharray", "", &PathDrawable::setStrokeDashArray, path);
|
||||
addStyle("stroke-linecap", "", &PathDrawable::setStrokeLinecap, path);
|
||||
addStyle("stroke-linejoin", "", &PathDrawable::setStrokeLinejoin, path);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Path::Path( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent),
|
||||
_path( new PathDrawable(this) )
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace canvas
|
||||
Path( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Path();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
||||
#include <simgear/scene/util/parse_color.hxx>
|
||||
#include <osg/Version>
|
||||
#include <osgDB/Registry>
|
||||
#include <osgText/Text>
|
||||
|
||||
namespace simgear
|
||||
@@ -31,26 +32,199 @@ namespace canvas
|
||||
public osgText::Text
|
||||
{
|
||||
public:
|
||||
|
||||
TextOSG(canvas::Text* text);
|
||||
|
||||
void setFontResolution(int res);
|
||||
void setCharacterAspect(float aspect);
|
||||
void setLineHeight(float factor);
|
||||
void setFill(const std::string& fill);
|
||||
void setStroke(const std::string& color);
|
||||
void setBackgroundColor(const std::string& fill);
|
||||
|
||||
osg::Vec2 handleHit(const osg::Vec2f& pos);
|
||||
float lineHeight() const;
|
||||
|
||||
virtual osg::BoundingBox computeBound() const;
|
||||
/// Get the number of lines
|
||||
size_t lineCount() const;
|
||||
|
||||
/// Get line @a i
|
||||
TextLine lineAt(size_t i) const;
|
||||
|
||||
/// Get nearest line to given y-coordinate
|
||||
TextLine nearestLine(float pos_y) const;
|
||||
|
||||
|
||||
SGVec2i sizeForWidth(int w) const;
|
||||
|
||||
virtual osg::BoundingBox
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
computeBound()
|
||||
#else
|
||||
computeBoundingBox()
|
||||
#endif
|
||||
const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class TextLine;
|
||||
|
||||
canvas::Text *_text_element;
|
||||
|
||||
virtual void computePositions(unsigned int contextID) const;
|
||||
};
|
||||
|
||||
class TextLine
|
||||
{
|
||||
public:
|
||||
TextLine();
|
||||
TextLine(size_t line, Text::TextOSG const* text);
|
||||
|
||||
/// Number of characters on this line
|
||||
size_t size() const;
|
||||
bool empty() const;
|
||||
|
||||
osg::Vec2 cursorPos(size_t i) const;
|
||||
osg::Vec2 nearestCursor(float x) const;
|
||||
|
||||
protected:
|
||||
typedef Text::TextOSG::GlyphQuads GlyphQuads;
|
||||
|
||||
Text::TextOSG const *_text;
|
||||
GlyphQuads const *_quads;
|
||||
|
||||
size_t _line,
|
||||
_begin,
|
||||
_end;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
TextLine::TextLine():
|
||||
_text(NULL),
|
||||
_quads(NULL),
|
||||
_line(0),
|
||||
_begin(-1),
|
||||
_end(-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
TextLine::TextLine(size_t line, Text::TextOSG const* text):
|
||||
_text(text),
|
||||
_quads(NULL),
|
||||
_line(line),
|
||||
_begin(-1),
|
||||
_end(-1)
|
||||
{
|
||||
if( !text || text->_textureGlyphQuadMap.empty() || !_text->lineCount() )
|
||||
return;
|
||||
|
||||
_quads = &text->_textureGlyphQuadMap.begin()->second;
|
||||
|
||||
GlyphQuads::LineNumbers const& line_numbers = _quads->_lineNumbers;
|
||||
GlyphQuads::LineNumbers::const_iterator begin_it =
|
||||
std::lower_bound(line_numbers.begin(), line_numbers.end(), _line);
|
||||
|
||||
if( begin_it == line_numbers.end() || *begin_it != _line )
|
||||
// empty line or past last line
|
||||
return;
|
||||
|
||||
_begin = begin_it - line_numbers.begin();
|
||||
_end = std::upper_bound(begin_it, line_numbers.end(), _line)
|
||||
- line_numbers.begin();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t TextLine::size() const
|
||||
{
|
||||
return _end - _begin;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool TextLine::empty() const
|
||||
{
|
||||
return _end == _begin;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 TextLine::cursorPos(size_t i) const
|
||||
{
|
||||
if( !_quads )
|
||||
return osg::Vec2(0, 0);
|
||||
|
||||
if( i > size() )
|
||||
// Position after last character if out of range (TODO better exception?)
|
||||
i = size();
|
||||
|
||||
osg::Vec2 pos(0, _text->_offset.y() + _line * _text->lineHeight());
|
||||
|
||||
if( empty() )
|
||||
return pos;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||
#else
|
||||
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||
#endif
|
||||
size_t global_i = _begin + i;
|
||||
|
||||
if( global_i == _begin )
|
||||
// before first character of line
|
||||
pos.x() = coords[_begin * 4].x();
|
||||
else if( global_i == _end )
|
||||
// After Last character of line
|
||||
pos.x() = coords[(_end - 1) * 4 + 2].x();
|
||||
else
|
||||
{
|
||||
float prev_l = coords[(global_i - 1) * 4].x(),
|
||||
prev_r = coords[(global_i - 1) * 4 + 2].x(),
|
||||
cur_l = coords[global_i * 4].x();
|
||||
|
||||
if( prev_l == prev_r )
|
||||
// If previous character width is zero set to begin of next character
|
||||
// (Happens eg. with spaces)
|
||||
pos.x() = cur_l;
|
||||
else
|
||||
// position at center between characters
|
||||
pos.x() = 0.5 * (prev_r + cur_l);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 TextLine::nearestCursor(float x) const
|
||||
{
|
||||
if( empty() )
|
||||
return cursorPos(0);
|
||||
|
||||
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||
#else
|
||||
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||
#endif
|
||||
|
||||
float const HIT_FRACTION = 0.6;
|
||||
float const character_width = _text->getCharacterHeight()
|
||||
* _text->getCharacterAspectRatio();
|
||||
|
||||
size_t i = _begin;
|
||||
for(; i < _end; ++i)
|
||||
{
|
||||
// Get threshold for mouse x position for setting cursor before or after
|
||||
// current character
|
||||
float threshold = coords[i * 4].x()
|
||||
+ HIT_FRACTION * glyphs[i]->getHorizontalAdvance()
|
||||
* character_width;
|
||||
|
||||
if( x <= threshold )
|
||||
break;
|
||||
}
|
||||
|
||||
return cursorPos(i - _begin);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::TextOSG::TextOSG(canvas::Text* text):
|
||||
_text_element(text)
|
||||
@@ -87,6 +261,19 @@ namespace canvas
|
||||
setColor( color );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::TextOSG::setStroke(const std::string& stroke)
|
||||
{
|
||||
osg::Vec4 color;
|
||||
if( stroke == "none" || !parseColor(stroke, color) )
|
||||
setBackdropType(NONE);
|
||||
else
|
||||
{
|
||||
setBackdropType(OUTLINE);
|
||||
setBackdropColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::TextOSG::setBackgroundColor(const std::string& fill)
|
||||
{
|
||||
@@ -96,100 +283,344 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 Text::TextOSG::handleHit(const osg::Vec2f& pos)
|
||||
float Text::TextOSG::lineHeight() const
|
||||
{
|
||||
float line_height = _characterHeight + _lineSpacing;
|
||||
|
||||
// TODO check with align other than TOP
|
||||
float first_line_y = -0.5 * _lineSpacing;//_offset.y() - _characterHeight;
|
||||
size_t line = std::max<int>(0, (pos.y() - first_line_y) / line_height);
|
||||
|
||||
if( _textureGlyphQuadMap.empty() )
|
||||
return osg::Vec2(-1, -1);
|
||||
|
||||
// TODO check when it can be larger
|
||||
assert( _textureGlyphQuadMap.size() == 1 );
|
||||
|
||||
const GlyphQuads& glyphquad = _textureGlyphQuadMap.begin()->second;
|
||||
const GlyphQuads::Glyphs& glyphs = glyphquad._glyphs;
|
||||
const GlyphQuads::Coords2& coords = glyphquad._coords;
|
||||
const GlyphQuads::LineNumbers& line_numbers = glyphquad._lineNumbers;
|
||||
|
||||
const float HIT_FRACTION = 0.6;
|
||||
const float character_width = getCharacterHeight()
|
||||
* getCharacterAspectRatio();
|
||||
|
||||
float y = (line + 0.5) * line_height;
|
||||
|
||||
bool line_found = false;
|
||||
for(size_t i = 0; i < line_numbers.size(); ++i)
|
||||
{
|
||||
if( line_numbers[i] != line )
|
||||
{
|
||||
if( !line_found )
|
||||
{
|
||||
if( line_numbers[i] < line )
|
||||
// Wait for the correct line...
|
||||
continue;
|
||||
|
||||
// We have already passed the correct line -> It's empty...
|
||||
return osg::Vec2(0, y);
|
||||
}
|
||||
|
||||
// Next line and not returned -> not before any character
|
||||
// -> return position after last character of line
|
||||
return osg::Vec2(coords[(i - 1) * 4 + 2].x(), y);
|
||||
}
|
||||
|
||||
line_found = true;
|
||||
|
||||
// Get threshold for mouse x position for setting cursor before or after
|
||||
// current character
|
||||
float threshold = coords[i * 4].x()
|
||||
+ HIT_FRACTION * glyphs[i]->getHorizontalAdvance()
|
||||
* character_width;
|
||||
|
||||
if( pos.x() <= threshold )
|
||||
{
|
||||
osg::Vec2 hit(0, y);
|
||||
if( i == 0 || line_numbers[i - 1] != line )
|
||||
// first character of line
|
||||
hit.x() = coords[i * 4].x();
|
||||
else if( coords[(i - 1) * 4].x() == coords[(i - 1) * 4 + 2].x() )
|
||||
// If previous character width is zero set to begin of next character
|
||||
// (Happens eg. with spaces)
|
||||
hit.x() = coords[i * 4].x();
|
||||
else
|
||||
// position at center between characters
|
||||
hit.x() = 0.5 * (coords[(i - 1) * 4 + 2].x() + coords[i * 4].x());
|
||||
|
||||
return hit;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing found -> return position after last character
|
||||
return osg::Vec2
|
||||
(
|
||||
coords.back().x(),
|
||||
(_lineCount - 0.5) * line_height
|
||||
);
|
||||
return (1 + _lineSpacing) * _characterHeight;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::BoundingBox Text::TextOSG::computeBound() const
|
||||
size_t Text::TextOSG::lineCount() const
|
||||
{
|
||||
osg::BoundingBox bb = osgText::Text::computeBound();
|
||||
if( !bb.valid() )
|
||||
return bb;
|
||||
return _lineCount;
|
||||
}
|
||||
|
||||
#if OSG_VERSION_LESS_THAN(3,1,0)
|
||||
// TODO bounding box still doesn't seem always right (eg. with center
|
||||
// horizontal alignment not completely accurate)
|
||||
bb._min.y() += _offset.y();
|
||||
bb._max.y() += _offset.y();
|
||||
//----------------------------------------------------------------------------
|
||||
TextLine Text::TextOSG::lineAt(size_t i) const
|
||||
{
|
||||
return TextLine(i, this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
TextLine Text::TextOSG::nearestLine(float pos_y) const
|
||||
{
|
||||
osgText::Font const* font = getActiveFont();
|
||||
if( !font || lineCount() <= 0 )
|
||||
return TextLine(0, this);
|
||||
|
||||
float asc = .9f, desc = -.2f;
|
||||
font->getVerticalSize(asc, desc);
|
||||
|
||||
float first_line_y = _offset.y()
|
||||
- (1 + _lineSpacing / 2 + desc) * _characterHeight;
|
||||
|
||||
size_t line_num = std::min<size_t>(
|
||||
std::max<size_t>(0, (pos_y - first_line_y) / lineHeight()),
|
||||
lineCount() - 1
|
||||
);
|
||||
|
||||
return TextLine(line_num, this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// simplified version of osgText::Text::computeGlyphRepresentation() to
|
||||
// just calculate the size for a given weight. Glpyh calculations/creating
|
||||
// is not necessary for this...
|
||||
SGVec2i Text::TextOSG::sizeForWidth(int w) const
|
||||
{
|
||||
if( _text.empty() )
|
||||
return SGVec2i(0, 0);
|
||||
|
||||
osgText::Font* activefont = const_cast<osgText::Font*>(getActiveFont());
|
||||
if( !activefont )
|
||||
return SGVec2i(-1, -1);
|
||||
|
||||
float max_width_safe = _maximumWidth;
|
||||
const_cast<TextOSG*>(this)->_maximumWidth = w;
|
||||
|
||||
SGRecti bb;
|
||||
|
||||
osg::Vec2 startOfLine_coords(0.0f,0.0f);
|
||||
osg::Vec2 cursor(startOfLine_coords);
|
||||
osg::Vec2 local(0.0f,0.0f);
|
||||
|
||||
unsigned int previous_charcode = 0;
|
||||
unsigned int line_length = 0;
|
||||
bool horizontal = _layout != VERTICAL;
|
||||
bool kerning = true;
|
||||
|
||||
float hr = _characterHeight;
|
||||
float wr = hr / getCharacterAspectRatio();
|
||||
|
||||
// osg should really care more about const :-/
|
||||
osgText::String& text = const_cast<osgText::String&>(_text);
|
||||
typedef osgText::String::iterator TextIterator;
|
||||
|
||||
for( TextIterator itr = text.begin(); itr != text.end(); )
|
||||
{
|
||||
// record the start of the current line
|
||||
TextIterator startOfLine_itr = itr;
|
||||
|
||||
// find the end of the current line.
|
||||
osg::Vec2 endOfLine_coords(cursor);
|
||||
TextIterator endOfLine_itr =
|
||||
const_cast<TextOSG*>(this)->computeLastCharacterOnLine(
|
||||
endOfLine_coords, itr, text.end()
|
||||
);
|
||||
|
||||
line_length = endOfLine_itr - startOfLine_itr;
|
||||
|
||||
// Set line position to correct alignment.
|
||||
switch( _layout )
|
||||
{
|
||||
case LEFT_TO_RIGHT:
|
||||
{
|
||||
switch( _alignment )
|
||||
{
|
||||
// nothing to be done for these
|
||||
//case LEFT_TOP:
|
||||
//case LEFT_CENTER:
|
||||
//case LEFT_BOTTOM:
|
||||
//case LEFT_BASE_LINE:
|
||||
//case LEFT_BOTTOM_BASE_LINE:
|
||||
// break;
|
||||
case CENTER_TOP:
|
||||
case CENTER_CENTER:
|
||||
case CENTER_BOTTOM:
|
||||
case CENTER_BASE_LINE:
|
||||
case CENTER_BOTTOM_BASE_LINE:
|
||||
cursor.x() = (cursor.x() - endOfLine_coords.x()) * 0.5f;
|
||||
break;
|
||||
case RIGHT_TOP:
|
||||
case RIGHT_CENTER:
|
||||
case RIGHT_BOTTOM:
|
||||
case RIGHT_BASE_LINE:
|
||||
case RIGHT_BOTTOM_BASE_LINE:
|
||||
cursor.x() = cursor.x() - endOfLine_coords.x();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RIGHT_TO_LEFT:
|
||||
{
|
||||
switch( _alignment )
|
||||
{
|
||||
case LEFT_TOP:
|
||||
case LEFT_CENTER:
|
||||
case LEFT_BOTTOM:
|
||||
case LEFT_BASE_LINE:
|
||||
case LEFT_BOTTOM_BASE_LINE:
|
||||
cursor.x() = 2 * cursor.x() - endOfLine_coords.x();
|
||||
break;
|
||||
case CENTER_TOP:
|
||||
case CENTER_CENTER:
|
||||
case CENTER_BOTTOM:
|
||||
case CENTER_BASE_LINE:
|
||||
case CENTER_BOTTOM_BASE_LINE:
|
||||
cursor.x() = cursor.x()
|
||||
+ (cursor.x() - endOfLine_coords.x()) * 0.5f;
|
||||
break;
|
||||
// nothing to be done for these
|
||||
//case RIGHT_TOP:
|
||||
//case RIGHT_CENTER:
|
||||
//case RIGHT_BOTTOM:
|
||||
//case RIGHT_BASE_LINE:
|
||||
//case RIGHT_BOTTOM_BASE_LINE:
|
||||
// break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VERTICAL:
|
||||
{
|
||||
switch( _alignment )
|
||||
{
|
||||
// TODO: current behaviour top baselines lined up in both cases - need to implement
|
||||
// top of characters alignment - Question is this necessary?
|
||||
// ... otherwise, nothing to be done for these 6 cases
|
||||
//case LEFT_TOP:
|
||||
//case CENTER_TOP:
|
||||
//case RIGHT_TOP:
|
||||
// break;
|
||||
//case LEFT_BASE_LINE:
|
||||
//case CENTER_BASE_LINE:
|
||||
//case RIGHT_BASE_LINE:
|
||||
// break;
|
||||
case LEFT_CENTER:
|
||||
case CENTER_CENTER:
|
||||
case RIGHT_CENTER:
|
||||
cursor.y() = cursor.y()
|
||||
+ (cursor.y() - endOfLine_coords.y()) * 0.5f;
|
||||
break;
|
||||
case LEFT_BOTTOM_BASE_LINE:
|
||||
case CENTER_BOTTOM_BASE_LINE:
|
||||
case RIGHT_BOTTOM_BASE_LINE:
|
||||
cursor.y() = cursor.y() - (line_length * _characterHeight);
|
||||
break;
|
||||
case LEFT_BOTTOM:
|
||||
case CENTER_BOTTOM:
|
||||
case RIGHT_BOTTOM:
|
||||
cursor.y() = 2 * cursor.y() - endOfLine_coords.y();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( itr != endOfLine_itr )
|
||||
{
|
||||
|
||||
for(;itr != endOfLine_itr;++itr)
|
||||
{
|
||||
unsigned int charcode = *itr;
|
||||
|
||||
osgText::Glyph* glyph = activefont->getGlyph(_fontSize, charcode);
|
||||
if( glyph )
|
||||
{
|
||||
float width = (float) (glyph->getWidth()) * wr;
|
||||
float height = (float) (glyph->getHeight()) * hr;
|
||||
|
||||
if( _layout == RIGHT_TO_LEFT )
|
||||
{
|
||||
cursor.x() -= glyph->getHorizontalAdvance() * wr;
|
||||
}
|
||||
|
||||
// adjust cursor position w.r.t any kerning.
|
||||
if( kerning && previous_charcode )
|
||||
{
|
||||
switch( _layout )
|
||||
{
|
||||
case LEFT_TO_RIGHT:
|
||||
{
|
||||
osg::Vec2 delta( activefont->getKerning( previous_charcode,
|
||||
charcode,
|
||||
_kerningType ) );
|
||||
cursor.x() += delta.x() * wr;
|
||||
cursor.y() += delta.y() * hr;
|
||||
break;
|
||||
}
|
||||
case RIGHT_TO_LEFT:
|
||||
{
|
||||
osg::Vec2 delta( activefont->getKerning( charcode,
|
||||
previous_charcode,
|
||||
_kerningType ) );
|
||||
cursor.x() -= delta.x() * wr;
|
||||
cursor.y() -= delta.y() * hr;
|
||||
break;
|
||||
}
|
||||
case VERTICAL:
|
||||
break; // no kerning when vertical.
|
||||
}
|
||||
}
|
||||
|
||||
local = cursor;
|
||||
osg::Vec2 bearing( horizontal ? glyph->getHorizontalBearing()
|
||||
: glyph->getVerticalBearing() );
|
||||
local.x() += bearing.x() * wr;
|
||||
local.y() += bearing.y() * hr;
|
||||
|
||||
// set up the coords of the quad
|
||||
osg::Vec2 upLeft = local + osg::Vec2(0.f, height);
|
||||
osg::Vec2 lowLeft = local;
|
||||
osg::Vec2 lowRight = local + osg::Vec2(width, 0.f);
|
||||
osg::Vec2 upRight = local + osg::Vec2(width, height);
|
||||
|
||||
// move the cursor onto the next character.
|
||||
// also expand bounding box
|
||||
switch( _layout )
|
||||
{
|
||||
case LEFT_TO_RIGHT:
|
||||
cursor.x() += glyph->getHorizontalAdvance() * wr;
|
||||
bb.expandBy(lowLeft.x(), lowLeft.y());
|
||||
bb.expandBy(upRight.x(), upRight.y());
|
||||
break;
|
||||
case VERTICAL:
|
||||
cursor.y() -= glyph->getVerticalAdvance() * hr;
|
||||
bb.expandBy(upLeft.x(), upLeft.y());
|
||||
bb.expandBy(lowRight.x(), lowRight.y());
|
||||
break;
|
||||
case RIGHT_TO_LEFT:
|
||||
bb.expandBy(lowRight.x(), lowRight.y());
|
||||
bb.expandBy(upLeft.x(), upLeft.y());
|
||||
break;
|
||||
}
|
||||
previous_charcode = charcode;
|
||||
}
|
||||
}
|
||||
|
||||
// skip over spaces and return.
|
||||
while( itr != text.end() && *itr == ' ' )
|
||||
++itr;
|
||||
if( itr != text.end() && *itr == '\n' )
|
||||
++itr;
|
||||
}
|
||||
else
|
||||
{
|
||||
++itr;
|
||||
}
|
||||
|
||||
// move to new line.
|
||||
switch( _layout )
|
||||
{
|
||||
case LEFT_TO_RIGHT:
|
||||
{
|
||||
startOfLine_coords.y() -= _characterHeight * (1.0 + _lineSpacing);
|
||||
cursor = startOfLine_coords;
|
||||
previous_charcode = 0;
|
||||
break;
|
||||
}
|
||||
case RIGHT_TO_LEFT:
|
||||
{
|
||||
startOfLine_coords.y() -= _characterHeight * (1.0 + _lineSpacing);
|
||||
cursor = startOfLine_coords;
|
||||
previous_charcode = 0;
|
||||
break;
|
||||
}
|
||||
case VERTICAL:
|
||||
{
|
||||
startOfLine_coords.x() += _characterHeight * (1.0 + _lineSpacing)
|
||||
/ getCharacterAspectRatio();
|
||||
cursor = startOfLine_coords;
|
||||
previous_charcode = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const_cast<TextOSG*>(this)->_maximumWidth = max_width_safe;
|
||||
|
||||
return bb.size();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::BoundingBox
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
Text::TextOSG::computeBound()
|
||||
#else
|
||||
Text::TextOSG::computeBoundingBox()
|
||||
#endif
|
||||
const
|
||||
{
|
||||
osg::BoundingBox bb =
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
osgText::Text::computeBound();
|
||||
#else
|
||||
osgText::Text::computeBoundingBox();
|
||||
#endif
|
||||
|
||||
_text_element->setBoundingBox(bb);
|
||||
#if OSG_VERSION_LESS_THAN(3,1,0)
|
||||
if( bb.valid() )
|
||||
{
|
||||
// TODO bounding box still doesn't seem always right (eg. with center
|
||||
// horizontal alignment not completely accurate)
|
||||
bb._min.y() += _offset.y();
|
||||
bb._max.y() += _offset.y();
|
||||
}
|
||||
#endif
|
||||
|
||||
return bb;
|
||||
}
|
||||
@@ -205,7 +636,13 @@ namespace canvas
|
||||
|
||||
const GlyphQuads& quads = _textureGlyphQuadMap.begin()->second;
|
||||
const GlyphQuads::Glyphs& glyphs = quads._glyphs;
|
||||
const GlyphQuads::Coords2& coords = quads._coords;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||
GlyphQuads::Coords2 const& coords = quads._coords;
|
||||
#else
|
||||
GlyphQuads::Coords2 refCoords = quads._coords;
|
||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||
#endif
|
||||
|
||||
const GlyphQuads::LineNumbers& line_numbers = quads._lineNumbers;
|
||||
|
||||
float wr = _characterHeight / getCharacterAspectRatio();
|
||||
@@ -271,6 +708,7 @@ namespace canvas
|
||||
|
||||
addStyle("fill", "color", &TextOSG::setFill, text);
|
||||
addStyle("background", "color", &TextOSG::setBackgroundColor, text);
|
||||
addStyle("stroke", "color", &TextOSG::setStroke, text);
|
||||
addStyle("character-size",
|
||||
"numeric",
|
||||
static_cast<
|
||||
@@ -292,13 +730,17 @@ namespace canvas
|
||||
addStyle("font", "", &Text::setFont);
|
||||
addStyle("alignment", "", &Text::setAlignment);
|
||||
addStyle("text", "", &Text::setText, false);
|
||||
|
||||
osgDB::Registry* reg = osgDB::Registry::instance();
|
||||
if( !reg->getReaderWriterForExtension("ttf") )
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Text: Missing 'ttf' font reader");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::Text( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent),
|
||||
_text( new Text::TextOSG(this) )
|
||||
{
|
||||
@@ -370,10 +812,51 @@ namespace canvas
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Text::heightForWidth(int w) const
|
||||
{
|
||||
return _text->sizeForWidth(w).y();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Text::maxWidth() const
|
||||
{
|
||||
return _text->sizeForWidth(INT_MAX).x();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t Text::lineCount() const
|
||||
{
|
||||
return _text->lineCount();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t Text::lineLength(size_t line) const
|
||||
{
|
||||
return _text->lineAt(line).size();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 Text::getNearestCursor(const osg::Vec2& pos) const
|
||||
{
|
||||
return _text->handleHit(pos);
|
||||
return _text->nearestLine(pos.y()).nearestCursor(pos.x());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 Text::getCursorPos(size_t line, size_t character) const
|
||||
{
|
||||
return _text->lineAt(line).cursorPos(character);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::StateSet* Text::getOrCreateStateSet()
|
||||
{
|
||||
if( !_transform.valid() )
|
||||
return 0;
|
||||
|
||||
// Only check for StateSet on Transform, as the text stateset is shared
|
||||
// between all text instances using the same font (texture).
|
||||
return _transform->getOrCreateStateSet();
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace simgear
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class TextLine;
|
||||
class Text:
|
||||
public Element
|
||||
{
|
||||
@@ -39,20 +40,33 @@ namespace canvas
|
||||
Text( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
~Text();
|
||||
|
||||
void setText(const char* text);
|
||||
void setFont(const char* name);
|
||||
void setAlignment(const char* align);
|
||||
|
||||
int heightForWidth(int w) const;
|
||||
int maxWidth() const;
|
||||
|
||||
/// Number of text lines.
|
||||
size_t lineCount() const;
|
||||
|
||||
/// Number of characters in @a line.
|
||||
size_t lineLength(size_t line) const;
|
||||
|
||||
osg::Vec2 getNearestCursor(const osg::Vec2& pos) const;
|
||||
osg::Vec2 getCursorPos(size_t line, size_t character) const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class TextLine;
|
||||
class TextOSG;
|
||||
osg::ref_ptr<TextOSG> _text;
|
||||
|
||||
virtual osg::StateSet* getOrCreateStateSet();
|
||||
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
66
simgear/canvas/elements/canvas_element_test.cpp
Normal file
66
simgear/canvas/elements/canvas_element_test.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/// Unit tests for canvas::Element
|
||||
#define BOOST_TEST_MODULE canvas
|
||||
#include <BoostTestTargetConfig.h>
|
||||
|
||||
#include "CanvasElement.hxx"
|
||||
#include "CanvasGroup.hxx"
|
||||
|
||||
namespace sc = simgear::canvas;
|
||||
|
||||
BOOST_AUTO_TEST_CASE( attr_data )
|
||||
{
|
||||
// http://www.w3.org/TR/html5/dom.html#attr-data-*
|
||||
|
||||
#define SG_CHECK_ATTR2PROP(attr, prop)\
|
||||
BOOST_CHECK_EQUAL(sc::Element::attrToDataPropName(attr), prop)
|
||||
|
||||
// If name starts with "data-", for each "-" (U+002D) character in the name
|
||||
// that is followed by a lowercase ASCII letter, remove the "-" (U+002D)
|
||||
// character and replace the character that followed it by the same character
|
||||
// converted to ASCII uppercase.
|
||||
|
||||
SG_CHECK_ATTR2PROP("no-data", "");
|
||||
SG_CHECK_ATTR2PROP("data-blub", "blub");
|
||||
SG_CHECK_ATTR2PROP("data-blub-x-y", "blubXY");
|
||||
SG_CHECK_ATTR2PROP("data-blub-x-y-", "blubXY-");
|
||||
|
||||
#undef SG_CHECK_ATTR2PROP
|
||||
|
||||
#define SG_CHECK_PROP2ATTR(prop, attr)\
|
||||
BOOST_CHECK_EQUAL(sc::Element::dataPropToAttrName(prop), attr)
|
||||
|
||||
// If name contains a "-" (U+002D) character followed by a lowercase ASCII
|
||||
// letter, throw a SyntaxError exception (empty string) and abort these steps.
|
||||
// For each uppercase ASCII letter in name, insert a "-" (U+002D) character
|
||||
// before the character and replace the character with the same character
|
||||
// converted to ASCII lowercase.
|
||||
// Insert the string "data-" at the front of name.
|
||||
|
||||
SG_CHECK_PROP2ATTR("test", "data-test");
|
||||
SG_CHECK_PROP2ATTR("testIt", "data-test-it");
|
||||
SG_CHECK_PROP2ATTR("testIt-Hyphen", "data-test-it--hyphen");
|
||||
SG_CHECK_PROP2ATTR("-test", "");
|
||||
SG_CHECK_PROP2ATTR("test-", "data-test-");
|
||||
|
||||
#undef SG_CHECK_PROP2ATTR
|
||||
|
||||
SGPropertyNode_ptr node = new SGPropertyNode;
|
||||
sc::ElementPtr el =
|
||||
sc::Element::create<sc::Group>(sc::CanvasWeakPtr(), node);
|
||||
|
||||
el->setDataProp("myData", 3);
|
||||
BOOST_CHECK_EQUAL( el->getDataProp<int>("myData"), 3 );
|
||||
BOOST_CHECK_EQUAL( node->getIntValue("data-my-data"), 3 );
|
||||
|
||||
SGPropertyNode* prop = el->getDataProp<SGPropertyNode*>("notExistingProp");
|
||||
BOOST_CHECK( !prop );
|
||||
prop = el->getDataProp<SGPropertyNode*>("myData");
|
||||
BOOST_CHECK( prop );
|
||||
BOOST_CHECK_EQUAL( prop->getParent(), node );
|
||||
BOOST_CHECK_EQUAL( prop->getIntValue(), 3 );
|
||||
|
||||
BOOST_CHECK( el->hasDataProp("myData") );
|
||||
el->removeDataProp("myData");
|
||||
BOOST_CHECK( !el->hasDataProp("myData") );
|
||||
BOOST_CHECK_EQUAL( el->getDataProp("myData", 5), 5 );
|
||||
}
|
||||
@@ -34,7 +34,10 @@ namespace canvas
|
||||
public:
|
||||
struct ScreenPosition
|
||||
{
|
||||
ScreenPosition() {}
|
||||
ScreenPosition():
|
||||
x(0),
|
||||
y(0)
|
||||
{}
|
||||
|
||||
ScreenPosition(double x, double y):
|
||||
x(x),
|
||||
@@ -67,8 +70,11 @@ namespace canvas
|
||||
public:
|
||||
|
||||
HorizontalProjection():
|
||||
_cos_rot(1),
|
||||
_sin_rot(0),
|
||||
_ref_lat(0),
|
||||
_ref_lon(0),
|
||||
_angle(0),
|
||||
_cos_angle(1),
|
||||
_sin_angle(0),
|
||||
_range(5)
|
||||
{
|
||||
setScreenRange(200);
|
||||
@@ -88,9 +94,19 @@ namespace canvas
|
||||
*/
|
||||
void setOrientation(float hdg)
|
||||
{
|
||||
_angle = hdg;
|
||||
|
||||
hdg = SGMiscf::deg2rad(hdg);
|
||||
_sin_rot = sin(hdg);
|
||||
_cos_rot = cos(hdg);
|
||||
_sin_angle = sin(hdg);
|
||||
_cos_angle = cos(hdg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get orientation/heading of the projection (in degree)
|
||||
*/
|
||||
float orientation() const
|
||||
{
|
||||
return _angle;
|
||||
}
|
||||
|
||||
void setRange(double range)
|
||||
@@ -114,8 +130,8 @@ namespace canvas
|
||||
pos.y *= scale;
|
||||
return ScreenPosition
|
||||
(
|
||||
_cos_rot * pos.x - _sin_rot * pos.y,
|
||||
-_sin_rot * pos.x - _cos_rot * pos.y
|
||||
_cos_angle * pos.x - _sin_angle * pos.y,
|
||||
-_sin_angle * pos.x - _cos_angle * pos.y
|
||||
);
|
||||
}
|
||||
|
||||
@@ -129,10 +145,11 @@ namespace canvas
|
||||
*/
|
||||
virtual ScreenPosition project(double lat, double lon) const = 0;
|
||||
|
||||
double _ref_lat,
|
||||
_ref_lon,
|
||||
_cos_rot,
|
||||
_sin_rot,
|
||||
double _ref_lat, ///<! Reference latitude (radian)
|
||||
_ref_lon, ///<! Reference latitude (radian)
|
||||
_angle, ///<! Map rotation angle (degree)
|
||||
_cos_angle,
|
||||
_sin_angle,
|
||||
_range;
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user